'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 104

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

мы могли видеть jgjle Если testl %edx,%edx. jle .L3мы могли бы легко найти jleкостюм (SF^OF)|ZF, если %edx равно нулю, ZF=1,но если %edx не равно нулю и равно -1, после testl, OF=0 и SF =1, поэтому флаг =true, который реализует прыжок .извините, мой английский беден