eax에 대한 `testl` eax?
-
02-07-2019 - |
문제
나는 일부 어셈블리를 이해하려고 노력하고 있습니다.
다음과 같은 어셈블리에 관심이 있습니다. 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
인수와 함께, 결과를 0을 확인하십시오. 따라서이 코드는 EAX가 0인지 아닌지 테스트합니다. je
0이면 점프합니다.
BTW, 이것은보다 작은 지시를 생성합니다 cmp eax, 0
이것이 컴파일러가 일반적으로 이런 식으로 수행하는 이유입니다.
테스트 명령은 피연산자간에 논리적 및 수술을 수행하지만 결과를 다시 레지스터에 기록하지는 않습니다. 플래그 만 업데이트됩니다.
예제에서 Test EAX, EAX가 0 인 경우 eAx가 0, 가장 높은 비트 세트와 다른 플래그 인 경우 부호 플래그를 설정합니다.
Zero 플래그가 설정되면 동일하면 점프가 동일합니다.
코드를 다음과 같은보다 읽기 쉬운 코드로 변환 할 수 있습니다.
cmp eax, 0
je somewhere
기능이 동일하지만 일부 바이트가 더 많은 코드 공간이 필요합니다. 이것이 바로 컴파일러가 비교 대신 테스트를 방출 한 이유입니다.
test
처럼 and
, 단, FLAGS만 작성하고 두 입력을 모두 수정하지 않은 채로 둡니다.2개로 다른 입력의 경우 일부 비트가 모두 0인지 또는 적어도 하나가 설정되어 있는지 테스트하는 데 유용합니다.(예: test al, 3
EAX가 4의 배수인 경우(따라서 하위 2비트가 모두 0인 경우) ZF를 설정합니다.
test eax,eax
모든 플래그를 정확히 같은 방식으로 설정합니다. cmp eax, 0
~일 것이다:
- CF 및 OF가 지워졌습니다. (AND/TEST는 항상 그렇게 합니다.0을 빼면 캐리가 발생하지 않습니다)
- EAX의 값에 따른 ZF, SF 및 PF.(
a = a&a = a-0
)
(더 이상 사용되지 않는 AF(ASCII/BCD 명령어에서 사용되는 보조 캐리 플래그 제외). TEST에서는 정의되지 않은 상태로 둡니다., 하지만 CMP는 "결과에 따라" 설정합니다..0을 빼면 4번째 비트에서 5번째 비트로 캐리가 생성될 수 없으므로 CMP는 항상 AF를 지워야 합니다.
TEST는 더 작고(즉각적이지 않음) 때로는 더 빠릅니다(CMP보다 더 많은 경우에 더 많은 CPU에서 비교 및 분기 작업으로 매크로 융합할 수 있음). 그게 test
레지스터가 0인지 아닌지 테스트하는 데 선호되는 관용구.
즉시값 0으로 CMP를 사용하는 유일한 일반적인 이유는 메모리 피연산자와 비교하려는 경우입니다(예: cmpb $0, (%esi)
암시적 길이의 C 스타일 문자열 끝에 종료 0바이트가 있는지 확인합니다.
AVX512F 추가 kortestw k1, k2
및 AVX512DQ/BW(KNL이 아닌 Skylake) 추가 ktestb/w/d/q k1, k2
, AVX512 마스크 레지스터(k0..k7)에서 작동하지만 여전히 다음과 같은 일반 FLAGS를 설정합니다. test
정수와 같은 방식으로 OR
또는 AND
지시는 합니다.
kortestw k1,k1
SSE/AVX2를 대체하는 AVX512 비교 결과를 기반으로 분기/cmovcc/setcc를 수행하는 관용적 방법입니다. (v)pmovmskb/ps/pd
+ test
또는 cmp
.
사용 jz
대 je
혼란스러울 수 있습니다.
jz
그리고 je
문자 그대로 동일한 지시 사항입니다., 즉.기계 코드의 동일한 opcode. 그들은 동일한 일을 하지만 인간에게는 다른 의미를 갖습니다..디스어셈블러(및 일반적으로 컴파일러의 asm 출력)는 하나만 사용하므로 의미적 구별이 손실됩니다.
cmp
그리고 sub
두 입력이 같을 때 ZF를 설정합니다(예:빼기 결과는 0입니다). je
(같으면 점프)는 의미상 관련된 동의어입니다.
test %eax,%eax
/ and %eax,%eax
결과가 0일 때 다시 ZF를 설정하지만 "동등성" 테스트는 없습니다.테스트 후 ZF는 두 피연산자가 같은지 여부를 알려주지 않습니다.그래서 jz
(0이면 점프)는 의미상 관련된 동의어입니다.
이 코드 스 니펫은 일부 구조물이나 물체에 대한 포인터가 주어진 서브 루틴에서 나온 것입니다. 두 번째 라인은 포인터에서 해당 물건에서 값을 가져 오는 것입니다. 아마도 포인터 일 수도 있고 아마도 int 일 수 있습니다. 3 라인과 4 라인은이 값을 0에 대해 테스트하고 (포인터 인 경우 NULL) 0이면 다음 몇 가지 작업 (표시되지 않음)을 건너 뜁니다.
0에 대한 테스트는 때때로 즉각적인 리터럴 제로 값과 비교하여 코딩되지만 테스트 OP가 더 빨리 실행될 것이라고 생각했을 수도있는 컴파일러 (또는 인간?) 이름 변경. 그것은 명백한 Mov Eax, #0 (오래된 표기법을 사용하는 것이 아니라 콜로라도에서 누군가의 번호판에서 보았던 Xor Eax, eax)와의 레지스터를 지우는 아이디어를 보유한 것과 같은 트릭 가방에서 나온 것입니다. ).
ASM에서는 perl, tmtowtdi와 같이.
EAX가 0이면 조건부 점프를 수행합니다. 그렇지 않으면 319E9에서 계속 실행됩니다.
일부 프로그램에서는 버퍼 오버플로를 확인하는 데 사용할 수 있습니다. 할당 된 공간의 맨 위에는 0이 배치됩니다. 데이터를 스택에 입력 한 후 할당 된 공간의 시작 부분에서 0을 찾아 할당 된 공간이 오버플로되지 않도록합니다.
그것은 악용 운동의 STACK0 운동에 사용되어 오버플로되었는지 확인하고 거기에없고 0이 있는지 확인하면 "다시 시도해보기"가 표시됩니다.
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가 0, zf = 1이면 %edx가 0이 아니고 testl 이후 -1, of = 0, sf = 1이면 jump .sorry, gramp .sorry, gramp. 내 영어는 가난합니다