(가정 86) 먼저 당신은 스택을 이해해야한다. 함수는 "스택"이라는 메모리 영역을 사용합니다. 각 플레이트에는 DWORD (32 비트) 데이터가 포함되어있는 플레이트 스택처럼 생각할 수 있습니다. CPU에는 스택의 현재 위치 (가상 메모리 주소 일뿐)를 기록하는 레지스터가 있습니다. 스택 포인터라고하며 일반적으로 esp 레지스터에 저장됩니다.
기능은 스택과 상호 작용
, 그들은 일반적으로 두 가지 중 하나를 수행 같습니다
푸시 또는
팝합니다. "밀어 넣기"는 스택 포인터를 스택 상단에 놓을 때 스택 포인터를 다음으로 가장 높은 위치로 이동시킨 다음 그 새로운 위치 (새로운 최상위 위치)로 복사하는 것으로 구성됩니다. 밀어 넣기는 더 많은 데이터가 저장되어 있기 때문에 "스택을 증가시킵니다"(더 많은 플레이트).
"팝"은 스택의 최상위 항목이 현재 스택 상단 (esp 레지스터가 가리키고있는 것)에서 cpu 레지스터 (일반적으로 eax) 스택 포인터를 스택 아래쪽의 한 위치로 이동합니다.
이제 함수를 호출하도록 설정할 수 있습니다.
코드
t.B(3, 4);
조립체 호 발생
// here is a push we described above. The function we are in currently is
// pushing the value "4" onto the stack. This is one of the arguments to the
// B function we are calling. Note that we push the last argument first
push 4
// here is another push. This time we are pushing the next argument to the
// B function
push 3
call B // this call sets up the context for the next function to run
우리 함수 현재 함수의 문맥 전환되어 호출된다. 함수가 실행할 필요가있는 여분의 peices 정보는 우리가 스택에 푸시 한 인수입니다.
새로운 함수는 스택에있는 로컬 변수를위한 공간을 만들기 위해 스택을 유지하고 스택 포인터를 레지스터에 저장하여 함수가 반환되면 되돌릴 수 있도록합니다. 이것이 발생하지 않는다면 호출 함수는 이전에 스택에 놓인 물건에 어떻게 접근할지 모르는 제어권을 회복 할 때 모든 방향이 혼란 스러울 것입니다. 예를 들어 자신의 로컬 변수 나 스택 포인터의 컨텍스트와 같은 것입니다. 함수를 호출했습니다.
여기 어셈블리가 진행 중입니다 (Havenard에서 이것을 훔치기).
// Here is the B function making sure that the calling function can get back to
// the it's stack context when B returns.
push ebp
mov ebp, esp
// remember when I said that a push was growing the stack. Well you can also grow
// it just by moving the stack pointer higher, as if there were already more plates there
// you may wonder why we are subtracting (sub) from the stack pointer (esp) to grow it
// the reason is that the stack "grows down" in memory. In other words, as the stack grows
// the memory addresses of the stack grow smaller.
// the reason we are subtracting 4 is because we only need to grow the stack by one plate
// so that we can store the local variable 'result' there. If we had 2 local variables
// we would have subtracted 8
sub esp, 4
// the instructions below are simply moving the static value 1 into the local variable
// 'result'. Local variables are always referenced relative to the bottom of the stack
// context for the current function. This value is stored in the ebp register, which we
// saw earlier in the function setup above.
// so now we think of the location where the 'result' variable is stored as "ebp-4"
// we know that because we put it there.
mov dword ptr [ebp-4], 1 // result = 1 (true)
// eax is a special register that contains the return value of the function. That is why
// you see the value of 'result' (which we know as [ebp-4] in the eax register
mov eax, dword ptr [ebp-4]
// We adjust the stack pointer back to it's previous location
// before we subtracted to make room for our local variable
add esp, 4
// Our work is done now.. time to clean stuff up for our calling function and
// leave things as we found them. Our trusty ebp register stores the old stack pointer
// that our calling function needs to resume it's stack context.
mov esp, ebp
pop ebp
ret
은 내가 특히 B 함수에서 반환에 탈락 한 몇 가지 세부 사항이 있습니다 확신 해요,하지만 내 생각은 꽤 좋은 개요입니다.
당신이 말한 질문과 같이, 이것은 너무 광범위한 질문입니다. 전체 챕터 (또는 전체 책)이 주제에 기록되었습니다. –
@ Neeil이 동의했지만, 아주 간단한 예를 들자면, 괜찮은 개요가 설명 될 수 있다고 생각합니다. 내 시도를 아래에서보십시오. –