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

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

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

Команда Jump, если команда Equal (je) перескакивает, если установлен флаг нуля.

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

cmp eax, 0
je  somewhere

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

Ответ 4

test как and, за исключением того, что он только пишет FLAGS, оставляя оба входа немодифицированными. При использовании двух разных входов полезно использовать для тестирования, если все биты равны нулю, или если задано хотя бы одно. (например, test al, 3 устанавливает ZF, если EAX является кратным 4 (и, таким образом, оба его младших 2 бита обнулены).


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

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

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


TEST меньше (без немедленного), а иногда и быстрее (может вставлять макросплав в процессор с более высоким числом процессоров в большинстве CPU, чем в 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), но все же устанавливают регулярные FLAGS, такие как test, так же, как целое число OR или and.

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 (jump if equal) - семантически релевантный синоним.

test %eax,%eax/and %eax,%eax снова устанавливает ZF, когда результат равен нулю, но нет теста равенства. ZF после теста не говорит вам, равны ли два операнда. Итак, jz (jump if zero) является семантически значимым синонимом.

Ответ 5

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

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

В asm, например perl, TMTOWTDI.

Ответ 6

Если eax равно нулю, он выполнит условный переход, иначе он продолжит выполнение при 319e9

Ответ 7

В некоторых программах их можно использовать для проверки переполнения буфера. На самом верху выделенного пространства помещается 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 <[email protected]>
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 <[email protected]>
0x08048425 <main+49>:   jmp    0x8048433 <main+63>
0x08048427 <main+51>:   mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:   call   0x804832c <[email protected]>
0x08048433 <main+63>:   leave
0x08048434 <main+64>:   ret

Ответ 8

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