Пытаюсь разобраться в какой-то сборке.
Сборка следующая, интересует testl
линейка:
000319df 8b4508 movl 0x08(%ebp), %eax
000319e2 8b4004 movl 0x04(%eax), %eax
000319e5 85c0 testl %eax, %eax
000319e7 7407 je 0x000319f0
Я пытаюсь понять точку testl
между %eax
и %eax
? Я думаю, что особенности этого кода не важны, я просто пытаюсь разобраться в тесте с самим собой - не всегда ли значение будет истинным?
assembly
x86
instructions
maxpenguin
источник
источник
test
иcmp
. Да, я понимаю, что это ваше мнение, основанное на ваших комментариях Коди. Однако поместить это в свой пост - другое дело; это не утверждение, с которым я согласен, просто потому, что я не знаю , одинаково ли оно во всех случаях.je
,jz
,cmp
, иtest
, а не JE, JZ, CMP или TEST. Я такой придирчивый.test a,a
иcmp $0,a
идентично установил флаги; спасибо, что указали, что это нетривиальное утверждение. re: TEST vstest
.: недавно я начал использовать заглавные буквы, как в руководствах Intel. Но когда я говорю о мнемонике AT&T и мнемонике Intel, я используюtestb
стиль для AT&T. IDK, если это помогает читаемости.Смысл в
test
том, чтобы объединить аргументы И и проверить результат на ноль. Таким образом, этот код проверяет, равен ли EAX нулю.je
прыгнет, если ноль.Кстати, это генерирует меньшую инструкцию, чем
cmp eax, 0
по этой причине компиляторы обычно делают это таким образом.источник
Команда тестирования выполняет логическую операцию И между операндами, но не записывает результат обратно в регистр. Обновляются только флаги.
В вашем примере тестовый eax, eax установит нулевой флаг, если eax равен нулю, знак-флаг, если установлен самый высокий бит, а также некоторые другие флаги.
Команда Перейти, если равно (je) перескакивает, если установлен нулевой флаг.
Вы можете перевести код в более читаемый код следующим образом:
Это имеет ту же функциональность, но требует на несколько байтов больше места для кода. Вот почему компилятор выдал тест вместо сравнения.
источник
test eax, eax
иcmp eax, 0
оба устанавливают все флаги и устанавливают для них одинаковые значения. Обе инструкции устанавливают все флаги «согласно результату». Вычитание0
никогда не может привести к переносу или переполнению. Ваш аргумент верен для любого немедленного действия, кроме 0, но не для 0.test
подобенand
, за исключением того, что он записывает только FLAGS, оставляя оба входа неизмененными. С двумя разными входами это полезно для проверки, все ли некоторые биты равны нулю или установлен хотя бы один. (например,test al, 3
устанавливает ZF, если EAX кратно 4 (и, таким образом, оба младших бита обнулены).test eax,eax
устанавливает все флаги точно так же, как еслиcmp eax, 0
бы :a = a&a = a-0
).(PF, как обычно, устанавливается только в соответствии с младшими 8 битами )
За исключением устаревшего AF (флаг вспомогательного переноса, используемый инструкциями ASCII / BCD). TEST оставляет его неопределенным , но CMP устанавливает его «в соответствии с результатом» . Поскольку вычитание нуля не может привести к переносу с 4-го на 5-й бит, CMP всегда должен очищать AF.
ТЕСТ меньше (не сразу), а иногда и быстрее (может макрослиться в муп сравнения и ветвления на большем количестве процессоров в большем количестве случаев, чем CMP). Это делает
test
предпочтительную идиому для сравнения регистра с нулем . Это оптимизация на глазокcmp reg,0
, которую можно использовать независимо от семантического значения.Единственная распространенная причина использования CMP с немедленным 0 - это когда вы хотите сравнить с операндом памяти. Например,
cmpb $0, (%esi)
чтобы проверить завершающий нулевой байт в конце строки C-стиля неявной длины.AVX512F добавляет
kortestw k1, k2
и добавляет AVX512DQ / BW (Skylake-X, но не KNL)ktestb/w/d/q k1, k2
, которые работают с регистрами маски AVX512 (k0..k7), но по-прежнему устанавливают обычные ФЛАГИ, как этоtest
делается, точно так же, как это делают целые числаOR
илиAND
инструкции. (Что-то вроде SSE4ptest
или SSEucomiss
: входы в домен SIMD и результат целочисленные флаги.)kortestw k1,k1
- это идиоматический способ ветвления / cmovcc / setcc на основе результата сравнения AVX512, заменяющий SSE / AVX2(v)pmovmskb/ps/pd
+test
илиcmp
.Использование
jz
vs.je
может сбивать с толку.jz
иje
представляют собой буквально одну и ту же инструкцию , то есть один и тот же код операции в машинном коде. Они делают то же самое, но имеют разное смысловое значение для людей . Дизассемблеры (и обычно вывод asm из компиляторов) будут всегда использовать только один, поэтому семантическое различие теряется.cmp
иsub
установите ZF, когда их два входа равны (т.е. результат вычитания равен 0).je
(переход, если равно) - семантически значимый синоним.test %eax,%eax
/and %eax,%eax
снова устанавливает ZF, когда результат равен нулю, но нет проверки на «равенство». ZF после теста не сообщает вам, равны ли два операнда. Итакjz
(переход, если ноль) - это семантически значимый синоним.источник
test
побитовойand
операции, может быть неочевидно для людей, только изучающих сборку (и ленивых / не знающих, что проверять справочное руководство каждые 60 секунд;) :)).kortest*
иktest*
пока я был на нем.Этот фрагмент кода взят из подпрограммы, которой был дан указатель на что-то, возможно, на какую-то структуру или объект. Вторая строка разыменовывает этот указатель, извлекая значение из этой вещи - возможно, это указатель или, может быть, просто int, хранящийся как его второй член (смещение +4). Третья и четвертая строки проверяют это значение на ноль (NULL, если это указатель) и пропускают следующие несколько операций (не показаны), если оно равно нулю.
Тест на ноль иногда кодируется как сравнение с непосредственным буквальным нулевым значением, но компилятор (или человек?), Который написал это, мог подумать, что testl op будет работать быстрее - принимая во внимание все современные вещи процессора, такие как конвейерная обработка и регистр переименование. Это из того же набора уловок, в котором заключена идея очистки реестра с помощью XOR EAX, EAX (который я видел на чьем-то номерном знаке в Колорадо!), А не очевидного, но, возможно, более медленного MOV EAX, # 0 (я использую более старую нотацию. ).
В asm, как и в perl, TMTOWTDI.
источник
Если eax равен нулю, он выполнит условный переход, в противном случае он продолжит выполнение на 319e9.
источник
В некоторых программах их можно использовать для проверки переполнения буфера. В самом верху выделенного места ставится 0. После ввода данных в стек он ищет 0 в самом начале выделенного пространства, чтобы убедиться, что выделенное пространство не переполнено.
Он использовался в упражнении stack0 для эксплойтов-упражнений, чтобы проверить, не было ли он переполнен, и если его нет и там был ноль, он отобразил бы "Попробуйте снова"
источник
cmp DWORD PTR [esp+0x5c], 0
/jz 0x8048427 <main+51>
было бы более эффективным, чем отдельная загрузка MOV, а затем ТЕСТ. Вряд ли это обычный вариант использования проверки нуля.мы могли бы увидеть JG , JLE Если
testl %edx,%edx. jle .L3
мы могли бы легко найти JLE костюм(SF^OF)|ZF
, если% EDX равен нулю, ZF = 1, но если% EDX не равен нулю и -1, после testl, то OF = 0 и SF = 1, поэтому флаг = true, который реализует прыжок. Извините, мой английский плохойисточник