함수 arg에 액세스하기 위해 x86 스택을 popping할 때의 세그먼트화 오류
x86 어셈블리와 C를 연결하려고 합니다.
내 C 프로그램:
extern int plus_10(int);
# include <stdio.h>
int main() {
int x = plus_10(40);
printf("%d\n", x);
return 0;
}
내 어셈블리 프로그램:
[bits 32]
section .text
global plus_10
plus_10:
pop edx
mov eax, 10
add eax, edx
ret
저는 다음과 같이 두 가지를 컴파일하고 연결합니다.
gcc -c prog.c -o prog_c.o -m32
nasm -f elf32 prog.asm -o prog_asm.o
gcc prog_c.o prog_asm.o -m32
그러나 결과 파일을 실행하면 분할 오류가 발생합니다.
하지만 내가 대체할 때
소아마비
와 함께
movedx, [syslog+4]
그 프로그램은 잘 작동합니다.누가 왜 이런 일이 일어나는지 설명해 주시겠습니까?
다음의 가능한 어셈블리 코드입니다.int x = plus_10(40);
push 40 ; push argument
call plus_10 ; call function
retadd: add esp, 4 ; clean up stack (dummy pop)
; result of the function call is in EAX, per the calling convention
; if compiled without optimization, the caller might just store it:
mov DWORD PTR [ebp-x], eax ; store return value
; (in eax) in x
이제 당신이 전화할 때plus_10
주소retadd
스택에 의해 밀립니다.call
설명.그것은 사실상.push
+jmp
,그리고.ret
효과적으로pop eip
.
스택은 다음과 같이 표시됩니다.plus_10
함수:
| ... |
+--------+
| 40 | <- ESP+4 points here (the function argument)
+--------+
| retadd | <- ESP points here
+--------+
ESP
반환 주소가 포함된 메모리 위치를 가리킵니다.
이제 당신이 사용할 수 있습니다.pop edx
반송 주소가 에 들어갑니다.edx
스택은 다음과 같습니다.
| ... |
+--------+
| 40 | <- ESP points here
+--------+
이제 당신이 실행하면,ret
이 시점에서 프로그램은 실제로 40 주소로 점프하여 segfault 또는 다른 예측 불가능한 방식으로 동작합니다.
컴파일러에 의해 생성된 실제 어셈블리 코드는 다를 수 있지만 이는 문제를 보여줍니다.
그나저나 함수를 작성하는 더 효율적인 방법은 다음과 같습니다. 대부분의 컴파일러는 이 작은 함수의 비선형 버전에 대해 최적화를 활성화하면 이 작업을 수행합니다.
global plus_10
plus_10:
mov eax, [esp+4] ; retval = first arg
add eax, 10 ; retval += 10
ret
이것은 보다 작고 약간 더 효율적입니다.
mov eax, 10
add eax, [esp+4] ; decode to a load + add.
ret
언급URL : https://stackoverflow.com/questions/56113827/segmentation-fault-when-popping-x86-stack-to-access-function-arg
'programing' 카테고리의 다른 글
C의 부동 소수점 데이터 유형 범위는? (0) | 2023.07.22 |
---|---|
한 열에서 고유한 열을 선택하고 다른 모든 열을 반환합니다. (0) | 2023.07.22 |
SpringBoot - HTTP 요청 헤더 구문 분석 오류 (0) | 2023.07.22 |
스프링 컨트롤러와 끝점의 차이 (0) | 2023.07.22 |
변수를 int 대 round() 함수에 사용 (0) | 2023.07.22 |