스택 포인터 값 출력
리눅스(Debian 및 Ubuntu)에서 C의 스택 포인터에서 현재 값을 출력하려면 어떻게 해야 합니까?
구글을 시도해 보았지만 결과가 나오지 않았습니다.
휴대가 불가능하거나 작동이 보장되지 않는 한 가지 방법은 로컬의 주소를 포인터로 간단히 인쇄하는 것입니다.
void print_stack_pointer() {
void* p = NULL;
printf("%p", (void*)&p);
}
이것은 본질적으로 다음의 주소를 출력할 것입니다.p
현재 스택 포인터의 좋은 근사치입니다.
그것을 할 수 있는 휴대용 방법은 없습니다.
GNUC에서 이것은 gcc가 "SP"를 ESP 또는 RSP의 줄임말로 인식하는 x86을 포함하여 SP라는 이름의 레지스터를 가진 대상 ISA에서 작동할 수 있습니다.
// broken with clang, but usually works with GCC
register void *sp asm ("sp");
printf("%p", sp);
로컬 레지스터 변수의 사용은 이제 GCC에 의해 더 이상 사용되지 않습니다.
이 기능에 대해 지원되는 유일한 용도는 확장 asm을 호출할 때 입력 및 출력 피연산자에 대한 레지스터를 지정하는 것입니다.
레지스터 변수를 정의해도 레지스터가 예약되지 않습니다.Extended asm을 호출하는 경우를 제외하고는 지정된 레지스터의 내용이 보장되지 않습니다.이러한 이유로 다음과 같은 용도는 명시적으로 지원되지 않습니다.만약 그들이 작동하는 것처럼 보인다면, 그것은 단지 우연일 뿐이고, 주변 코드의 관련 없는 변경 또는 심지어 미래 버전의 gcc의 최적화의 사소한 변경으로 인해 의도한 대로 작동을 멈출 수 있습니다.
또한 클랑(clang)과의 연습에서도 깨졌습니다.sp
초기화되지 않은 다른 변수와 같이 취급됩니다.
특정 GCC에 대한 듀들0r의 답변 외에 GCC 특정(x86 특정은 아님)을 사용할 수 있습니다.
이것은 Clang에서도 작동할 것입니다. (그러나 그것에 대한 버그가 있습니다.)
재러드 파가 대답한 것처럼 지역 주민의 주소를 취하는 것도 해결책입니다.
AFAIK the C 표준은 이론적으로 어떤 콜 스택도 요구하지 않습니다.
아펠의 논문을 기억하세요: 쓰레기 수집은 스택 할당보다 빠를 수 있습니다. 매우 이상한 C 구현은 그러한 기술을 사용할 수 있습니다!하지만 AFAIK는 C에 사용된 적이 없습니다.
한 사람은 다른 기술을 꿈꿀 수 있었습니다.또한 분할된 스택(적어도 최근 GCC에서는)을 가질 수 있는데, 이 경우 스택 포인터라는 개념은 의미가 훨씬 적습니다(그러면 스택이 연속적이지 않고 각각 몇 개의 호출 프레임으로 구성된 많은 세그먼트로 구성될 수 있기 때문입니다).
.Linux
당신은 사용할 수 있습니다.proc
스택 포인터를 인쇄할 의사 파일 시스템입니다.
여기 /proc/your-pid/stat pseudo-file, 필드를 보십시오.28
,29
.
startstack %lu 스택의 시작(즉, 하단) 주소입니다.
kstkesp %lu 프로세스의 커널 스택 페이지에 있는 ESP(스택 포인터)의 현재 값입니다.
이 두 개의 값을 분석하기만 하면 됩니다.
다음과 같은 확장 어셈블리 명령을 사용할 수도 있습니다.
#include <stdint.h>
uint64_t getsp( void )
{
uint64_t sp;
asm( "mov %%rsp, %0" : "=rm" ( sp ));
return sp;
}
32비트 시스템의 경우 64는 32로, rsp는 esp로 교체해야 합니다.
당신은 그 정보를 파일에 가지고 있습니다./proc/<your-process-id>/maps
, 현과 같은 선으로[stack]
(따라서 컴파일러나 머신과는 독립적입니다).이 접근 방식의 유일한 단점은 해당 파일을 읽기 위해서는 루트가 필요하다는 것입니다.
lldb or gdb를 시도합니다.예를 들어 lldb에서 역추적 형식을 설정할 수 있습니다.
settings set frame-format "frame #${frame.index}: ${ansi.fg.yellow}${frame.pc}: {pc:${frame.pc},fp:${frame.fp},sp:${frame.sp}} ${ansi.normal}{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n"
그래서 우리는 bp, spin debug을 출력할 수 있습니다.
frame #10: 0x208895c4: pc:0x208895c4,fp:0x01f7d458,sp:0x01f7d414 UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 376
https://lldb.llvm.org/use/formatting.html 에서 자세히 보기
setjmp를 사용할 수 있습니다.정확한 세부 정보는 구현에 따라 다릅니다. 헤더 파일을 찾아보세요.
#include <setjmp.h>
jmp_buf jmp;
setjmp(jmp);
printf("%08x\n", jmp[0].j_esp);
알 수 없는 코드를 실행할 때도 편리합니다.전후에 sp를 확인하고 a를 할 수 있습니다.longjmp
치우기 위해서.
msvc를 사용하는 경우 제공된 _AddressOfReturnAddress() 함수를 사용할 수 있습니다.
그것은 반환 주소의 주소를 반환할 것이고, 이것은 함수의 입구에서 RSP의 값이 주소는 반환 주소를 반환합니다.해당 기능을 사용하고 돌아오면 리턴 주소가 팝업오프되기 때문에 RSP 값이 8만큼 증가합니다.이 정보를 사용하면 스택 포인터의 현재 주소를 다음과 같이 반환하는 간단한 함수를 작성할 수 있습니다.
uintptr_t GetStackPointer() {
return (uintptr_t)_AddressOfReturnAddress() + 0x8;
}
int main(int argc, const char argv[]) {
uintptr_t rsp = GetStackPointer();
printf("Stack pointer: %p\n", rsp);
}
다음을 사용할 수 있습니다.
uint32_t msp_value = __get_MSP(); // Read Main Stack pointer
마찬가지로 PSP 값을 얻으려면 다음과 같이 하십시오.
uint32_t psp_value = __get_PSP(); // Read Process Stack pointer
어셈블리 언어를 사용하려면 MSP 및 PSP 프로세스를 사용할 수도 있습니다.
MRS R0, MSP // Read Main Stack pointer to R0
MRS R0, PSP // Read Process Stack pointer to R0
언급URL : https://stackoverflow.com/questions/20059673/print-out-value-of-stack-pointer
'source' 카테고리의 다른 글
각 줄의 텍스트 파일을 파워셸을 통해 배열로 저장하는 방법 (0) | 2023.10.18 |
---|---|
jQuery를 사용하여 텍스트 정렬 스타일을 동적으로 추가하는 방법 (0) | 2023.10.18 |
Windows에서 MySQL Workbench가 열리지 않음 (0) | 2023.10.08 |
Android에서 상대 레이아웃의 Z 순서 보기 정의 (0) | 2023.10.08 |
파워셸 ISE에서 런스페이스를 재설정할 수 있습니까? (0) | 2023.10.08 |