> > Как вы думаете, что будет в EAX после исполнения > > следующего: > > > > MOV EAX, 7777 > > RCR EAX, 32 > > RCL EAX, 64 > > Вот здесь меня терзают смутные сомнения. Поскольку полный > круг = 33 бита (32 + перенос), то двигать нужно было > соответственно на 33 и 66. Это, если по-хорошему. Да и > вообще результат этих двух прокрутов должен быть > эквивалентен RCL EAX, 32 или RCR EAX, 1. > > Как вы думаете, что будет в EAX после исполнения > > следующего: > > > > MOV EAX, 7777 > > RCR EAX, 32 > > RCL EAX, 64 > > Вот здесь меня терзают смутные сомнения. Поскольку полный > круг = 33 бита (32 + перенос), то двигать нужно было > соответственно на 33 и 66. Это, если по-хорошему. Да и > вообще результат этих двух прокрутов должен быть > эквивалентен RCL EAX, 32 или RCR EAX, 1.
Во всех инструкциях циклического сдвига, просто сдвига и сдвига с исп. флага переноса используются только младшие 5 бит второго операнда, что реально даёт возможность сдвига на 31 позицию максимум. Остальное понятно (проявление цикличности и проч. «эффекты»), поскольку все они исходят из этого 5-битного ограничения.
И если с обычными и циклическими сдвигами без использования флага переноса всё понятно, поскольку такая "фича" процессора не только покрывает все возможные варианты сдвига, но и может найти какое-нибудь полезное применение в программировании, то циклические сдвиги RCL и RCR с невозможностью сдвига на 32 позиции явная недоработка.
В самом деле, рассмотрим пример:
Пусть CF = 0;
MOV EAX, $FFFFFFFF
RCL EAX, 31
В результате получим $BFFFFFFF, что в двоичном представлении будет 101(30), СF = 1
Но если изменить инструкцию сдвига на [RCL EAX, 32], то теоретически в результате должны получить 01(31), CF = 1, чего не наблюдается. Налицо ошибка процессора. Ошибка ещё и потому, что аналогичная 16-битная инструкция на свой полный размер отрабатывается корректно, т.е. последовательность [CF = 0; MOV AX, $FFFF; RCL AX, 16] даст в результате EAX = 01(15), СF = 1.
Я немножко порыл Сеть, но ничего об этом нигде не нашёл. Может и вправду, напишем в Intel? Прикольно то, что конкуренты (AMD) старательно копируют все фичи и баги, поскольку на этих процессорах точно такая же картина с этими инструкциями.
Скомпилил Симантеком - выдала 1, скомпилил стареньким Борландом - выдала 0, то же с ключиком -3 - выдала 1.
Выводы - в библиотечке для 286 двигается 32 раза, а сам поцессор (проверял на Атлоне и P-III) реагирует только на 4 младших бита.
Интересно - что на самом деле должно быть (по стандарту)?
Оказывается, это не баг, а фича Intel. Реально инструкция SHL и SHR делает сдвиг на (N mod _разрядность сдвигаемого регистра_).11.02.04 13:08 Автор: HandleX <Александр М.> Статус: The Elderman
Дополнительные исследования показали, что…11.02.04 13:35 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 11.02.04 13:37 Количество правок: 1
Итак, цикличность сдвига равна 32 и не зависит от разрядности сдвигаемого регистра. Интересно, как поведёт себя это дело на IA64? Скорее всего она станет равна 64. Так что делайте выводы.
А ты попробуй printf("%ld\n", l)10.02.04 16:15 Автор: SL Статус: Незарегистрированный пользователь
Во первых в современных компилерах int и так имеет размер 32 бита (а %d - печатает именно int). Во вторых после смещения на 32 все равно 0 везде должен остаться. В третьих даже в 16-битных компилерах в little-endian архитектурах единица вылезет в старшие разряды, которые идут в памяти после младших. То бишь скорее %ld будет не нулем, чем %d
ИМХО это именно глюк
Блин, сразу не смекнул.11.02.04 11:56 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
> Во первых в современных компилерах int и так имеет размер > 32 бита (а %d - печатает именно int). Во вторых после > смещения на 32 все равно 0 везде должен остаться. В третьих > даже в 16-битных компилерах в little-endian архитектурах > единица вылезет в старшие разряды, которые идут в памяти > после младших. То бишь скорее %ld будет не нулем, чем %d > > ИМХО это именно глюк Попробовал Борландом 3.1, все равно 0.
Все-таки библиотека, скорее всего честно двигает 32 раза, ну да это не важно. Обидно, что проц не сдвинул 32 раза, а нигде это не написано.
Как раз про проц-то все написано. А вот про глюк компиляторов - нет.14.02.04 04:17 Автор: AlexD <Alexander> Статус: Member
Имелось ввиду imho следующее: вполне логично, что сдвиг мпилятор переводит и интеловскую инструкцию shl. Так вот, её второй операнд может иметь величину от 0 до 31 включительно(кажись как раз начиная с 386-х это и изменили). Соответственно на процах выше 286 инструкция shl <lya-lya>, 32 равносильна nop - ничего не делающей операции. Поэтому мы и получаем 1. На 286 же вроде не было такого ограничения(или на 8086 :-)? ) - и там выполняется полный сдвиг на 32....т.е. получаем 0. Так что, видимо, ни от каких библиотек это не зависит... Просто писатели компиляторов не учли платформно-зависимый прикол от интела...
Интересно на 386 и 486 проверить было, может там напрямую...11.02.04 12:05 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman Отредактировано 11.02.04 12:06 Количество правок: 1
> включительно(кажись как раз начиная с 386-х это и
Интересно на 386 и 486 проверить было бы, может там напрямую двигали, с использованием регистра сдвига и счетчика.
> изменили). Соответственно на процах выше 286 инструкция shl > <lya-lya>, 32 равносильна nop - ничего не делающей > операции. Поэтому мы и получаем 1. На 286 же вроде не было > такого ограничения(или на 8086 :-)? ) - и там выполняется > полный сдвиг на 32....т.е. получаем 0. Так что, видимо, ни > от каких библиотек это не зависит... Просто писатели
Раз уж в 286 нет инструкции сдвига 32 битного целого, похоже компилер генерит вызов встроенной функции.
> компиляторов не учли платформно-зависимый прикол от > интела...
Мне кажется так: в 286 нет 32-битных целых, но есть сдвиг на любое число от 0 до 25514.02.04 04:15 Автор: AlexD <Alexander> Статус: Member
> Интересно - что на самом деле должно быть (по стандарту)? По стандарту << - операция сдвига, а не ротации. Так что единица не должна была вернуться в нулевой разряд никаким макаром. В общем 0 должен быть
Сдвиг (<< или shl) не циклический (rol или rcl). Скорее...11.02.04 11:42 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
> По стандарту << - операция сдвига, а не ротации. Так > что единица не должна была вернуться в нулевой разряд > никаким макаром. В общем 0 должен быть Сдвиг (<< или shl) не циклический (rol или rcl). Скорее всего проц посмотрел на младшие 4 разряда (а они все нули) и ничего не сдвинул.
Может там че-то с интерпретацией carry flag компилером?10.02.04 15:21 Автор: whiletrue <Роман> Статус: Elderman Отредактировано 10.02.04 15:24 Количество правок: 2
Гы-ыыы! А вы попробуйте вот что... Всё-таки цикличность явно наблюдается... (updated)11.02.04 12:36 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 11.02.04 12:46 Количество правок: 2
--- В общем, возвращает она 8. А если сдвигать на 34 бита, то EAX=4. А если на 33 бита, то EAX=2. Ну и надо думать, что сдвиг на 32 бита даёт единицу.
Вообще, если в регистр занести любое значение и выполнить SHL регистр, 32, то значение регистра не изменится! -- Begin update --
О! значение регистра не меняется, если делать его сдвиг на 32 * N, где N — целое число... Причёи направление сдвига неважно — это может быть и SHR! ;-)
-- End update --
Странно, что об этом нигде не написано...
А rol, ror, rcl, rcr никто не прбовал?11.02.04 14:55 Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
Абсолютно то же с ROL и ROR, RCR и RCL (внутри)11.02.04 15:06 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 11.02.04 15:41 Количество правок: 2
Ваши предположения правильные — в регистре будет число 7777!
Ни одна из инструкций после MOV не изменила содержимое EAX (проверял отладчиком).
Вывод — IA32 в вышеуказанных инструкциях использует только младшие 5 бит во втором операнде (на сколько двигать), всё остальное отбрасывает.
Кста, на AMD тоже самое. Я думаю, это описано в спецификациях Intel, лезть на их сайт неохота ;-)
А мое сообщение повыше не пробовал читать:)? Я и написал, что написано в спецификации14.02.04 04:19 Автор: AlexD <Alexander> Статус: Member