나는 C 코드를 통해 프로그램의 특정 트레이스에 사용 된 레지스터의 수를 알아 내야 만했다. push 또는 pop 명령이 발생할 때마다 ESP 레지스터를 저장하는 것을 무시했다. 또한 X86 명령어를 참조했다. 그리고 거기에 "ESP, 스택 포인터,"사용해서는 안된다. "왜?"왜 PUSH 또는 POP 명령어를 사용하는 동안 ESP 레지스터를 사용하지 않는 것이 좋습니까?
답변
일반용 레지스터로 사용하면 안됩니다. 적절한주의를 기울여 스택 포인터로 사용하십시오. 예 : 'sub esp, ...'명령을 사용하여 스택의 로컬 변수에 대한 일부 메모리를 예약 할 수 있지만 ret 명령 전에 원래 값을 복원해야합니다.
x86에서 ESP
은 스택 포인터입니다. 원래 16 비트 8088 및 8086 프로세서에서 레지스터는 S tack ointer에 대해 간단히 SP
이라고 불 렸습니다. 386 프로세서에서 32 비트 지원이 추가되면 E
접두사 ("확장"용)가 모든 레지스터 이름에 추가되어 ESP
이됩니다. 스택 포인터는 항상 현재 모드에서 프로세서의 기본 단어 크기와 동일한 비트 폭을가집니다. 즉, 32 비트 보호 모드에서 실행중인 경우 스택 포인터는 32 비트 너비이고 ESP
에 저장됩니다. 16 비트 리얼 모드에서 실행중인 경우 스택 포인터는 16 비트 너비이고 SP
에 저장됩니다.
x86 아키텍처의 64 비트 확장 (다양하게 알려진 AMD64, x86-64 또는 x64)은 레지스터를 64 비트로 확장하고 R
접두어를 추가했습니다. 따라서, RSP
레지스터는 스택 포인터를 포함하는데, 이는 긴 (64 비트) 모드로 실행될 때 64 비트 폭이다.
이 레지스터의 다른 레지스터 (EAX
는 ECX
가 EDX
가 EBX
, ESI
, EDI
및 EBP
)는,이 등가 방식으로 사용될 수 없다 개념적으로 유사하지만. 스택 포인터를 유지하려면 만 설계되었으므로 범용 레지스터로 사용할 수 없습니다.
명시 적으로 스택 포인터를 누르거나 팝하지 않는 이유는 다른 명령에 의해 암시 적으로 수행되기 때문입니다. 사실, PUSH
과 POP
명령어는 스택 포인터를 조작하는 명령어입니다. 스택 포인터를 조작하여 스택에 푸시하고 팝하기 때문입니다.
x86에서 스택은 항상 메모리에서 아래쪽으로 커지므로 은 스택 포인터에서 적절한 바이트 수를 뺍니다 (피연산자 크기에 따라). POP
은 적절한 바이트 수를 추가합니다.
CALL
및 RET
명령어도 암시 적으로 스택 포인터를 조작합니다. 자세한 내용은 Intel x86 아키텍처 설명서 인 available here을 참조하십시오. x86 태그 위키에는 다른 많은 리소스가 있습니다.
ESP
레지스터가 명시 적으로 조작되는 것을 볼 수있는 유일한 시간은 ADD
또는 SUB
명령어의 대상 피연산자로 사용될 때입니다. 이들은 일반적으로 컴파일러를 최적화하고 값을 저장하거나 스택을 정리하기 위해 필요한만큼 스택 포인터를 증가 시키거나 감소 시켜서 함수의 프롤로그 및 에필로그에 삽입됩니다. 그들은 PUSH
및 POP
과 유사하게 기능하지만, 행에 여러 번 푸시 및 팝하는 효과가있을 수 있습니다.예를 들어 :
push eax
push eax
push eax
push eax
...
pop eax
pop eax
pop eax
pop eax
간단하게 교체 할 수 있습니다 :
sub eax, 16
...
add eax, 16
(실제로 저장EAX
의 값으로 시도되지 않은 단지에 공간을 만들기 위해 PUSH
를 사용하고 있다고 가정 스택).
ur 대답은 내가 작성한 것입니다. 그 값은 스택에 데이터를 저장할 위치를 가리키는 유일한 레지스터이기 때문에 복원해야합니다.> 그렇다면 스택이 엉망이되는 것을 막는 이유는 무엇입니까? – archies50
네, 그렇습니다. – Serge