Вопрос

Я пытаюсь понять некоторую сборку.

Сборка следующая, меня интересует 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?Я думаю, что специфика этого кода не важна, я просто пытаюсь понять тест сам по себе - разве значение не всегда будет истинным?

Это было полезно?

Решение

Он проверяет, является ли eax равно 0, или выше, или ниже.В этом случае переход совершается, если eax равен 0.

Другие советы

Значение test заключается в объединении аргументов AND и проверке результата на ноль.Итак, этот код проверяет, равен ли EAX нулю или нет. je подскочит, если ноль.

Кстати, это генерирует меньшую инструкцию, чем cmp eax, 0 по этой причине компиляторы обычно делают это именно так.

Инструкция тестирования выполняет логическую операцию И между операндами, но не записывает результат обратно в регистр.Обновляются только флаги.

В вашем примере тест eax, eax установит нулевой флаг, если eax равен нулю, знак-флаг, если установлен старший бит, а также некоторые другие флаги.

Инструкция Jump if Equal (je) выполняет переход, если установлен нулевой флаг.

Вы можете перевести код в более читаемый код следующим образом:

cmp eax, 0
je  somewhere

Он имеет ту же функциональность, но требует на несколько байт больше места для кода.По этой причине компилятор выдал тест вместо сравнения.

test как and, за исключением того, что он записывает только ФЛАГИ, оставляя оба входа неизмененными.С двумя другой входов, это полезно для проверки того, все ли некоторые биты равны нулю или установлен хотя бы один.(например. test al, 3 устанавливает ZF, если EAX кратно 4 (и, таким образом, оба младших бита обнулены).


test eax,eax устанавливает все флаги точно так же, как cmp eax, 0 бы:

  • CF и OF очищены (AND/TEST всегда так делает;и вычитание нуля никогда не приводит к переносу)
  • ZF, SF и PF в соответствии со значением в EAX.(a = a&a = a-0)

(За исключением устаревшего AF (вспомогательного флага переноса, используемого инструкциями ASCII/BCD). ТЕСТ оставляет это неопределенным, но CMP устанавливает его «по результату».Поскольку вычитание нуля не может привести к переносу с 4-го на 5-й бит, CMP всегда должен очищать AF).


TEST меньше (не мгновенный), а иногда и быстрее (может объединить макросы в операцию сравнения и ветвления на большем количестве процессоров в большем количестве случаев, чем CMP). Что делает test предпочтительная идиома для проверки регистра на ноль или нет.

Единственная распространенная причина использования CMP с немедленным 0 — это когда вы хотите сравнить с операндом памяти (например, cmpb $0, (%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 это буквально одна и та же инструкция, т.е.тот же код операции в машинном коде. Они делают одно и то же, но имеют разное смысловое значение для человека..Дизассемблеры (и, как правило, ассемблерный вывод компиляторов) будут использовать только один, поэтому семантическое различие теряется.

cmp и sub установите ZF, когда их два входа равны (т.е.результат вычитания равен 0). je (перейти, если равно) — семантически релевантный синоним.

test %eax,%eax / and %eax,%eax снова устанавливает ZF, когда результат равен нулю, но проверки на «равенство» нет.ZF после проверки не сообщает вам, равны ли два операнда.Так jz (перейти, если ноль) является семантически значимым синонимом.

Этот фрагмент кода взят из подпрограммы, которой был дан указатель на что-то, возможно, на какую-то структуру или объект.Вторая строка разыменовывает этот указатель, извлекая из него значение — возможно, это сам указатель или, может быть, просто целое число, хранящееся как его второй член (смещение +4).Третья и четвёртая строки проверяют это значение на ноль (NULL, если это указатель) и пропускают следующие несколько операций (не показаны), если оно равно нулю.

Проверка на ноль иногда кодируется как сравнение с непосредственным буквальным нулевым значением, но компилятор (или человек?), написавший это, мог подумать, что операция testl будет работать быстрее - принимая во внимание все современные возможности ЦП, такие как конвейерная обработка и регистр. переименование.Это из того же набора трюков, в котором содержится идея очистки регистра с помощью XOR EAX,EAX (которую я видел на чьем-то номерном знаке в Колорадо!), а не очевидного, но, возможно, более медленного MOV EAX, #0 (я использую старую систему обозначений). ).

В ассемблере, как и в перле, 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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top