스택 최상단에 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를 원상복구)
'커널' 카테고리의 다른 글
| 16. 라즈베리파이 - thread_info 구조체 초기화 코드 (0) | 2025.07.13 |
|---|---|
| 15. 라즈베리파이 - thread_info 구조체_preempt_count 필드 (0) | 2025.07.13 |
| 13. 라즈베리파이 - 아키텍처 별 thread_info 구조체 (0) | 2025.07.12 |
| 12. 라즈베리파이 - 태스크 디스크립터(2) (0) | 2025.07.12 |
| 12. 라즈베리파이 - 태스크 디스크립터(1) (0) | 2025.07.12 |