유저 스페이스에서 커널 스페이스로 전환하려면 시스템 콜을 호출해야 한다 것은 마르고 닳도록 들었죠?
이번에는 ARM64 Architecture에서 EL0 ->EL1로 변환될 시, Stack을 어떻게 Push하는 지 살펴볼께요.
"rild"란 프로세스의 콜스택을 예를 들어 볼 께요. 잘 보면, 유저 공간에서 sendto란 시스템 콜을 호출했다는 걸 알 수 있네요.
-000|do_mem_abort()
-001|el1_da(asm)
-->|exception
-002|ch_pop_remote_rx_intent()
-003|glink_tx_common()
-004|glink_txv()
-005|ipc_router_glink_xprt_write()
-006|msm_ipc_router_write_pkt(inline)
-006|msm_ipc_router_send_to()
-007|msm_ipc_router_sendmsg()
-008|sock_sendmsg_nosec(inline)
-008|sock_sendmsg()
-009|SYSC_sendto(inline)
-009|sys_sendto()
-010|el0_svc_naked(asm)
.
아래는 "rild"란 프로세스의 task descriptor(주소: 0xFFFFFFE577E1A400) 인데요. stack란 멤버가 0xFFFFFFE4DE6A4000을 가르키고 있는데요, 이 주소는 스택의 Top Address를 가르켜요.
(struct task_struct*)0xFFFFFFE577E1A400 = 0xFFFFFFE577E1A400 -> (
state = 0x0,
stack = 0xFFFFFFE4DE6A4000,
usage = (counter = 0x2),
// .. 생략..
comm = "rild",
nameidata = 0x0,
.
리눅스 커널에서 스택은 Bottom Address(높은 주소) 에서 Top Address(낮은 주소로) 자란다는 사실은 다 아실 꺼에요. ARM64(Aarch64) 아키텍처에서는 커널 공간의 프로세스 스택 주소는 0x4000바이트로 이거든요. 그럼 rild"란 프로세스는 (0xFFFFFFE4DE6A4000+0x4000) 에서 0xFFFFFFE4DE6A4000 주소로 스택이 자라난다는 사실을 알 수 있어요. 스택이 자라난다는 소리가 뭐냐구요? 스택 공간에는 로컬 변수를 할당 받아 쓰고 가장 중요한 함수가 호출될 때 돌아갈 주소(Linked Register)와 돌아갈 주소가 있는 주소(Frame Pointer 주소)를 스택에 저장하거든요. 스택에 어떤 값을 푸쉬하면 자연히 스택 주소가 점점 작아져요. 이걸 스택이 자란다고 할 수 있죠. 높은 주소에서 낮은 주소로요.
만약 A -> B -> C 순서로 함수가 호출되었으면 아래와 같은 심볼 정보 확인을 할 수 있어요. 아래는 정말 쉽게 설명한 도식인데. 나중에 ARM64 아키텍쳐의 Calling Convention은 자세히 다룰 예정이에요.
0xFFFFFFE4DE6A4000 //<<-- 낮은 주소(stack top 주소)
// 생략
0xFFFFFFE4DE6A7FA0 D
0xFFFFFFE4DE6A7FA8
0xFFFFFFE4DE6A7FB0
0xFFFFFFE4DE6A7FB8 C
0xFFFFFFE4DE6A7FC0
0xFFFFFFE4DE6A7FC8
0xFFFFFFE4DE6A7FD0 B
0xFFFFFFE4DE6A7FD8
0xFFFFFFE4DE6A7FE0
0xFFFFFFE4DE6A7FE8
0xFFFFFFE4DE6A7FF0 A
0xFFFFFFE4DE6A7FF8
0xFFFFFFE4DE6A8000 //<<-- 높은 주소(stack bottom 주소)
.
그럼 스택 bottom 주소 0xFFFFFFE4DE6A8000로 가볼까요? 잘 보면 유저 공간에서 구동 중인 레지스터가 스택에 Push된 걸 알 수 있어요.
_____________address|_data____________________|value_____________|symbol
NUD:FFFFFFE4DE6A7E60| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7E68| 30 31 68 99 9F FF FF FF 0xFFFFFF9F99683130 \\vmlinux\Global\el0_svc_naked+0x24
NUD:FFFFFFE4DE6A7E70| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7E78| 28 DF FD AF 7B 00 00 00 0x7BAFFDDF28
NUD:FFFFFFE4DE6A7E80| FF FF FF FF FF FF FF FF 0xFFFFFFFFFFFFFFFF
NUD:FFFFFFE4DE6A7E88| 30 31 68 99 9F FF FF FF 0xFFFFFF9F99683130 \\vmlinux\Global\el0_svc_naked+0x24
NUD:FFFFFFE4DE6A7E90| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7E98| 08 00 00 00 00 00 00 00 0x8
NUD:FFFFFFE4DE6A7EA0| FF FF FF FF FF FF FF FF 0xFFFFFFFFFFFFFFFF
NUD:FFFFFFE4DE6A7EA8| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7EB0| 00 00 00 A0 00 00 00 00 0xA0000000
NUD:FFFFFFE4DE6A7EB8| 3C 6B 77 2B 46 76 A8 C2 0xC2A876462B776B3C
NUD:FFFFFFE4DE6A7EC0| 45 00 00 00 00 00 00 00 0x45 // x0
NUD:FFFFFFE4DE6A7EC8| 80 37 81 AF 7B 00 00 00 0x7BAF813780 // x1
NUD:FFFFFFE4DE6A7ED0| 16 00 00 00 00 00 00 00 0x16 // x2
NUD:FFFFFFE4DE6A7ED8| 40 00 00 00 00 00 00 00 0x40 // x3
NUD:FFFFFFE4DE6A7EE0| 20 DD FD AF 7B 00 00 00 0x7BAFFDDD20 // x4
NUD:FFFFFFE4DE6A7EE8| 14 00 00 00 00 00 00 00 0x14 // x5
NUD:FFFFFFE4DE6A7EF0| C8 DC FD AF 7B 00 00 00 0x7BAFFDDCC8 // x6
NUD:FFFFFFE4DE6A7EF8| 01 00 00 00 00 00 00 00 0x1 // x7
NUD:FFFFFFE4DE6A7F00| CE 00 00 00 00 00 00 00 0xCE // x8
NUD:FFFFFFE4DE6A7F08| 02 00 00 00 00 00 00 00 0x2 // x9
NUD:FFFFFFE4DE6A7F10| 00 00 00 00 00 00 00 00 0x0 // x10
NUD:FFFFFFE4DE6A7F18| 00 00 00 00 00 00 00 00 0x0 // x11
NUD:FFFFFFE4DE6A7F20| B9 E6 3B AF 7B 00 00 00 0x7BAF3BE6B9 // x12
NUD:FFFFFFE4DE6A7F28| 40 01 00 00 00 00 00 00 0x140 // x13
NUD:FFFFFFE4DE6A7F30| 0D 00 00 00 00 00 00 00 0x0D // x14
NUD:FFFFFFE4DE6A7F38| AB AA AA AA AA AA AA AA 0xAAAAAAAAAAAAAAAB // x15
NUD:FFFFFFE4DE6A7F40| 98 CF E2 B1 7B 00 00 00 0x7BB1E2CF98 // x16
NUD:FFFFFFE4DE6A7F48| 14 B3 AB B2 7B 00 00 00 0x7BB2ABB314 // x17
NUD:FFFFFFE4DE6A7F50| D6 00 00 00 00 00 00 00 0xD6 // x18
NUD:FFFFFFE4DE6A7F58| 78 DD FD AF 7B 00 00 00 0x7BAFFDDD78 // x19
NUD:FFFFFFE4DE6A7F60| C0 72 81 AF 7B 00 00 00 0x7BAF8172C0 // x20
NUD:FFFFFFE4DE6A7F68| 16 00 00 00 00 00 00 00 0x16 // x21
NUD:FFFFFFE4DE6A7F70| 28 8D E2 B1 7B 00 00 00 0x7BB1E28D28 // x22
NUD:FFFFFFE4DE6A7F78| C0 83 84 AF 7B 00 00 00 0x7BAF8483C0 // x23
NUD:FFFFFFE4DE6A7F80| 70 83 84 AF 7B 00 00 00 0x7BAF848370 // x24
NUD:FFFFFFE4DE6A7F88| B8 83 84 AF 7B 00 00 00 0x7BAF8483B8 // x25
NUD:FFFFFFE4DE6A7F90| 80 D7 80 AF 7B 00 00 00 0x7BAF80D780 // x26
NUD:FFFFFFE4DE6A7F98| 10 B0 90 B1 7B 00 00 00 0x7BB190B010 // x27
NUD:FFFFFFE4DE6A7FA0| 17 4A A6 B1 7B 00 00 00 0x7BB1A64A17 // x28
NUD:FFFFFFE4DE6A7FA8| 10 DD FD AF 7B 00 00 00 0x7BAFFDDD10 // x29
NUD:FFFFFFE4DE6A7FB0| 30 B3 AB B2 7B 00 00 00 0x7BB2ABB330 // x30
NUD:FFFFFFE4DE6A7FB8| 10 DD FD AF 7B 00 00 00 0x7BAFFDDD10 // sp
NUD:FFFFFFE4DE6A7FC0| C4 B7 AF B2 7B 00 00 00 0x7BB2AFB7C4 // pc
NUD:FFFFFFE4DE6A7FC8| 00 00 00 60 00 00 00 00 0x60000000 // cprs
NUD:FFFFFFE4DE6A7FD0| 45 00 00 00 00 00 00 00 0x45
NUD:FFFFFFE4DE6A7FD8| CE 00 00 00 00 00 00 00 0xCE
NUD:FFFFFFE4DE6A7FE0| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7FE8| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A7FF0| C8 C3 39 00 EA 71 00 00 0x71EA0039C3C8
NUD:FFFFFFE4DE6A7FF8| 13 00 00 00 00 00 00 00 0x13
NUD:FFFFFFE4DE6A8000| 00 00 00 00 00 00 00 00 0x0
NUD:FFFFFFE4DE6A8008| 00 00 00 00 00 00 00 00 0x0
여기서 아주 주의 깊게 쳐야 볼 레지스터는 X8인데요. 0xCE란 값을 가르키고 있네요. 이게 뭐냐면 시스템 콜 번호이거든요. 시스템 콜 번호는 CrashTool로 확인이 가능해요. 자 확인해 볼까요? sys_sendto란 시스템 콜의 번호는 0xce임을 알 수 있어요.
crash64> sys -c
NUM SYSTEM CALL FILE AND LINE NUMBER
0 sys_io_setup ../kernel/fs/aio.c: 1257
// .. 생략
cd sys_getpeername ../kernel/net/socket.c: 1794
ce sys_sendto ../kernel/net/socket.c: 1826
cf sys_recvfrom ../kernel/net/socket.c: 1889
Reference: ARM 프로세서의 주요 기능
ARM 프로세서는 왜 배워야 할까
ARM 프로세서 학습하는 방법의 문제점
ARM 프로세서 소개
ARM 아키텍처를 구성하는 주요 기능
● 어셈블리 명령어란
● ARM의 동작 모드와 익셉션 레벨
Written by <디버깅을 통해 배우는 리눅스 커널의 구조와 원리> 저자
# Reference (ARM Processor)
'시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 카테고리의 다른 글
ARM64 - ttrb0 Special Register 설정 건 (0) | 2023.06.09 |
---|---|
ARM64(Aarch64) - 함수 호출시 Stack Push(스택 푸쉬) 규약 (0) | 2023.06.09 |
ARM64(Aarch64) - Special Register 설정(Trace32) (0) | 2023.06.09 |
ARM32- 스택 푸쉬(Stack Push) Userspace -> Kernel Space (0) | 2023.06.09 |
[Linux][ARM] char buf[32]; vs char buf[32]={0}; (0) | 2023.06.09 |