programing

기본 포인터와 스택 포인터란 정확히 무엇입니까?그들은 무엇을 가리키고 있나요?

prostudy 2022. 7. 7. 22:27
반응형

기본 포인터와 스택 포인터란 정확히 무엇입니까?그들은 무엇을 가리키고 있나요?

DrawSquare()가 DrawLine()을 호출하는 위키피디아에서 가져온 이 예를 사용합니다.

alt text

(이 그림에서는, 하단의 주소가 높고, 상단의 주소가 낮은 것에 주의해 주세요).

누가 설명 좀 해줄래?ebp그리고.esp이 문맥에 있나요?

제가 봤을 때 스택 포인터는 항상 스택의 상단을 가리키고 베이스 포인터는 현재 함수의 선두를 가리킨다고 할 수 있습니다.아니면?


edit: Windows 프로그램의 컨텍스트에서 이것을 의미합니다.

edit2: 그럼 어떻게?eip일하는 것도요?

edit3: MSVC++에서 다음 코드를 취득했습니다.

var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
hInstance= dword ptr  8
hPrevInstance= dword ptr  0Ch
lpCmdLine= dword ptr  10h
nShowCmd= dword ptr  14h

모두 dwords인 것 같아서 각각 4바이트가 소요됩니다.따라서 hInstance에서 var_4 of 4 바이트에 갭이 있음을 알 수 있습니다.뭐야?Wikipedia의 사진처럼 반송주소라고 생각됩니다.


(편집자 주: 마이클의 답변에서 질문에 해당되지 않는 긴 인용구를 삭제했지만 후속 질문은 편집되었습니다.)

이는 함수 호출의 흐름이 다음과 같기 때문입니다.

* Push parameters (hInstance, etc.)
* Call function, which pushes return address
* Push ebp
* Allocate space for locals

여기서 질문(마지막, 희망!)은 호출하고 싶은 함수의 인수를 팝하는 순간부터 프롤로그의 마지막까지 정확히 어떤 일이 일어나는가 하는 것입니다.ebp, 특히 그 순간에 어떻게 진화하는지를 알고 싶다(프롤로그가 어떻게 동작하는지 이미 이해하고 있다.스택에 인수를 푸시한 후와 프롤로그 전에 무슨 일이 일어나고 있는지 알고 싶다).

ESP는 현재 스택 포인터입니다.단어 또는 주소가 스택에 푸시되거나 스택에서 팝업될 때마다 변경됩니다. EBP컴파일러가 함수의 파라미터와 로컬 변수를 추적하는 데 보다 편리한 방법입니다.ESP직접적으로.

일반적으로(그리고 이것은 컴파일러마다 다를 수 있습니다), 호출되는 함수에 대한 모든 인수는 호출 함수에 의해 스택에 푸시됩니다(보통 함수 프로토타입에서 선언된 역순서입니다만, 이것은 다릅니다).그 후 함수가 호출되어 반환 주소가 푸시됩니다( ).EIP)를 스택에 추가합니다.

구기능에 들어가면EBP값이 스택에 푸시되고EBP의 값으로 설정됩니다.ESP그 다음에ESP(스택이 메모리 내에서 하향으로 증가하기 때문에) 감소하여 함수의 로컬 변수 및 임시용 공간을 할당합니다.그 시점부터, 함수의 실행 중에, 함수에 대한 인수는, 스택상에, 다음의 양의 오프셋으로 배치됩니다.EBP(이것들은 함수 호출 전에 푸시되었기 때문에) 및 로컬 변수는 에서 음의 오프셋에 있습니다.EBP(함수 엔트리 후에 스택에 할당되었기 때문입니다).그렇기 때문에EBP함수 콜프레임의 중심을 가리키기 때문에 프레임 포인터라고 불립니다.

종료 시 기능만 설정하면 됩니다.ESP값어치에 맞게EBP(스택에서 로컬 변수의 할당을 해제하고 엔트리를 공개합니다.EBP스택의 맨 위)에서 이전 버전을 팝합니다.EBP스택으로부터의 값을 반환하고 나서, 함수가 반환한다(복귀 주소를 에 입력).EIP).

콜링 함수로 돌아가면 콜링 함수가 증가합니다.ESPfunction 인수를 삭제하기 위해 다른 함수를 호출하기 직전에 스택에 푸시했습니다.이 시점에서 스택은 착신 함수를 호출하기 전의 상태로 돌아갑니다.

esp당신이 말한 그대로, 스택의 맨 위입니다.

ebp보통 으로 설정됩니다.esp기능을 시작할 때 사용합니다.함수 파라미터와 로컬 변수는 각각 에서 일정한 오프셋을 더하고 빼서 액세스합니다.ebp에 의해 "x86"이 정의됩니다ebp여러 함수 호출 간에 유지되는 것으로 간주됩니다. ebp그 자체는 실제로 이전 프레임의 기본 포인터를 가리키고 있습니다.이 포인터는 스택을 디버거로 이동하고 다른 프레임 로컬 변수를 표시하여 작동할 수 있도록 합니다.

대부분의 기능 프롤로그는 다음과 같습니다.

push ebp      ; Preserve current frame pointer
mov ebp, esp  ; Create new frame pointer pointing to current stack top
sub esp, 20   ; allocate 20 bytes worth of locals on stack.

그런 다음 함수 후반부에 다음과 같은 코드가 있을 수 있습니다(두 로컬 변수가 모두 4바이트라고 가정함).

mov [ebp-4], eax    ; Store eax in first local
mov ebx, [ebp - 8]  ; Load ebx from second local

FPO 또는 프레임 포인터 생략 최적화를 유효하게 할 수 있는 경우, 실제로는 이것을 배제하고,ebp다른 지역 주민을 등록하고 접근하기 위해esp에 직접 수 .

편집:

갱신된 질문의 경우 스택에서 누락된2개의 엔트리는 다음과 같습니다.

var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
*savedFramePointer = dword ptr 0*
*return address = dword ptr 4*
hInstance = dword ptr  8h
PrevInstance = dword ptr  0C
hlpCmdLine = dword ptr  10h
nShowCmd = dword ptr  14h

이는 함수 호출의 흐름이 다음과 같기 때문입니다.

  • 파라미터( 「 parameters 「 」hInstance의 개요)
  • 반환 주소를 푸시하는 콜 함수
  • ebp
  • 지역 주민을 위한 공간 할당

네 말이 맞아.스택 포인터는 스택의 상위 항목을 가리키고 베이스 포인터는 함수를 호출하기 전의 스택의 "이전" 상단을 가리킵니다.

함수를 호출하면 로컬 변수가 스택에 저장되고 스택포인터가 증가합니다.함수에서 돌아오면 스택의 모든 로컬 변수가 범위를 벗어납니다.이를 수행하려면 스택 포인터를 기본 포인터(함수 호출 전 "이전" 상단)로 되돌립니다.

이 방법으로 메모리를 할당하는 은 매우 빠르고 효율적입니다.

편집: 자세한 내용은 x86 어셈블리에 대한 WikiBook의 x86 분해/기능 및 스택 프레임을 참조하십시오.Visual Studio 사용에 관심이 있을 만한 정보를 추가하려고 합니다.

발신자 EBP를 첫 번째 로컬 변수로 저장하는 것은 표준 스택프레임이라고 불리며, 이는 Windows 상의 거의 모든 콜규칙에 사용할 수 있습니다.발신자 또는 착신자가 전달된 파라미터의 할당을 해제하고 레지스터로 전달되는 파라미터의 할당은 다르지만 이는 표준 스택프레임 문제와 직교합니다.

Windows 프로그램 얘기가 나와서 말인데 Visual Studio를 사용하여 C++ 코드를 컴파일할 수 있습니다.Microsoft 에서는 Frame Pointer Exclossion 이라고 하는 최적화를 사용하고 있기 때문에 dbghlp 라이브러리와 PDB 파일을 실행 파일에 사용하지 않고 스택을 이동하는 것은 거의 불가능합니다.

이 프레임 포인터 누락은 컴파일러가 오래된 EBP를 표준 위치에 저장하지 않고 EBP 레지스터를 다른 용도로 사용하기 때문에 로컬 변수가 특정 함수에 얼마나 많은 공간을 필요로 하는지 모르기 때문에 발신자 EIP를 찾는 데 어려움이 있음을 의미합니다.물론 Microsoft는 이 경우에도 스택 워크를 수행할 수 있는 API를 제공하지만 PDB 파일에서 심볼 테이블 데이터베이스를 검색하는 데 시간이 너무 오래 걸리는 경우도 있습니다.

컴파일 유닛에서 FPO를 회피하려면 /O2 사용을 피하거나 프로젝트의 C++ 컴파일 플래그를 명시적으로 추가해야 합니다.릴리스 설정에서 FPO를 사용하는 C 또는 C++ 런타임에 대해 링크하는 경우가 많기 때문에 dbghlp.dll이 없으면 스택워크를 실행하기가 어렵습니다.

우선 x86 스택은 높은 주소 값에서 낮은 주소 값으로 구축되기 때문에 스택 포인터는 스택의 하단을 가리킵니다.스택 포인터는 푸시할 다음 콜(또는 콜)이 다음 값을 설정하는 포인트입니다.이 동작은 C/C++ 문과 동일합니다.

 // push eax
 --*esp = eax
 // pop eax
 eax = *esp++;

 // a function call, in this case, the caller must clean up the function parameters
 move eax,some value
 push eax
 call some address  // this pushes the next value of the instruction pointer onto the
                    // stack and changes the instruction pointer to "some address"
 add esp,4 // remove eax from the stack

 // a function
 push ebp // save the old stack frame
 move ebp, esp
 ... // do stuff
 pop ebp  // restore the old stack frame
 ret

베이스 포인터는 현재 프레임의 맨 위에 있습니다.ebp는 일반적으로 반환 주소를 가리킵니다. ebp+4는 함수의 첫 번째 파라미터(또는 클래스 메서드의 이 값)를 가리킵니다.ebp-4는 함수의 첫 번째 로컬 변수(보통 이전 값 ebp)를 가리키므로 이전 프레임 포인터를 복원할 수 있습니다.

esp는 "Extended Stack Pointer" ....ebp는 "Something Base Pointer" ....eip은 "Something Instruction Pointer"......스택 포인터는 스택세그먼트의 오프셋주소를 가리킵니다.베이스 포인터는 추가 세그먼트의 오프셋 주소를 가리킵니다.명령 포인터는 코드 세그먼트의 오프셋 주소를 가리킵니다.이제, 세그먼트에 대해서...프로세서 메모리 영역의 소규모 64KB 분할입니다.이 프로세스를 메모리 세그멘테이션이라고 합니다.이 글이 도움이 되었기를 바랍니다.

어셈블리 프로그래밍을 한 지 오래되었지만링크는 유용할 수 있습니다.

프로세서에는 데이터를 저장하는 데 사용되는 레지스터 컬렉션이 있습니다.이들 중 일부는 직접 값이고 다른 일부는 RAM 내의 영역을 가리키고 있습니다.레지스터는 특정 동작에 사용되는 경향이 있으며 어셈블리의 모든 오퍼랜드에는 특정 레지스터에 일정량의 데이터가 필요합니다.

스택 포인터는 다른 프로시저를 호출할 때 주로 사용됩니다.최신 컴파일러에서는 많은 데이터가 먼저 스택에 덤프되고 그 다음에 반환 주소가 지정되므로 반환하라는 명령을 받으면 시스템이 반환 위치를 알 수 있습니다.스택 포인터는 새로운 데이터를 스택에 푸시할 수 있는 다음 위치를 가리키며, 스택이 다시 팝업될 때까지 스택에 머무릅니다.

베이스 레지스터 또는 세그먼트 레지스터는 대량의 데이터 주소 공간을 가리킵니다.두 번째 레지스터와 결합하면 베이스 포인터는 메모리를 큰 블록으로 분할하고 두 번째 레지스터는 이 블록 내의 항목을 가리킵니다.이에 대한 기본 포인터는 데이터 블록의 기본을 가리킵니다.

어셈블리는 CPU에 따라 매우 고유하다는 점에 유의하십시오.링크된 페이지에는 다양한 유형의 CPU에 대한 정보가 나와 있습니다.

언급URL : https://stackoverflow.com/questions/1395591/what-is-exactly-the-base-pointer-and-stack-pointer-to-what-do-they-point

반응형