저는 CodeProject here에있는 기사를 읽음으로써 C와 GCC에서 AT & T 스타일 인라인 어셈블리를 소량 사용하려고합니다. 이 작업을 수행하려는 주된 이유는 내 코드에서 신뢰할 수있는 명령어 주소를 가질 수 있도록 EIP 레지스터의 기존 값을 찾는 것입니다. 나는 지금까지이 개념에 대한 이해를 보여주기 위해 간단한 예제 프로그램을 작성했습니다 :C에서 함수의 반송 주소를 찾는 방법은 무엇입니까?
#include <stdio.h>
#include <stdlib.h>
int mainReturnAddress = 0;
int main()
{
asm volatile (
"popl %%eax;"
"pushl %%eax;"
"movl %%eax, %0;"
: "=r" (mainReturnAddress)
);
printf("Address : %d\n", mainReturnAddress);
return 0;
}
이 특정 예제의 목적은에서 저장된 32 비트 리턴 어드레스를 나타내는 스택의 상단에서 4 바이트를 팝업하는 것입니다 EIP 레지스터에 넣고 스택에 다시 밀어 넣습니다. 그 다음, 나는 그것을 글로벌 변수 mainReturnAddress
변수에 저장한다. 마지막으로 mainReturnAddress에 저장된 값을 인쇄합니다.
이 코드의 출력은 4200560
입니다.
이 코드는 앞서 언급 한 목적을 달성합니까? 이것이 Windows 플랫폼 32 비트의 교차 프로세서입니까?
무엇이 스택에 있는지는 구현에 따라 다릅니다. 로컬 스택 변수를 가지고 있다면, 스택 상에도 존재할 것이므로, 스택의 최상위를 터뜨려도 원하는 것을 얻을 수 있다고 보장 할 수는 없습니다. 그런데 왜 귀국 주소가 필요한가요? 만약 당신이 어떤 명령의 "신뢰할 수있는"주소를 얻길 원한다면'int mainAddress = (int) main;'그냥'main' 자체의 주소를 얻을 수 있습니다. 어떤 사람들은'(int) & main'을하고 싶지만 그렇게 할 필요는 없습니다. –
Mark와 Carl이 만든 좋은 점 이외에,이 asm은 gcc에게 그렇게하지 않고 eax를 수정합니다. 이것은 매우 이상한 버그를 소개하는 좋은 방법입니다. 더 나은 해결책은 pushl/popl %% eax를 % 0을 사용하도록 변경하고 movl을 제거하는 것입니다. 아, 64 비트를 지원하려고한다면 포인터를 int로 취급하는 것은 나쁜 생각입니다. 어쨌든 나쁜 습관. –