# sigreturn32.S — 말로 풀어 읽기
Linux v6.18.37 · arch/arm64/kernel/sigreturn32.S

시그널 핸들러가 끝난 뒤에는 핸들러를 호출하기 전의 프로그램 상태로 돌아가야 합니다. 일반적인 RET만으로는 중단된 레지스터와 마스크를 모두 복구할 수 없습니다. 이 작은 사용자 코드는 r7에 시스템 호출 번호를 넣고 SVC로 커널에 복구를 요청합니다.

## 처음 읽을 때
여기의 .byte는 레지스터 복원 명령이 아니라 사용자에게 제공할 명령 바이트를 만드는 줄입니다. 실제 복원은 요청을 받은 커널이 수행합니다.

## 더 깊이 살펴볼 때
ARM과 Thumb의 명령 폭, 리틀 엔디언 바이트 순서, EABI에서 r7이 맡는 역할을 함께 읽어 보세요. 원본 Thumb 주석은 바이트와 반대여서 실제 인코딩을 확인해야 합니다.

![단계별 개념 그림](../media/sigreturn32-overview.png)
화살표는 SVC 진입과 원래 실행으로의 복귀입니다. 화면 배치는 실제 메모리 주소 순서가 아닙니다.

## EABI 번호와 코드 범위
원본 1–20행

### 16행
```asm
#include <asm/unistd_compat_32.h>
```
AArch32 호환 시스템 호출 번호를 가져옵니다. 뒤의 sigreturn·rt_sigreturn 기계어는 AArch64 x8 ABI가 아니라 AArch32 r7 번호를 사용하므로 호환 번호 정의가 필요합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.

### 18행
```asm
	.section .rodata
```
이후 출력할 바이트를 어느 섹션에 넣을지 바꿉니다. 빌드 도구가 코드를 분류하는 작업이며 현재 CPU의 PC나 SP를 옮기는 줄은 아닙니다. .rodata

### 19행
```asm
	.globl __aarch32_sigret_code_start
```
AArch32 시그널 복귀 명령 모음의 시작 기호를 다른 커널 코드가 찾을 수 있게 내보냅니다. 여기 있는 바이트를 사용자 복귀 트램펄린에 배치할 때 시작과 끝 기호로 범위를 계산합니다. 이 표기는 심벌을 다른 오브젝트에서도 참조할 수 있게 하며 CPU가 실행하는 명령을 추가하지 않습니다.

### 20행
```asm
__aarch32_sigret_code_start:
```
여기에 __aarch32_sigret_code_start라는 위치 이름을 붙입니다. 다른 줄의 분기나 주소 계산이 이 위치를 찾아올 수 있습니다. 이름 자체가 CPU 작업을 추가하지는 않습니다.

## sigreturn의 ARM·Thumb 바이트
원본 21–33행

### 25행
```asm
	.byte	__NR_compat32_sigreturn, 0x70, 0xa0, 0xe3	// mov	r7, #__NR_compat32_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. 리틀 엔디언 ARM 명령 MOV r7,#sigreturn을 바이트로 만듭니다. r7은 AArch32 EABI 시스템 호출 번호 레지스터이며, 뒤의 SVC가 사용자 시그널 프레임에 보관한 문맥을 커널에서 검사·복원하도록 요청하게 합니다.
ARM MOV r7,#119의 바이트입니다. 119는 syscall_32.tbl의 sigreturn 번호입니다.

### 26행
```asm
	.byte	__NR_compat32_sigreturn, 0x00, 0x00, 0xef	// svc	#__NR_compat32_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. ARM 상태의 SVC를 바이트로 만듭니다. 직전 r7의 sigreturn 번호와 함께 커널에 들어가 시그널 이전 상태를 복원합니다. 일반 함수의 LR로 단순 RET하는 동작과 다릅니다.
ARM SVC 명령입니다. EABI는 r7의 시스템 호출 번호를 사용합니다.

### 31행
```asm
	.byte	__NR_compat32_sigreturn, 0x27			// svc	#__NR_compat32_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. 0x27xx는 Thumb MOVS r7,#imm 인코딩이므로 sigreturn 번호를 r7에 넣습니다. 이 줄의 원문 주석 SVC는 다음 줄과 뒤바뀌어 있어 실제 바이트를 기준으로 해석해야 합니다.
실제 바이트는 0x2777, 즉 Thumb MOVS r7,#119입니다. 원문 svc 주석은 바이트와 반대입니다.

### 32행
```asm
	.byte	__NR_compat32_sigreturn, 0xdf			// mov	r7, #__NR_compat32_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. 0xdfxx는 Thumb SVC 인코딩입니다. 앞에서 설정한 r7의 sigreturn 번호로 커널 복귀 서비스를 요청합니다. 원문에 MOV라고 적혀 있어도 실제 명령은 SVC입니다.
실제 바이트는 0xdf77, 즉 Thumb SVC #119입니다. 원문 mov 주석은 바이트와 반대입니다.

## rt_sigreturn과 범위 끝
원본 34–47행

### 37행
```asm
	.byte	__NR_compat32_rt_sigreturn, 0x70, 0xa0, 0xe3	// mov	r7, #__NR_compat32_rt_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. ARM 상태의 MOV r7,#rt_sigreturn을 만듭니다. rt_sigreturn은 확장된 시그널 프레임·마스크를 포함한 복귀 ABI를 사용하며 일반 sigreturn과 별도 호출 번호입니다.
ARM MOV r7,#173입니다. rt_sigreturn 번호는 173입니다.

### 38행
```asm
	.byte	__NR_compat32_rt_sigreturn, 0x00, 0x00, 0xef	// svc	#__NR_compat32_rt_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. ARM SVC로 rt_sigreturn을 요청합니다. 커널이 사용자 프레임의 레지스터·시그널 상태를 검사하고 복원하는 경로로 들어갑니다.

### 43행
```asm
	.byte	__NR_compat32_rt_sigreturn, 0x27		// svc	#__NR_compat32_rt_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. Thumb MOVS r7,#rt_sigreturn의 바이트입니다. 0x27xx 인코딩과 호출 번호를 기준으로 해석하며 이 줄의 SVC 주석은 맞지 않습니다.
실제 바이트는 0x27ad, 즉 Thumb MOVS r7,#173입니다.

### 44행
```asm
	.byte	__NR_compat32_rt_sigreturn, 0xdf		// mov	r7, #__NR_compat32_rt_sigreturn
```
이 .byte 자체는 CPU 명령이 아니라, 어셈블 단계에서 각 값을 1바이트씩 내보내는 지시문입니다. 이 파일에서는 그 바이트열이 명령어 인코딩이며, 시그널 복귀 시 CPU가 이를 AArch32 명령으로 실행합니다. Thumb SVC의 0xdfxx 인코딩입니다. rt_sigreturn 복귀 서비스를 요청하고, 원래 응용 프로그램의 PC·SP 등은 커널 복원 경로에서 결정됩니다.
실제 바이트는 0xdfad, 즉 Thumb SVC #173입니다.

### 46행
```asm
        .globl __aarch32_sigret_code_end
```
__aarch32_sigret_code_end를 다른 오브젝트에서도 찾을 수 있는 이름으로 공개합니다. 이름을 공개하는 것만으로 함수가 실행되지는 않습니다.

### 47행
```asm
__aarch32_sigret_code_end:
```
여기에 __aarch32_sigret_code_end라는 위치 이름을 붙입니다. 다른 줄의 분기나 주소 계산이 이 위치를 찾아올 수 있습니다. 이름 자체가 CPU 작업을 추가하지는 않습니다.

## 설명한 뒤 함께 생각해 볼 질문

### SVC 즉시값만 보면 syscall 번호를 알 수 있나요?
이 코드가 사용하는 EABI에서 커널은 r7의 시스템 호출 번호를 사용합니다.

### Thumb의 0x27xx는 어떤 명령인가요?
MOVS r7,#imm8입니다. 0xdfxx는 SVC입니다. 이 파일의 해당 주석 순서는 뒤바뀌어 있습니다.

### 이 파일이 사용자 레지스터를 모두 복원하나요?
아닙니다. sigreturn 요청을 보내고 커널의 시그널 복귀 처리가 프레임을 해석해 복원합니다.
