'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 равен нулю, знак-флаг, если установлен самый высокий бит, а также некоторые другие флаги.
скачок, если равная (je) инструкция прыгает, если установлен нулевой флаг.
вы можете перевести код на более читаемый код, например это:
cmp eax, 0
je somewhere
который имеет ту же функциональность, но требует несколько байтов больше пространства кода. Вот почему компилятор испустил тест вместо сравнения.
test
как and
, только он пишет флагов, оставив свои входы без изменений. С двумя разные входные сигналы, полезно для испытывать если некоторые биты все нул, или если хотя бы одно установлено. (например,test al, 3
устанавливает ZF, если EAX кратно 4 (и, таким образом, имеет оба его низких 2 бита обнулены).
test eax,eax
устанавливает все флаги точно так же, как cmp eax, 0
бы:
- CF и cleared (и / TEST всегда делает это; и вычитание нуля никогда не приводит к переносу)
- ZF, SF и PF согласно значению в EAX. (
a = a&a = a-0
)
(за исключением устаревшего флага AF (auxiliary-carry, используемого инструкциями 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
(перейти Если равно) - это семантически релевантный синоним.
test %eax,%eax
/ and %eax,%eax
снова устанавливает ZF, когда результат равен нулю, но нет теста "равенство". ZF после теста не говорит вам, были ли равны два операнда. Так что jz
(перейти, если ноль) является семантически релевантным синонимом.
этот фрагмент кода из подпрограммы, которой был дан указатель на что-то, возможно, какую-то структуру или объект. 2-я строка разыменовывает этот указатель, извлекая значение из этой вещи-возможно, сам указатель или, возможно, просто int, сохраненный как его 2-й член (offset +4). 3-я и 4-я строки проверяют это значение на ноль (NULL, если это указатель) и пропускают следующие несколько операций (не показано), если он равен нулю.
тест для нуля иногда кодируется как сравнение с немедленное литеральное нулевое значение, но компилятор (или человек?) кто написал это, возможно, думал, что testl op будет работать быстрее-принимая во внимание все современные вещи CPU, такие как конвейеризация и переименование регистра. Это из того же мешка трюков, который содержит идею очистки реестра с XOR EAX, EAX (который я видел на чьем-то номерном знаке в Колорадо!) вместо очевидного, но, возможно, более медленного MOV EAX, #0 (я использую более старую нотацию).
в asm, как perl, TMTOWTDI.
в некоторых программах их можно использовать для проверки переполнения буфера. В самом верху выделенного пространства помещается 0. После ввода данных в стек он ищет 0 в самом начале выделенного пространства, чтобы убедиться, что выделенное пространство не переполнено.
Он использовался в упражнении stack0 exploits-exercises, чтобы проверить, переполнен ли он, и если нет, и там был ноль, он отобразит "повторите попытку"
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
мы могли видеть jg,jle
Если testl %edx,%edx. jle .L3
мы могли бы легко найти jleкостюм (SF^OF)|ZF
, если %edx равно нулю, ZF=1, но если %edx не равно нулю и равно -1, после testl, OF=0 и SF =1, поэтому флаг =true, который реализует прыжок
.извините, мой английский беден