'testl' eax против eax?
Я пытаюсь понять некоторые сборки.
сборка следующим образом, я заинтересован в 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
? Я думаю, что специфика того, что этот код не важен, я просто пытаюсь понять тест с самим собой - не будет ли значение всегда истинным?
8 ответов:
Он проверяет, является ли
eax
равен 0, или выше, или ниже. В этом случае прыжок выполняется, еслиeax
равен 0.
смысл
test
есть и аргументы вместе, и проверить результат на ноль. Таким образом, этот код проверяет, равен ли EAX нулю или нет.je
будет прыгать, если ноль.кстати, это генерирует меньшую инструкцию, чем
cmp eax, 0
что является причиной того, что компиляторы обычно делают это таким образом.
тестовая инструкция выполняет логическую операцию AND между операндами, но не записывает результат обратно в регистр. Обновляются только флаги.
в вашем примере тест eax, eax установит нулевой флаг, если eax равен нулю, знак-флаг, если установлен самый высокий бит, а также некоторые другие флаги.
команда Jump if Equal (je) переходит, если установлен нулевой флаг.
вы можете перевести код в более читаемый код, например это:
cmp eax, 0 je somewhere
это имеет ту же функциональность, но требует несколько байтов больше кодового пространства. Вот почему компилятор выдал тест вместо сравнения.
test
какand
, за исключением того, что он только пишет флаги, оставляя оба его входа неизмененными. С двумя разные входы, это полезно для тестирования, если некоторые биты равны нулю, или если хотя бы один набор. (например,test al, 3
устанавливает ZF, если EAX кратно 4 (и, таким образом, оба его младших 2 бита обнулены).
test eax,eax
устанавливает все флаги точно так же, какcmp eax, 0
хотел бы:
- CF и cleared (и / TEST всегда это делает; и вычитание нуля никогда не приводит к переносу)
- ЗФ, СФ и ПФ в соответствии со значением в регистре EAX. (
a = a&a = a-0
)(за исключением устаревшего AF (вспомогательный флаг переноса, используемый инструкциями ASCII/BCD). , (%esi) чтобы проверить наличие завершающего нулевого байта в конце строки c-стиля неявной длины).
AVX512F добавляет
kortestw k1, k2
и AVX512DQ/BW (Skylake но не KNL) добавитьktestb/w/d/q k1, k2
, которые работают на регистрах маски AVX512 (k0..k7) но все же установите обычные флаги, такие какtest
делает, так же, как целое числоOR
илиAND
инструкции делать.
kortestw k1,k1
это идиоматический способ ветвления / cmovcc / setcc на основе результата сравнения AVX512, заменяющего SSE / AVX2(v)pmovmskb/ps/pd
+test
илиcmp
.
использование
jz
иje
можно запутаться.
jz
иje
буквально та же инструкция, т. е. тот же код в машинный код. они делают то же самое, но имеют разное смысловое значение для человека. Дизассемблеры (и, как правило, вывод asm из компиляторов) будут использовать только один, поэтому семантическое различие теряется.
cmp
иsub
установите ZF, когда их два входа равны (т. е. результат вычитания равен 0).je
(jump if equal) - семантически значимый синоним.
test %eax,%eax
/and %eax,%eax
снова устанавливает ZF, когда результат равен нулю, но нет теста "равенство". ZF после теста не говорит вам, были ли равны два операнда. Так чтоjz
(перейти, если ноль) является семантически значимым синонимом.
этот фрагмент кода из подпрограммы, которая была дана указатель на что-то, вероятно, некоторые структуры или объекта. Вторая строка разыменовывает этот указатель, извлекая значение из этой вещи-возможно, сам указатель или, может быть, просто int, сохраненный как его 2-й член (смещение +4). 3-я и 4-я строки проверяют это значение на ноль (NULL, если это указатель) и пропускают следующие несколько операций (не показано), если оно равно нулю.
тест на ноль иногда кодируется как сравнение с немедленное литеральное нулевое значение, но компилятор (или человек?) кто написал это, возможно, думал, что testl op будет работать быстрее-принимая во внимание все современные вещи процессора, такие как конвейеризация и переименование регистра. Это из того же мешка трюков, который содержит идею очистки регистра с помощью XOR EAX, EAX (который я видел на чьем-то номерном знаке в Колорадо!) вместо очевидного, но, возможно, более медленного движения EAX, #0 (я использую более старую нотацию).
в asm, как perl, TMTOWTDI.
Если eax равен нулю, он выполнит условный прыжок, в противном случае он продолжит выполнение на 319e9
в некоторых программах они могут быть использованы для проверки на переполнение буфера. В самом верху выделенного пространства помещается 0. После ввода данных в стек он ищет 0 в самом начале выделенного пространства, чтобы убедиться, что выделенное пространство не переполнено.
Он был использован в упражнении stack0 эксплойтов-упражнения, чтобы проверить, если он был переполнен, и если там не было и там был ноль, он будет отображать "попробуйте еще раз"
0x080483f4 <main+0>: push ebp 0x080483f5 <main+1>: mov ebp,esp 0x080483f7 <main+3>: and esp,0xfffffff0 0x080483fa <main+6>: sub esp,0x60 0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0 ;puts a zero on stack 0x08048405 <main+17>: lea eax,[esp+0x1c] 0x08048409 <main+21>: mov DWORD PTR [esp],eax 0x0804840c <main+24>: call 0x804830c <gets@plt> 0x08048411 <main+29>: mov eax,DWORD PTR [esp+0x5c] 0x08048415 <main+33>: test eax,eax ; checks if its zero 0x08048417 <main+35>: je 0x8048427 <main+51> 0x08048419 <main+37>: mov DWORD PTR [esp],0x8048500 0x08048420 <main+44>: call 0x804832c <puts@plt> 0x08048425 <main+49>: jmp 0x8048433 <main+63> 0x08048427 <main+51>: mov DWORD PTR [esp],0x8048529 0x0804842e <main+58>: call 0x804832c <puts@plt> 0x08048433 <main+63>: leave 0x08048434 <main+64>: ret