2011-04-20 5 views
3

조립을 처음하다. 나는이 다음 함수 조립에누군가가 어셈블리 코드를 설명해 주시겠습니까?

int foo(char *argv[]) 
{ 
    char buf[256]; 
    bar(argv[1], buf); 
} 

-

0x08048473 <foo+0>:push %ebp 
0x08048474 <foo+1>:mov %esp,%ebp 
0x08048476 <foo+3>:sub $0x118,%esp 
0x0804847c <foo+9>:mov 0x8(%ebp),%eax 
0x0804847f <foo+12>:add $0x4,%eax 
0x08048482 <foo+15>:mov (%eax),%edx 
0x08048484 <foo+17>:lea -0x100(%ebp),%eax 
0x0804848a <foo+23>:mov %eax,0x4(%esp) 
0x0804848e <foo+27>:mov %edx,(%esp) 
0x08048491 <foo+30>:call 0x8048454 <bar> 
0x08048496 <foo+35>:leave 
0x08048497 <foo+36>:ret  

사람이 나에게 설명 할 수주십시오? 왜 거기에 하위 280이 있습니까? 256 바이트는 스택에 확실히 할당됩니다. 나는 나머지를 설명 할 수 없다.

답변

4

스택은 로컬 변수뿐만 아니라 함수에 필요한 중간 값에도 사용됩니다. 여기에서 foo() 함수는 두 개의 포인터, 즉 문자열 (argv[1])과 다른 하나를 buf 변수에 지정하여 bar()을 호출합니다. 그 포인터 값은 스택에, 즉 mov %eax,0x4(%esp)mov %edx,(%esp) opcode로 푸시됩니다. 따라서 foo()에는 256 바이트 이상의 스택 공간이 필요합니다. 자세한 내용은에서

:

표준 함수 프롤로그의
0x08048473 <foo+0>:push %ebp 
0x08048474 <foo+1>:mov %esp,%ebp 

: 함수가 (즉, 인자)라고했다 전에 스택 요소 에 포인트 %ebp을 사용합니다.

0x08048476 <foo+3>:sub $0x118,%esp 

일부 공간

주로 (뿐만 아니라) buf[]를 들어, 스택에 예약되어 있습니다.

0x0804847c <foo+9>:mov 0x8(%ebp),%eax 
0x0804847f <foo+12>:add $0x4,%eax 
0x08048482 <foo+15>:mov (%eax),%edx 

0x8(%ebp)argv 함수 인수입니다. 이 opcode는 argv[1]에서 포인터를 가져 와서 결과를 %edx에 저장합니다. 이것은 bar()의 첫 번째 인수가됩니다. %eax

0x08048484 <foo+17>:lea -0x100(%ebp),%eax 

이 저장 buf[]의 주소 - 컴파일러 buf[] 그것이 sub으로 예약 된 스택 스페이스의 상부 256 바이트에 위치 할 것을 결정했다. bar()위한

0x0804848a <foo+23>:mov %eax,0x4(%esp) 
0x0804848e <foo+27>:mov %edx,(%esp) 

개의 인수가 스택에 푸시 (실제로 두 상위 스택 위치로 작성 %esp 이미 조정되어 있음).

0x08048491 <foo+30>:call 0x8048454 <bar> 

bar()이 호출됩니다.

0x08048496 <foo+35>:leave 
0x08048497 <foo+36>:ret 

leave

는 프롤로그 (그것은 mov %ebp, %esp; pop %ebp 동등하다) 취소합니다. ret이 함수를 종료합니다.

GCC는 스택에 조금만 할당하는 것으로 알려져 있습니다. 여기에 280 대신에 264 바이트를 예약 할 수 있습니다. 이것은 내부 레지스터 할당 최적화 도구의 결과입니다 (여분의 스택 슬롯 은 중간 값을 저장하는 데 사용되는 이었지만 옵티마이 저는 마지막으로 해당 값을 유지하는 방법을 발견했습니다. 레지스터 전용).

+0

감사합니다. 그것은 매우 분명했습니다.그래서 처음 두 줄은 함수 반환 값이 저장된 곳입니다. 반환 값이 함수 매개 변수 다음에, 호출 된 함수의 로컬 변수 앞에 저장되지 않았습니까? – user220201

+0

반환 값은 일반적으로 기존 레지스터 (x86 프로세서의 % eax)에서 교환됩니다. 여기서 당신은'return'을 가지지 않기 때문에 어셈블리 코드는'% eax'에 대해 아무 것도하지 않습니다 : 호출자는'foo()'가 그 시점에서'% eax'의 값을 포함하는 값을 반환한다는 것을 알게 될 것입니다. –

+0

bar()가 돌아 오는 지점에 대해 물어보기를 바랍니다. bar가 반환되면 foo()가 실행을 계속하는 지점입니다. 저장되어있는 곳은 어디입니까? – user220201

관련 문제