커널

14. 라즈베리파이 - 프로세스 스택

corin13 2025. 7. 13. 17:03

스택 최상단에 thread_info 위치함

===최상단 0x80C00000===

(Struct thread_info *) 0x80C00000

아래로 thread_info 필드들이 배치됨(amr64 기준)

(unsinged long flags)

(u64 premmpt_count) u32 need_resched, u32 count, u32 cpu

 

arm64에서 스택의 기본 크기 : 16kb(0x4000)

arm32 8kb(0x20000

 

스택 크기 확인

 

 

프로세스 스택은 어떻게 쌓이는가?

  • 높은 주소에서 낮은 주소로 자라남
  • 가장 먼저 호출된 함수는 프로세스 스택 최하단에 위치
  • 스택 포인터 위로 조절
  • 지역 변수, 복귀 레지스터도 스택에 저장
  • 하단부터 차곡차곡 저장
  • 위에 함수가 실행을 마치면, 아래 함수로 복귀
  • 리턴 주소를 스택에 저장
  • 함수 실행을 마치면, 돌아갈 주소 pop하고 ret

 

 

read_write.c 열기

 

바로 return하면서 ksys_write 호출

 

out에서 어셈블리로 보기

 

/__arm64_sys_write 검색

 

vmlinux 어셈블리 덤프 뜨기

vim vmlinux.d 검색하면 똑같은 코드가 보임

psciasp : 보안상 들어간

x29 : 프레임 포인터 저장하는 레지스터, x30 : 스택 포인터

stp x29, x30, [sp #-16] : 지금의 스택 포인터를 x29 x30 저장하고 현재 스택 포인터 -16

mov x29, sp : 감소된 스택 포인터를 프레임 포인터에 저장

<ksys_write> 이동

호출 이후 ldp 복구하는 과정

 

예제 - stackTest.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>


ssize_t ksys_write(int fd, const char *buf, size_t count) {
return 77;
}


ssize_t __arm64_sys_write(int fd, const char *buf, size_t count) {
return ksys_write(fd, buf, count);
}




int main() {
// 테스트를 위한 파일


__arm64_sys_write(7,(const char *)8,9);
return 0;
}

 

컴파일 gdb 열기

 

list 입력

 

break 10 하고 run

 

disass 결과 <__arm64_sys_write>+20 시점

sp fp(x29) 같은 값을 가지고 있음

w0 7, x1 8, x2 9 저장되어 있음

7,8,9 인자값이 레지스터에 저장된 stackTest.c에서 있음

<+0> : 스택 공간 확보

<+8> str w0, [sp, #44] : w0레지스터에 있는 값을 sp+44 저장해라

<+20~28>  : ksys_write 호출을 위해 인자를 넘겨주기 위한 준비 과정

<+40> : 확보한 공간 정리

 

ksys_write

<+0> : 스택 공간 확보

<+24> : 확보한 공간 정리(sp 원상복구)