역할과 입력
- x0: EFI 함수 주소 / x1: 오류 처리에 쓸 값
- x2–x6: EFI 함수에 전달할 최대 다섯 인자
원본 .S · 빌드 조건: Makefile · 명령·주소 표기 읽는 법
87줄 · SHA-256: fab9fb3a9d328033e53a1115d4e07866535ee3b10b4eab91f6da7e64d66e394e
구조와 흐름
EFI 호출 전후의 두 스택
두 스택의 연결
커널 스택에 112바이트를 확보합니다. [SP+16]에 x1, [SP+24]에 x18, +32부터 x19–x28을 저장합니다. x29는 이 프레임을 가리킵니다. EFI 스택 맨 위의 16바이트에는 x18과 x29를 기록하여 예외 처리에서도 원래 스택을 찾을 수 있게 합니다.
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2018 Linaro Ltd <ard.biesheuvel@linaro.org>
4 */
5
6#include <linux/linkage.h>
7#include <asm/assembler.h>
8
9SYM_FUNC_START(__efi_rt_asm_wrapper)
10 stp x29, x30, [sp, #-112]!
11 mov x29, sp
12
13 /*
14 * Register x18 is designated as the 'platform' register by the AAPCS,
15 * which means firmware running at the same exception level as the OS
16 * (such as UEFI) should never touch it.
17 */
18 stp x1, x18, [sp, #16]
19
20 /*
21 * Preserve all callee saved registers and preserve the stack pointer
22 * value at the base of the EFI runtime stack so we can recover from
23 * synchronous exceptions occurring while executing the firmware
24 * routines.
25 */
26 stp x19, x20, [sp, #32]
27 stp x21, x22, [sp, #48]
28 stp x23, x24, [sp, #64]
29 stp x25, x26, [sp, #80]
30 stp x27, x28, [sp, #96]
31
32 ldr_l x16, efi_rt_stack_top
33 mov sp, x16
34 stp x18, x29, [sp, #-16]!
35
- L6
- C 호출용 EFI 래퍼와 예외 복구 코드의 시작·끝을 선언할 linkage 매크로를 가져옵니다. 두 경로의 진입 방식이 달라 FUNC와 CODE 선언을 구분합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
- L7
- 전역 변수 값을 PC 상대 방식으로 읽는 ldr_l 등 ARM64 공통 매크로를 가져옵니다. 이 파일은 EFI 스택 상단 변수의 값을 찾을 때 이를 사용합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
- L9
- 커널에서 UEFI 런타임 서비스를 호출할 때 스택과 보존 레지스터를 관리하는 진입점입니다. x0는 펌웨어 함수 주소, x1은 오류 메시지에 쓸 함수 이름이며 x2~x6이 실제 서비스 인자입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
- L10
- 112바이트의 커널 스택 프레임을 만들고 x29·LR을 저장합니다. 나머지 공간에는 함수 이름, x18, x19~x28을 보관하여 펌웨어 예외가 발생해도 커널 호출자로 복귀할 수 있게 합니다. 메모리에서는 sp + (-112) 위치가 첫 레지스터 x29에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x30에 대응합니다. 대괄호 뒤의 !는 주소 갱신을 뜻합니다. sp에 오프셋 -112을 더한 주소로 접근하고 그 주소를 sp에도 남깁니다.
- L11
- 새 커널 스택 프레임 주소를 x29에 남깁니다. 잠시 EFI 전용 스택으로 바꿨다가 돌아올 때 이 값으로 원래 스택을 찾습니다. x29에 담기는 것은 SP의 주소값이며, SP와 스택 메모리의 내용은 그대로입니다.
- L18
- 오류를 알릴 때 사용할 함수 이름 x1과 호출 전 x18을 보관합니다. x18은 플랫폼 전용 레지스터이므로 펌웨어가 바꾸면 안 되며, 호출 뒤 비교할 기준이 됩니다. 메모리에서는 sp + (16) 위치가 첫 레지스터 x1에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x18에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L26
- 커널의 x19·x20를 저장 프레임 +32에 보관합니다. 정상적인 펌웨어는 이를 보존하지만, 실행 도중 예외가 나면 정상 복귀 절차를 건너뛰므로 별도 복구 경로가 이 저장본을 사용합니다. 메모리에서는 sp + (32) 위치가 첫 레지스터 x19에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x20에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L27
- 커널의 x21·x22를 저장 프레임 +48에 보관합니다. 정상적인 펌웨어는 이를 보존하지만, 실행 도중 예외가 나면 정상 복귀 절차를 건너뛰므로 별도 복구 경로가 이 저장본을 사용합니다. 메모리에서는 sp + (48) 위치가 첫 레지스터 x21에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x22에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L28
- 커널의 x23·x24를 저장 프레임 +64에 보관합니다. 정상적인 펌웨어는 이를 보존하지만, 실행 도중 예외가 나면 정상 복귀 절차를 건너뛰므로 별도 복구 경로가 이 저장본을 사용합니다. 메모리에서는 sp + (64) 위치가 첫 레지스터 x23에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x24에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L29
- 커널의 x25·x26를 저장 프레임 +80에 보관합니다. 정상적인 펌웨어는 이를 보존하지만, 실행 도중 예외가 나면 정상 복귀 절차를 건너뛰므로 별도 복구 경로가 이 저장본을 사용합니다. 메모리에서는 sp + (80) 위치가 첫 레지스터 x25에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x26에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L30
- 커널의 x27·x28를 저장 프레임 +96에 보관합니다. 정상적인 펌웨어는 이를 보존하지만, 실행 도중 예외가 나면 정상 복귀 절차를 건너뛰므로 별도 복구 경로가 이 저장본을 사용합니다. 메모리에서는 sp + (96) 위치가 첫 레지스터 x27에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x28에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L32
- 부팅 때 할당한 EFI 런타임 전용 스택의 최상단 주소를 읽습니다. 펌웨어의 스택 사용을 현재 태스크의 일반 커널 스택에서 분리합니다. ldr_l은 ADRP로 심벌이 속한 페이지를 구한 뒤 LDR로 그 위치의 값을 읽는 매크로입니다. 주소를 구하는 adr_l과 달리 실제 메모리 접근이 있습니다.
- L33
- SP를 EFI 전용 스택으로 바꿉니다. 이후 펌웨어 함수와 그 내부 호출은 이 공간에 프레임을 만듭니다. 바뀌는 것은 SP가 담은 주소입니다. 원래 스택의 데이터가 새 주소로 복사되는 것은 아닙니다.
- L34
- EFI 스택 상단에 원래 x18과 커널 프레임 주소 x29를 기록합니다. 예외 처리 코드는 이 두 값을 통해 원래 태스크 스택과 shadow call stack 상태를 되찾습니다. 메모리에서는 sp + (-16) 위치가 첫 레지스터 x18에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x29에 대응합니다. 대괄호 뒤의 !는 주소 갱신을 뜻합니다. sp에 오프셋 -16을 더한 주소로 접근하고 그 주소를 sp에도 남깁니다.
정상 호출과 복귀
함수 주소는 x8에 옮기고 인자는 x0–x4로 재배치합니다. BLR 뒤에는 x29로 커널 SP를 복원하고 EFI 스택의 기록을 지웁니다. x0의 EFI 반환값은 유지합니다. 저장한 x18과 현재 x18을 비교하며 정상 경로에서는 펌웨어가 보존해야 하는 x19–x28을 다시 읽지 않습니다.
36 /*
37 * We are lucky enough that no EFI runtime services take more than
38 * 5 arguments, so all are passed in registers rather than via the
39 * stack.
40 */
41 mov x8, x0
42 mov x0, x2
43 mov x1, x3
44 mov x2, x4
45 mov x3, x5
46 mov x4, x6
47 blr x8
48
49 mov x16, sp
50 mov sp, x29
51 str xzr, [x16, #8] // clear recorded task SP value
52
53 ldp x1, x2, [sp, #16]
54 cmp x2, x18
55 ldp x29, x30, [sp], #112
56 b.ne 0f
57 ret
- L41
- 펌웨어 함수 주소를 x8에 보관합니다. 곧 x0를 첫 번째 서비스 인자로 바꿔야 하므로 분기 주소를 미리 옮겨 둡니다. MOV는 x8의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L42
- 래퍼의 x2를 펌웨어의 첫 인자 x0로 옮깁니다. 함수 포인터와 이름이라는 래퍼 전용 인자 두 개를 제외한 실제 인자를 전달합니다. MOV는 x0의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L43
- 래퍼의 x3를 펌웨어의 두 번째 인자 x1로 옮깁니다. MOV는 x1의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L44
- 래퍼의 x4를 펌웨어의 세 번째 인자 x2로 옮깁니다. MOV는 x2의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L45
- 래퍼의 x5를 펌웨어의 네 번째 인자 x3로 옮깁니다. MOV는 x3의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L46
- 래퍼의 x6를 펌웨어의 다섯 번째 인자 x4로 옮깁니다. 이 구현이 다루는 런타임 서비스는 인자가 다섯 개 이하라 추가 스택 인자 이동이 필요하지 않습니다. MOV는 x4의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
- L47
- x8의 UEFI 런타임 서비스를 EFI 전용 스택에서 호출합니다. 서비스의 efi_status_t 결과는 x0로 돌아오며, 래퍼는 이후 검사에서도 이 값을 보존합니다. BLR은 다음 명령의 주소를 LR(x30)에 기록하고 레지스터에 든 목적지로 분기합니다.
- L49
- 돌아온 EFI 스택 주소를 x16에 남깁니다. 원래 태스크 스택으로 돌아간 뒤 EFI 스택에 기록한 복구용 포인터를 지우기 위해 사용합니다. x16에 담기는 것은 SP의 주소값이며, SP와 스택 메모리의 내용은 그대로입니다.
- L50
- x29에 보관했던 커널 프레임 주소로 SP를 복원합니다. 이후 프레임 해제와 함수 이름 읽기는 원래 태스크 스택에서 수행합니다. 바뀌는 것은 SP가 담은 주소입니다. 원래 스택의 데이터가 새 주소로 복사되는 것은 아닙니다.
- L51
- EFI 스택에 남긴 태스크 SP 값을 0으로 지웁니다. 현재 태스크가 아직 EFI 펌웨어를 실행 중이라는 잘못된 판정을 막기 위한 정리입니다. 실제로 x16 + (8) 주소의 메모리 8바이트를 xzr의 값으로 씁니다. 이 주소 형식은 기준 레지스터 x16 자체를 갱신하지 않습니다.
- L53
- 원래 함수 이름을 x1에, 호출 전 x18을 x2에 읽습니다. x0에는 펌웨어 결과를 그대로 남겨 오류를 보고하더라도 반환할 수 있게 합니다. 메모리에서는 sp + (16) 위치가 첫 레지스터 x1에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x2에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L54
- 호출 전 x18과 펌웨어에서 돌아온 x18을 비교합니다. 플랫폼 레지스터 보존 규약을 어긴 펌웨어인지 확인합니다. CMP는 두 피연산자의 뺄셈 결과로 NZCV 조건 플래그만 갱신하고 원래 레지스터 값은 유지합니다.
- L55
- 호출자의 프레임 포인터·LR을 복원하고 112바이트 스택 프레임을 해제합니다. 정상 반환과 오류 보고 양쪽이 같은 호출자에게 돌아갈 준비를 합니다. 메모리에서는 sp 위치가 첫 레지스터 x29에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x30에 대응합니다. 대괄호 밖의 오프셋 112은 후위 갱신입니다. 기존 sp 주소로 접근한 뒤 sp에 이 값을 더합니다.
- L56
- x18이 바뀌었다면 복원·오류 보고 경로로 갑니다. 같으면 바로 펌웨어 결과 x0를 반환합니다. 앞서 계산한 NZCV 중 Z=0 조건으로 분기합니다. 이 줄은 두 값을 새로 비교하지 않으며 조건이 맞지 않으면 다음 명령으로 진행합니다.
- L57
- 펌웨어의 반환 상태 x0를 바꾸지 않고 커널 호출자에게 돌려줍니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
x18이 바뀐 경우
SHADOW_CALL_STACK 설정에서는 x18이 별도 반환 주소 스택을 가리킵니다. EFI 스택에 저장한 원래 값을 복구한 뒤 efi_handle_corrupted_x18로 tail call합니다. 이 B 명령은 LR을 바꾸지 않습니다.
580:
59 /*
60 * With CONFIG_SHADOW_CALL_STACK, the kernel uses x18 to store a
61 * shadow stack pointer, which we need to restore before returning to
62 * potentially instrumented code. This is safe because the wrapper is
63 * called with preemption disabled and a separate shadow stack is used
64 * for interrupts.
65 */
66#ifdef CONFIG_SHADOW_CALL_STACK
67 ldr_l x18, efi_rt_stack_top
68 ldr x18, [x18, #-16]
69#endif
70
71 b efi_handle_corrupted_x18 // tail call
72SYM_FUNC_END(__efi_rt_asm_wrapper)
- L58
- 펌웨어가 x18을 손상시킨 경우 들어오는 오류 보고 경로의 시작입니다. shadow call stack을 사용하는 빌드는 먼저 x18을 복구합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
- L66
- Shadow Call Stack은 함수의 복귀 주소를 일반 스택과 별도 공간에도 보관하여 덮어쓰기 공격에 대비하는 기능입니다. ARM64에서는 x18이 그 별도 스택의 포인터이므로, 이 설정이 켜졌다면 C 오류 보고 코드로 가기 전에 손상된 x18부터 복구해야 합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
- L67
- x18이 손상된 경로에서 EFI 전용 스택 상단 주소를 다시 읽습니다. 기존 x18 값은 믿을 수 없으므로 저장본을 찾을 주소부터 새로 구합니다. ldr_l은 ADRP로 심벌이 속한 페이지를 구한 뒤 LDR로 그 위치의 값을 읽는 매크로입니다. 주소를 구하는 adr_l과 달리 실제 메모리 접근이 있습니다.
- L68
- EFI 스택 상단의 16바이트 아래에 저장한 원래 x18을 되찾습니다. 이후 계측된 C 함수가 올바른 shadow call stack에 복귀 주소를 기록하도록 합니다.
- L69
- Shadow Call Stack용 포인터 복구는 여기까지입니다. 설정과 관계없이 x18 보존 규약 위반에 대한 오류 보고는 이어서 수행합니다.
- L71
- x0의 펌웨어 상태와 x1의 함수 이름으로 efi_handle_corrupted_x18을 꼬리 호출합니다. 이 함수는 펌웨어가 x18을 손상시켰다는 메시지를 남기고 원래 상태값을 그대로 반환합니다. B를 사용하므로 래퍼로 재복귀하지 않습니다. 이 분기는 LR에 새 복귀 주소를 기록하지 않습니다.
- L72
- (__efi_rt_asm_wrapper)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
동기 예외 복구
efi.c의 efi_runtime_fixup_exception은 저장된 레지스터의 x0를 EFI_ABORTED, x30을 커널 프레임 주소, PC를 __efi_rt_asm_recover로 바꿉니다. 여기서 x30은 복귀 코드 주소가 아니라 SP 복구용 주소입니다. x19–x28과 FP/LR을 읽고 원래 호출자에게 반환합니다.
73
74SYM_CODE_START(__efi_rt_asm_recover)
75 mov sp, x30
76
77 ldr_l x16, efi_rt_stack_top // clear recorded task SP value
78 str xzr, [x16, #-8]
79
80 ldp x19, x20, [sp, #32]
81 ldp x21, x22, [sp, #48]
82 ldp x23, x24, [sp, #64]
83 ldp x25, x26, [sp, #80]
84 ldp x27, x28, [sp, #96]
85 ldp x29, x30, [sp], #112
86 ret
87SYM_CODE_END(__efi_rt_asm_recover)
- L74
- 펌웨어 실행 중 동기 예외를 커널이 복구하기로 결정했을 때 들어오는 별도 경로입니다. efi_runtime_fixup_exception이 PC를 여기로 바꾸고 x0에 EFI_ABORTED, x30에 저장된 태스크 SP를 마련합니다. 이 매크로는 정렬된 코드 시작 심벌을 정의하고 다른 오브젝트에서도 참조할 수 있게 합니다.
- L75
- 여기서 x30은 보통의 복귀 주소가 아니라 예외 처리 코드가 넣어 준 태스크 스택 프레임 주소입니다. 이를 SP에 넣어 펌웨어 스택을 벗어납니다. 바뀌는 것은 SP가 담은 주소입니다. 원래 스택의 데이터가 새 주소로 복사되는 것은 아닙니다.
- L77
- EFI 런타임 스택 상단을 다시 찾아, 이제 펌웨어 실행을 벗어났다는 표시를 정리할 준비를 합니다. ldr_l은 ADRP로 심벌이 속한 페이지를 구한 뒤 LDR로 그 위치의 값을 읽는 매크로입니다. 주소를 구하는 adr_l과 달리 실제 메모리 접근이 있습니다.
- L78
- EFI 스택 끝의 복구용 태스크 SP 기록을 0으로 지웁니다. 정상 반환 경로와 동일하게 EFI 실행 중 상태를 해제합니다. 실제로 x16 + (-8) 주소의 메모리 8바이트를 xzr의 값으로 씁니다. 이 주소 형식은 기준 레지스터 x16 자체를 갱신하지 않습니다.
- L80
- 정상적인 펌웨어 복귀를 거치지 못한 경로이므로, 호출 전에 프레임 +32에 보관한 x19·x20를 직접 되살립니다. 커널 호출자가 기대하는 callee-saved 상태를 복원하는 단계입니다. 메모리에서는 sp + (32) 위치가 첫 레지스터 x19에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x20에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L81
- 정상적인 펌웨어 복귀를 거치지 못한 경로이므로, 호출 전에 프레임 +48에 보관한 x21·x22를 직접 되살립니다. 커널 호출자가 기대하는 callee-saved 상태를 복원하는 단계입니다. 메모리에서는 sp + (48) 위치가 첫 레지스터 x21에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x22에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L82
- 정상적인 펌웨어 복귀를 거치지 못한 경로이므로, 호출 전에 프레임 +64에 보관한 x23·x24를 직접 되살립니다. 커널 호출자가 기대하는 callee-saved 상태를 복원하는 단계입니다. 메모리에서는 sp + (64) 위치가 첫 레지스터 x23에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x24에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L83
- 정상적인 펌웨어 복귀를 거치지 못한 경로이므로, 호출 전에 프레임 +80에 보관한 x25·x26를 직접 되살립니다. 커널 호출자가 기대하는 callee-saved 상태를 복원하는 단계입니다. 메모리에서는 sp + (80) 위치가 첫 레지스터 x25에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x26에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L84
- 정상적인 펌웨어 복귀를 거치지 못한 경로이므로, 호출 전에 프레임 +96에 보관한 x27·x28를 직접 되살립니다. 커널 호출자가 기대하는 callee-saved 상태를 복원하는 단계입니다. 메모리에서는 sp + (96) 위치가 첫 레지스터 x27에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x28에 대응합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
- L85
- 예외 전 커널 호출자의 프레임 포인터와 LR을 복원하고 전체 저장 프레임을 해제합니다. EFI 내부의 복귀 주소로 돌아가는 것이 아닙니다. 메모리에서는 sp 위치가 첫 레지스터 x29에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x30에 대응합니다. 대괄호 밖의 오프셋 112은 후위 갱신입니다. 기존 sp 주소로 접근한 뒤 sp에 이 값을 더합니다.
- L86
- 예외 처리 코드가 준비한 EFI_ABORTED를 x0에 둔 채 원래 커널 호출자로 돌아갑니다. 커널의 C 예외 처리 쪽에서는 이후 EFI 런타임 서비스 사용도 비활성화합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
- L87
- (__efi_rt_asm_recover)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
매크로 정의와 확장
각 정의는 v6.18.37 원문입니다. 역슬래시 인자는 사용 위치의 값으로 치환되며, 안쪽 매크로와 조건부 블록은 이후 단계에서 다시 처리됩니다.
SYM_CODE_END
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
include/linux/linkage.h L305–L306
#define SYM_CODE_END(name) \
SYM_END(name, SYM_T_NONE)SYM_CODE_START
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
include/linux/linkage.h L278–L279
#define SYM_CODE_START(name) \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)SYM_FUNC_END
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
include/linux/linkage.h L248–L249
#define SYM_FUNC_END(name) \
SYM_END(name, SYM_T_FUNC)SYM_FUNC_START
아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.
arch/arm64/include/asm/linkage.h L18–L20
#define SYM_FUNC_START(name) \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \
bti c ;include/linux/linkage.h L209–L210
#define SYM_FUNC_START(name) \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)상수·구조체 오프셋
S_*·THREAD_*·FREGS_* 등의 구조체 오프셋은 빌드한 C 구조체 배치에서 생성됩니다. 숫자를 고정하지 않고 원래 기호를 사용했습니다.