DUJINLABS.COM

Linux v6.18.37 · ARM64

vmlinux.lds.S — 커널의 코드·데이터·초기 테이블 배치

이 파일은 C 전처리를 거쳐 링커가 읽는 스크립트입니다. 점(.)은 CPU의 PC나 SP가 아니라 현재 출력 위치를 뜻합니다. 아래 배치 그림의 화살표는 링크 주소가 증가하는 방향이며 실행 순서가 아닙니다.

역할과 입력

  • 입력: 각 오브젝트의 .text·.data·.bss 등 섹션
  • 배치 기준: KIMAGE_VADDR, PAGE_SIZE, SEGMENT_ALIGN과 CONFIG

원본 .S · 빌드 조건: Makefile · 명령·주소 표기 읽는 법

411줄 · SHA-256: 12b92c8409731f26a750744c8c50bcebd81841f6b7aa7ff408fe32f466788a9b

구조와 흐름

커널의 코드·데이터·초기 테이블 배치
화살표: 파일·링크 배치 순서입니다. CPU 실행 순서가 아닙니다. 칸 크기는 실제 바이트 비율과 다릅니다.

KVM 섹션과 공통 링커 매크로

CONFIG_KVM이면 hyp의 읽기 전용·데이터·per-CPU·재배치 섹션과 BSS 시작 부분을 정의합니다. SBSS_ALIGN은 호스트와 hyp BSS 시작을 맞추기 위한 값입니다. asm-generic/vmlinux.lds.h의 매크로가 공통 섹션 수집 규칙을 제공합니다.

vmlinux.lds.S · L1–L79
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * ld script to make ARM Linux kernel
4 * taken from the i386 version by Russell King
5 * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
6 */
7
8#include <asm/hyp_image.h>
9#ifdef CONFIG_KVM
10#define HYPERVISOR_EXTABLE					\
11	. = ALIGN(SZ_8);					\
12	__start___kvm_ex_table = .;				\
13	*(__kvm_ex_table)					\
14	__stop___kvm_ex_table = .;
15
16#define HYPERVISOR_RODATA_SECTIONS				\
17	HYP_SECTION_NAME(.rodata) : {				\
18		. = ALIGN(PAGE_SIZE);				\
19		__hyp_rodata_start = .;				\
20		*(HYP_SECTION_NAME(.data..ro_after_init))	\
21		*(HYP_SECTION_NAME(.rodata))			\
22		. = ALIGN(PAGE_SIZE);				\
23		__hyp_rodata_end = .;				\
24	}
25
26#define HYPERVISOR_DATA_SECTION					\
27	HYP_SECTION_NAME(.data) : {				\
28		. = ALIGN(PAGE_SIZE);				\
29		__hyp_data_start = .;				\
30		*(HYP_SECTION_NAME(.data))			\
31		. = ALIGN(PAGE_SIZE);				\
32		__hyp_data_end = .;				\
33	}
34
35#define HYPERVISOR_PERCPU_SECTION				\
36	. = ALIGN(PAGE_SIZE);					\
37	HYP_SECTION_NAME(.data..percpu) : {			\
38		*(HYP_SECTION_NAME(.data..percpu))		\
39	}
40
41#define HYPERVISOR_RELOC_SECTION				\
42	.hyp.reloc : ALIGN(4) {					\
43		__hyp_reloc_begin = .;				\
44		*(.hyp.reloc)					\
45		__hyp_reloc_end = .;				\
46	}
47
48#define BSS_FIRST_SECTIONS					\
49	__hyp_bss_start = .;					\
50	*(HYP_SECTION_NAME(.bss))				\
51	. = ALIGN(PAGE_SIZE);					\
52	__hyp_bss_end = .;
53
54/*
55 * We require that __hyp_bss_start and __bss_start are aligned, and enforce it
56 * with an assertion. But the BSS_SECTION macro places an empty .sbss section
57 * between them, which can in some cases cause the linker to misalign them. To
58 * work around the issue, force a page alignment for __bss_start.
59 */
60#define SBSS_ALIGN			PAGE_SIZE
61#else /* CONFIG_KVM */
62#define HYPERVISOR_EXTABLE
63#define HYPERVISOR_RODATA_SECTIONS
64#define HYPERVISOR_DATA_SECTION
65#define HYPERVISOR_PERCPU_SECTION
66#define HYPERVISOR_RELOC_SECTION
67#define SBSS_ALIGN			0
68#endif
69
70#define RO_EXCEPTION_TABLE_ALIGN	4
71#define RUNTIME_DISCARD_EXIT
72
73#include <asm-generic/vmlinux.lds.h>
74#include <asm/cache.h>
75#include <asm/kernel-pgtable.h>
76#include <asm/kexec.h>
77#include <asm/memory.h>
78#include <asm/page.h>
79
L8
KVM nVHE 코드의 섹션 이름에 .hyp 접두사를 붙이는 HYP_SECTION_NAME 등을 가져옵니다. 호스트 커널과 별도 주소 공간에서 실행할 하이퍼바이저의 코드·데이터를 구분하기 위한 정의입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L9
KVM은 Linux에서 가상 머신을 실행하는 기능입니다. 켜진 빌드는 nVHE 하이퍼바이저용 예외 복구 표와 읽기 전용·쓰기 가능·CPU별 데이터 및 재배치 정보를 각각 수집합니다. 꺼지면 아래 #else에서 이 배치 매크로들을 비웁니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L10
EL2의 KVM 코드에서 복구 가능한 예외가 발생했을 때 사용할 예외 표를 모으는 배치 규칙입니다. 표 항목의 시작·끝을 기호로 제공하여 런타임에서 해당 범위를 찾을 수 있게 합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L11
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SZ_8); \
L12
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __start___kvm_ex_table = .; \
L13
KVM 코드가 __kvm_ex_table에 기록한 예외 위치와 복구 위치 정보를 모읍니다. 일반 명령 본문을 모으는 곳이 아니라 예외 처리기가 참조할 표입니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L14
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __stop___kvm_ex_table = .;
L16
nVHE 하이퍼바이저의 상수와 초기화 후 읽기 전용으로 둘 데이터를 페이지 경계로 묶는 배치 규칙입니다. 호스트의 일반 .rodata와 따로 관리할 범위를 제공합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L17
HYP_SECTION_NAME(.rodata)는 .hyp.rodata로 펼쳐집니다. nVHE 하이퍼바이저가 사용할 읽기 전용 자료를 이 출력 섹션에 넣습니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L18
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L19
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_rodata_start = .; \
L20
nVHE 코드의 초기화 뒤 수정하지 않을 .hyp.data..ro_after_init 데이터를 모읍니다. 처음부터 상수인 아래 .hyp.rodata와 같은 보호 범위로 묶되, 이 링커 문장 자체가 페이지 권한을 바꾸지는 않습니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L21
nVHE 코드의 상수 데이터를 .hyp.rodata에 모읍니다. 앞뒤 페이지 정렬은 뒤의 메모리 매핑 코드가 다른 종류의 데이터와 분리해 권한을 적용할 수 있도록 합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L22
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L23
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_rodata_end = .; \
L24
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L26
nVHE 하이퍼바이저가 실행 중 수정할 데이터의 배치 규칙입니다. 읽기 전용 범위와 별도로 페이지 단위의 시작·끝을 잡습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L27
nVHE의 쓰기 가능한 .hyp.data 출력 섹션을 시작합니다. 이 영역은 위의 .hyp.rodata와 다른 권한으로 매핑할 수 있어야 합니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L28
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L29
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_data_start = .; \
L30
초기값이 있는 nVHE 전역 변수를 .hyp.data로 모읍니다. 0으로 초기화할 변수는 뒤의 .hyp.bss 범위에 놓습니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L31
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L32
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_data_end = .; \
L33
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L35
하이퍼바이저의 CPU별 변수 원본을 별도 영역에 모으는 규칙입니다. 각 CPU가 자기 상태를 독립적으로 갖도록 하는 percpu 영역이며 일반 전역 데이터와 구분합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L36
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L37
nVHE 코드의 CPU별 데이터 원본을 .hyp.data..percpu 출력 섹션에 모읍니다. 여기서 CPU 수만큼 실제 복사본을 만드는 것은 아닙니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L38
여러 nVHE 오브젝트에 흩어진 percpu 변수들을 한 원본 범위로 연결합니다. CPU별 영역의 배치·초기화에서 이 원본을 사용합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L39
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L41
nVHE 코드가 별도 주소 공간에 놓일 때 주소를 보정할 위치들의 목록을 모읍니다. 일반 커널의 .rela.dyn 재배치와 구분된 hyp 전용 목록입니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L42
.hyp.reloc 항목을 4바이트 경계에 배치합니다. 각 항목은 nVHE 주소 보정에 사용할 기록이며 이 섹션을 실행하는 것은 아닙니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L43
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_reloc_begin = .; \
L44
nVHE 빌드에서 생성한 .hyp.reloc 기록을 모읍니다. __hyp_reloc_begin과 __hyp_reloc_end 사이를 순회하여 하이퍼바이저 주소 보정 대상을 찾을 수 있습니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L45
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_reloc_end = .; \
L46
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L48
BSS의 가장 앞에 nVHE 하이퍼바이저의 0 초기화 변수를 놓도록 공통 BSS_SECTION 규칙에 추가합니다. 하이퍼바이저와 호스트 BSS가 같은 시작 주소를 갖는 전제를 뒤의 ASSERT가 확인합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L49
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_bss_start = .; \
L50
nVHE의 0 초기화 변수를 호스트 BSS의 첫 부분에 모읍니다. 파일에 0을 일일이 저장하기보다 부팅 코드가 이 범위를 0으로 지웁니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L51
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L52
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_bss_end = .;
L60
BSS_SECTION 내부의 빈 .sbss 때문에 __bss_start와 __hyp_bss_start가 어긋나는 링커 배치 문제를 막습니다. KVM 빌드에서는 SBSS 정렬을 한 페이지로 강제합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L61
KVM을 빌드하지 않는 경우입니다. 하이퍼바이저 전용 데이터·복구 표·재배치 영역을 추가할 필요가 없어 아래 매크로들을 빈 정의로 만듭니다.
L62
KVM이 꺼져 있으므로 하이퍼바이저 예외 복구 표를 추가하지 않습니다. 뒤의 HYPERVISOR_TEXT 안에서 이 이름을 사용해도 아무 배치 문장이 나오지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L63
KVM이 꺼져 있으므로 nVHE 읽기 전용 데이터 섹션을 추가하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L64
KVM이 꺼져 있으므로 nVHE의 쓰기 가능한 데이터 섹션을 추가하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L65
KVM이 꺼져 있으므로 nVHE CPU별 데이터 원본 영역을 추가하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L66
KVM이 꺼져 있으므로 nVHE 주소 보정 기록 섹션을 추가하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L67
KVM 전용 BSS 시작 정렬 문제를 피하기 위한 추가 정렬을 사용하지 않습니다. 일반 BSS 배치 규칙은 그대로 적용됩니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L68
— 전처리 조건 구간을 끝냅니다.
L70
일반 커널 예외 복구 표를 읽기 전용 데이터 쪽에 4바이트 정렬로 배치하도록 공통 링커 매크로에 전달합니다. 이 표는 접근 오류가 난 명령에서 복구 위치를 찾는 데 쓰입니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L71
종료용 코드·데이터를 링크 시 바로 버리지 않고 초기화 영역에 남긴 뒤 부팅 후 해제하도록 선택합니다. 대체 명령 표 등 다른 섹션에서 참조하는 주소가 링크 과정에서 사라지는 것을 피합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L73
초기화 함수 목록, 읽기 전용 데이터, BSS, percpu 등 여러 아키텍처가 공유하는 배치 규칙을 가져옵니다. 위에서 정한 KVM·예외 표·종료 영역 정책을 이 매크로들이 반영합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L74
CPU 캐시 라인에 맞춘 데이터 정렬 값을 가져옵니다. 뒤의 PERCPU_SECTION과 RW_DATA가 L1_CACHE_BYTES를 사용합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L75
초기 identity mapping과 커널 매핑에 필요한 페이지 표 공간 크기 및 표 사이 오프셋을 가져옵니다. 뒤의 공간 예약과 ASSERT가 이 정의에 맞아야 합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L76
펌웨어를 다시 거치지 않고 다른 커널을 시작하는 kexec의 제어 페이지 크기 정의를 가져옵니다. 파일 끝에서 재배치 코드가 그 공간에 들어가는지 검사합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L77
커널 이미지의 가상 기준 주소 KIMAGE_VADDR와 스택·세그먼트 정렬 등 ARM64 메모리 배치 상수를 가져옵니다. 파일 오프셋과 실행 가상 주소를 정할 때 필요한 정의입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L78
선택한 커널 페이지 크기 PAGE_SIZE 등의 정의를 가져옵니다. 코드·데이터 경계를 페이지 단위로 분리하여 나중에 각각의 접근 권한을 설정할 수 있게 합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.

진입점과 특수 코드 구간

ENTRY(_text)는 ELF 진입 심볼을 정합니다. IDMAP_TEXT, HIBERNATE_TEXT, KEXEC_TEXT, TRAMP_TEXT는 입력 섹션들을 모으고 시작·끝 심볼을 남깁니다. CONFIG가 꺼진 경우 해당 매크로는 비어 있습니다. UNWIND_DATA_SECTIONS는 설정 시 .eh_frame을 수집합니다.

vmlinux.lds.S · L80–L145
80#include "image.h"
81
82OUTPUT_ARCH(aarch64)
83ENTRY(_text)
84
85jiffies = jiffies_64;
86
87#define HYPERVISOR_TEXT					\
88	. = ALIGN(PAGE_SIZE);				\
89	__hyp_idmap_text_start = .;			\
90	*(.hyp.idmap.text)				\
91	__hyp_idmap_text_end = .;			\
92	__hyp_text_start = .;				\
93	*(.hyp.text)					\
94	HYPERVISOR_EXTABLE				\
95	. = ALIGN(PAGE_SIZE);				\
96	__hyp_text_end = .;
97
98#define IDMAP_TEXT					\
99	. = ALIGN(SZ_4K);				\
100	__idmap_text_start = .;				\
101	*(.idmap.text)					\
102	__idmap_text_end = .;
103
104#ifdef CONFIG_HIBERNATION
105#define HIBERNATE_TEXT					\
106	ALIGN_FUNCTION();				\
107	__hibernate_exit_text_start = .;		\
108	*(.hibernate_exit.text)				\
109	__hibernate_exit_text_end = .;
110#else
111#define HIBERNATE_TEXT
112#endif
113
114#ifdef CONFIG_KEXEC_CORE
115#define KEXEC_TEXT					\
116	ALIGN_FUNCTION();				\
117	__relocate_new_kernel_start = .;		\
118	*(.kexec_relocate.text)				\
119	__relocate_new_kernel_end = .;
120#else
121#define KEXEC_TEXT
122#endif
123
124#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
125#define TRAMP_TEXT					\
126	. = ALIGN(PAGE_SIZE);				\
127	__entry_tramp_text_start = .;			\
128	*(.entry.tramp.text)				\
129	. = ALIGN(PAGE_SIZE);				\
130	__entry_tramp_text_end = .;			\
131	*(.entry.tramp.rodata)
132#else
133#define TRAMP_TEXT
134#endif
135
136#ifdef CONFIG_UNWIND_TABLES
137#define UNWIND_DATA_SECTIONS				\
138	.eh_frame : {					\
139		__pi___eh_frame_start = .;		\
140		*(.eh_frame)				\
141		__pi___eh_frame_end = .;		\
142	}
143#else
144#define UNWIND_DATA_SECTIONS
145#endif
L80
head.S의 Image 헤더에 넣을 커널 크기와 플래그를 링크 시 계산하는 HEAD_SYMBOLS 정의를 가져옵니다. 커널 엔디언과 관계없이 부트로더가 읽는 헤더 값을 리틀 엔디언으로 만듭니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L82
출력 ELF의 아키텍처를 AArch64로 지정합니다.
L83
출력 ELF의 진입 심볼을 _text로 지정합니다.
L85
타이머 틱 누적값인 jiffies를 64비트 실제 저장소 jiffies_64와 같은 주소로 연결합니다. AArch64의 unsigned long은 64비트이므로 두 이름으로 같은 카운터를 읽을 수 있습니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L87
EL2 초기 진입용 identity-mapped 코드와 일반 hyp 코드, KVM 예외 복구 표를 묶습니다. 뒤의 경계 기호로 필요한 EL2 코드만 매핑할 수 있습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L88
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L89
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_idmap_text_start = .; \
L90
물리 주소와 같은 가상 주소에서 실행하도록 작성된 hyp 초기화 코드를 모읍니다. 하이퍼바이저 주소 변환 상태를 바꾸는 짧은 구간에 필요하며 파일 끝에서 한 페이지 이내인지 확인합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L91
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_idmap_text_end = .; \
L92
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_text_start = .; \
L93
일반 .hyp.text 코드를 모읍니다. 앞의 짧은 identity-mapped 초기 코드와 경계를 구분하여 각각 필요한 주소 공간에 매핑할 수 있게 합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L94
CONFIG_KVM이 켜졌으면 앞에서 정의한 EL2 예외 복구 표를 이 위치에 배치합니다. KVM이 꺼졌으면 빈 매크로이므로 별도 표가 추가되지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L95
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L96
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hyp_text_end = .;
L98
MMU 상태를 바꾸는 동안 물리 주소와 같은 가상 주소에서 실행할 .idmap.text 코드를 모으는 규칙입니다. 시작을 4KiB 경계에 놓고 끝에서 한 4KiB 범위를 넘지 않는지 확인합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L99
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SZ_4K); \
L100
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __idmap_text_start = .; \
L101
MMU 전환 구간에 필요한 identity-mapped 함수들을 모읍니다. 커널의 높은 가상 주소 매핑을 아직 사용할 수 없거나 바꾸는 시점에 실행할 코드입니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L102
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __idmap_text_end = .;
L104
최대절전은 메모리 상태를 저장했다가 다시 복원하는 기능입니다. 켜진 빌드에서는 복원된 커널로 돌아갈 마지막 전환 코드를 별도 섹션으로 모읍니다. 꺼지면 이 코드 수집 매크로는 비워집니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L105
최대절전 이미지 복원 후 원래 커널로 넘어갈 .hibernate_exit.text 코드와 경계를 정의합니다. 복원 중 사용할 별도 실행 위치에 복사할 범위를 알 수 있게 합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L106
최대절전 복원 진입 함수를 CONFIG_FUNCTION_ALIGNMENT 경계에 맞춥니다. 복사할 코드의 첫 함수가 요구하는 정렬을 링크 결과에서도 유지합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L107
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hibernate_exit_text_start = .; \
L108
최대절전 복원의 마지막 전환 코드를 모읍니다. 뒤의 ASSERT는 이 범위가 4KiB 안에 들어가고 첫 명령이 swsusp_arch_suspend_exit인지 확인합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L109
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __hibernate_exit_text_end = .;
L110
— 앞 전처리 조건의 반대 경로입니다.
L111
최대절전 기능을 빌드하지 않으므로 복원용 전환 코드를 별도 수집하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L112
— 전처리 조건 구간을 끝냅니다.
L114
kexec는 현재 커널에서 새 커널로 직접 넘어가는 기능입니다. 켜지면 새 커널 이미지의 위치를 정리하고 진입할 재배치 코드를 별도 범위로 모읍니다. 꺼지면 KEXEC_TEXT는 비어 있습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L115
새 커널을 시작할 때 안전한 제어 페이지로 복사할 kexec 재배치 코드의 시작·끝을 정합니다. 현재 커널 메모리를 덮어쓰는 중에도 실행할 짧은 코드가 필요하기 때문입니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L116
kexec 재배치 코드의 첫 함수를 CONFIG_FUNCTION_ALIGNMENT 경계에 맞춥니다. 뒤에서 이 시작 위치가 arm64_relocate_new_kernel인지 함께 검증합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L117
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __relocate_new_kernel_start = .; \
L118
kexec의 마지막 이미지 이동·진입 코드를 모읍니다. 이 범위를 별도 제어 페이지에 옮길 수 있도록 뒤에서 크기와 시작 함수를 검사합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L119
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __relocate_new_kernel_end = .;
L120
— 앞 전처리 조건의 반대 경로입니다.
L121
kexec를 빌드하지 않으므로 새 커널 전환용 재배치 코드의 별도 배치가 필요 없습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L122
— 전처리 조건 구간을 끝냅니다.
L124
KPTI는 사용자 모드에서 커널 매핑 대부분을 빼는 보호 기능입니다. 켜진 빌드는 사용자·커널 페이지 표 사이를 전환하는 작은 진입 trampoline을 별도 페이지에 모읍니다. 실제 사용 여부는 부팅 시 CPU와 정책에 따라 결정됩니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L125
KPTI 예외 진입 trampoline의 실행 코드와 상수를 따로 모읍니다. 사용자용 페이지 표에서도 커널로 넘어가는 데 필요한 이 작은 영역은 접근 가능해야 합니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L126
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L127
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __entry_tramp_text_start = .; \
L128
entry.S가 만든 .entry.tramp.text 코드를 모읍니다. 예외 발생 시 커널 전체 매핑을 되살린 뒤 정상 벡터로 넘어가는 코드입니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L129
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE); \
L130
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __entry_tramp_text_end = .; \
L131
KPTI trampoline이 참조할 읽기 전용 자료를 코드 뒤에 둡니다. 일반 커널 데이터 전체를 사용자용 페이지 표에 남길 수 없으므로 필요한 자료를 이 별도 섹션에서 찾습니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L132
— 앞 전처리 조건의 반대 경로입니다.
L133
KPTI를 빌드하지 않으므로 제한된 매핑에서 실행할 진입 trampoline을 이 위치에 배치하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L134
— 전처리 조건 구간을 끝냅니다.
L136
컴파일러가 만든 호출 프레임 정보를 보존하는 설정입니다. 이 버전의 ARM64에서는 동적 Shadow Call Stack 구성이 이 설정을 선택하고, 초기 scs_patch가 .eh_frame을 읽어 PAC 명령을 SCS 코드로 바꿀 위치를 찾습니다. 꺼지면 이 섹션 수집 매크로가 비어 있습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L137
동적 Shadow Call Stack 패치가 참고할 .eh_frame 범위와 초기 코드용 __pi_ 경계 기호를 정의합니다. 일반 실행 중 스택 추적을 위해 무조건 영구 보존하는 영역으로 해석하면 안 됩니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L138
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .eh_frame : { \
L139
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi___eh_frame_start = .; \
L140
컴파일러의 호출 프레임 정보를 모읍니다. 초기 scs_patch는 이 정보에서 함수의 복귀 주소 처리 위치를 찾아 지원 구성에 맞는 Shadow Call Stack 명령으로 바꿉니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L141
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi___eh_frame_end = .; \
L142
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L143
— 앞 전처리 조건의 반대 경로입니다.
L144
호출 프레임 정보를 보존하지 않는 빌드이므로 이 전용 .eh_frame 배치 규칙을 추가하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L145
— 전처리 조건 구간을 끝냅니다.

PE 파일 정렬과 일반 text

PECOFF_FILE_ALIGNMENT는 0x200입니다. EFI 구성에서는 데이터 끝을 이 단위로 맞춥니다. SECTIONS는 출력 배치를 시작하고 필요 없는 동적 링크 섹션을 버립니다. _text는 KIMAGE_VADDR, _stext는 SEGMENT_ALIGN에 맞춘 일반 text 시작입니다.

vmlinux.lds.S · L146–L198
146
147/*
148 * The size of the PE/COFF section that covers the kernel image, which
149 * runs from _stext to _edata, must be a round multiple of the PE/COFF
150 * FileAlignment, which we set to its minimum value of 0x200. '_stext'
151 * itself is 4 KB aligned, so padding out _edata to a 0x200 aligned
152 * boundary should be sufficient.
153 */
154PECOFF_FILE_ALIGNMENT = 0x200;
155
156#ifdef CONFIG_EFI
157#define PECOFF_EDATA_PADDING	\
158	.pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
159#else
160#define PECOFF_EDATA_PADDING
161#endif
162
163SECTIONS
164{
165	/*
166	 * XXX: The linker does not define how output sections are
167	 * assigned to input sections when there are multiple statements
168	 * matching the same input section name.  There is no documented
169	 * order of matching.
170	 */
171	DISCARDS
172	/DISCARD/ : {
173		*(.interp .dynamic)
174		*(.dynsym .dynstr .hash .gnu.hash)
175		*(.ARM.attributes)
176	}
177
178	. = KIMAGE_VADDR;
179
180	.head.text : {
181		_text = .;
182		HEAD_TEXT
183	}
184	.text : ALIGN(SEGMENT_ALIGN) {	/* Real text segment		*/
185		_stext = .;		/* Text and read-only data	*/
186			IRQENTRY_TEXT
187			SOFTIRQENTRY_TEXT
188			ENTRY_TEXT
189			TEXT_TEXT
190			SCHED_TEXT
191			LOCK_TEXT
192			KPROBES_TEXT
193			HYPERVISOR_TEXT
194			*(.gnu.warning)
195	}
196
197	. = ALIGN(SEGMENT_ALIGN);
198	_etext = .;			/* End of text section */
L154
EFI가 해석하는 PE/COFF 이미지의 파일 정렬 단위를 512바이트로 정합니다. 커널의 메모리 페이지 크기와는 별개인 실행 파일 형식의 조건입니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L156
EFI 펌웨어가 이 커널 이미지를 PE/COFF 실행 파일로 적재할 수 있게 만드는 빌드입니다. 켜지면 데이터 파일 크기의 512바이트 정렬을 맞추는 padding 섹션을 추가합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L157
EFI용 PE/COFF 데이터 파일 크기를 512바이트 배수로 채우는 규칙을 정의합니다. 실제 padding은 아래 PECOFF_EDATA_PADDING을 사용한 위치에 출력됩니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L158
0 한 바이트를 실제 파일에 넣고 다음 PE/COFF 파일 정렬 경계까지 채웁니다. _edata까지의 파일 구간 길이가 헤더가 요구하는 512바이트 배수가 되도록 합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L159
— 앞 전처리 조건의 반대 경로입니다.
L160
EFI용 파일 정렬 보정이 필요 없는 빌드이므로 추가 padding을 출력하지 않습니다. 전처리기는 이후 이 이름이 쓰인 곳에 정의한 내용을 치환합니다. 실행 중 값을 보관하는 변수를 만드는 줄은 아닙니다.
L161
— 전처리 조건 구간을 끝냅니다.
L163
입력 오브젝트의 섹션을 출력 이미지에 배치하는 규칙을 시작합니다.
L164
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L171
최종 실행 이미지에 필요하지 않은 .discard 계열과 종료 호출 목록 등 공통 폐기 대상을 제거합니다. 위의 RUNTIME_DISCARD_EXIT 때문에 종료 코드·데이터 자체는 여기서 바로 제거되지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L172
이 블록에 일치하는 입력 섹션은 출력 이미지에서 버립니다.
L173
사용자 ELF 실행 파일의 동적 로더 경로와 동적 링크 정보는 이 커널 실행 경로에서 쓰지 않으므로 제거합니다. 커널이 처리할 재배치 기록은 아래에서 별도로 보존합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L174
사용자 공간 동적 링커용 심볼·문자열·해시 표를 제거합니다. 커널의 자체 심볼 표나 디버깅용 ELF 심볼 전체를 없앤다는 뜻은 아닙니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L175
입력 오브젝트의 ARM 속성 메타데이터를 최종 커널 이미지에서 제거합니다. CPU가 실행할 코드나 시스템 레지스터 설정을 삭제하는 줄은 아닙니다.
L176
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L178
링크할 커널 이미지의 첫 가상 주소를 KIMAGE_VADDR로 정합니다. 뒤의 _text가 정확히 이 주소여야 이미지 상대 주소로 물리·가상 변환을 하는 부팅 코드가 맞게 동작합니다. 여기서 .은 링커의 현재 배치 위치이며 CPU의 PC 레지스터가 아닙니다.
L180
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .head.text : {
L181
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _text = .;
L182
head.S의 .head.text를 이미지 맨 앞에 넣습니다. 부트로더가 읽을 ARM64 Image 헤더와 초기 진입 명령이 여기 있어야 합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L183
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L184
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .text : ALIGN(SEGMENT_ALIGN) {
L185
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _stext = .;
L186
하드웨어 인터럽트 진입용으로 표시한 코드들을 연속 범위에 모읍니다. __irqentry_text_start와 끝 기호로 이 종류의 코드 주소를 구별할 수 있게 합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L187
softirq 진입용으로 표시된 코드를 모읍니다. 하드웨어 IRQ 진입 범위와 따로 경계를 두어 실행 위치의 성격을 구분합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L188
예외·시스템 호출 진입용 .entry.text를 모으고 범위를 기록합니다. 일반 함수 본문과 달리 특별한 레지스터·추적 규칙을 갖는 진입 코드의 위치를 식별할 수 있게 합니다.
L189
일반 함수 코드와 hot·unlikely·계측 제한 코드 등을 공통 규칙에 맞춰 수집합니다. 실행 빈도나 계측 가능 여부에 따라 구분한 입력 섹션도 최종 실행 영역 안에 들어갑니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L190
스케줄러의 .sched.text를 모으고 시작·끝을 기록합니다. 호출 주소가 스케줄러 코드에 속하는지 판단할 수 있는 범위를 만듭니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L191
spinlock 관련 .spinlock.text를 모으고 경계를 기록합니다. 락을 직접 획득하는 링커 명령이 아니라 해당 구현 코드의 주소 범위를 만드는 작업입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L192
kprobe와 관련된 특별한 .kprobes.text 코드를 한 범위로 모읍니다. 실행 중 probe를 설치하는 줄은 아니며 코드 주소의 분류에 필요한 경계를 제공합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L193
앞서 정한 EL2 코드와 identity-mapped 초기화 코드, KVM 예외 복구 표를 실행 영역에 배치합니다. KVM 전용 표는 해당 빌드에서만 추가됩니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L194
모든 입력 오브젝트에서 패턴에 일치하는 섹션을 현재 출력 구간에 모읍니다: *(.gnu.warning)
L195
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L197
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SEGMENT_ALIGN);
L198
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _etext = .;

읽기 전용 코드와 루트 테이블

RO_DATA 뒤 .rodata.text에는 커널의 일반 매핑으로 실행하지 않는 trampoline·hibernate·kexec·idmap 코드를 모읍니다. 별도 실행 매핑의 권한은 페이지 테이블 코드에서 설정합니다. idmap_pg_dir, 선택적 tramp_pg_dir, reserved_pg_dir, swapper_pg_dir는 각각 한 페이지를 예약합니다.

vmlinux.lds.S · L199–L240
199
200	/* everything from this point to __init_begin will be marked RO NX */
201	RO_DATA(PAGE_SIZE)
202
203	HYPERVISOR_RODATA_SECTIONS
204
205	.got : { *(.got) }
206	/*
207	 * Make sure that the .got.plt is either completely empty or it
208	 * contains only the lazy dispatch entries.
209	 */
210	.got.plt : { *(.got.plt) }
211	ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18,
212	       "Unexpected GOT/PLT entries detected!")
213
214	/* code sections that are never executed via the kernel mapping */
215	.rodata.text : {
216		TRAMP_TEXT
217		HIBERNATE_TEXT
218		KEXEC_TEXT
219		IDMAP_TEXT
220		. = ALIGN(PAGE_SIZE);
221	}
222
223	idmap_pg_dir = .;
224	. += PAGE_SIZE;
225
226#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
227	tramp_pg_dir = .;
228	. += PAGE_SIZE;
229#endif
230
231	reserved_pg_dir = .;
232	. += PAGE_SIZE;
233
234	swapper_pg_dir = .;
235	. += PAGE_SIZE;
236
237	. = ALIGN(SEGMENT_ALIGN);
238	__init_begin = .;
239	__inittext_begin = .;
240
L201
상수와 각종 읽기 전용 표를 페이지 단위로 정리하여 배치합니다. 이후 커널이 이 영역에 쓰기 금지·실행 금지 권한을 적용할 수 있도록 코드와 경계를 분리합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L203
nVHE 하이퍼바이저의 읽기 전용 데이터 범위를 배치합니다. KVM을 빌드하지 않으면 앞에서 빈 매크로로 정의했으므로 아무 섹션도 추가하지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L205
주소를 간접 참조할 때 쓰는 Global Offset Table의 항목을 보존합니다. .got은 데이터 표이며 이곳에 함수 본문을 넣는 것이 아닙니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L210
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .got.plt : { *(.got.plt) }
L211
동적 함수 호출 연결용 GOT/PLT 항목이 없거나 예약된 24바이트만 있는지 링크 시 확인합니다. 커널이 처리하지 않는 추가 lazy binding 항목이 생기면 빌드를 중단합니다.
L212
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "Unexpected GOT/PLT entries detected!")
L215
커널의 일반 이미지 매핑에서는 실행하지 않을 전환 코드를 읽기 전용 영역에 둡니다. 각 코드는 identity mapping이나 trampoline 별칭 등 필요한 별도 매핑에서 실행됩니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L216
KPTI의 제한된 주소 공간에서 커널 매핑으로 들어오는 trampoline과 상수를 배치합니다. 일반 커널 매핑에서 이 코드 페이지를 실행 가능하게 둘 필요는 없습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L217
최대절전 복원 마지막 단계에 별도 위치에서 실행할 코드를 배치합니다. 기능을 끈 빌드에서는 이 매크로가 비어 있습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L218
새 커널로 전환할 때 제어 페이지에 복사하여 실행할 kexec 코드를 배치합니다. 기능을 끈 빌드에서는 아무 내용도 추가되지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L219
MMU 전환 중 identity mapping으로 실행할 코드를 배치합니다. 같은 물리 코드가 일반 커널 매핑에서는 읽기 전용 데이터처럼 놓일 수 있습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L220
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE);
L221
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L223
identity mapping의 루트 페이지 표가 시작할 주소를 기록합니다. 바로 뒤에서 PAGE_SIZE만큼 공간을 예약하므로 표의 위치와 크기가 연결됩니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L224
identity mapping 루트 표 한 페이지를 이미지 주소 공간에 예약합니다. 여기서는 표 항목을 채우지 않으며 부팅 코드가 필요한 매핑을 작성합니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L226
사용자 공간에서 커널 매핑을 제거하는 KPTI를 빌드한 경우에만 제한된 trampoline용 루트 표 공간을 마련합니다. 꺼지면 이 표와 예약 공간은 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L227
KPTI trampoline용 페이지 표의 위치를 기록합니다. entry.S가 커널 표와의 고정 오프셋으로 전환하므로 배치가 코드의 상수와 일치해야 합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L228
KPTI trampoline용 루트 표 한 페이지를 예약합니다. 모든 커널 영역을 사용자 주소 공간에 남기는 것이 아니라 필요한 작은 진입 영역을 연결할 표입니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L229
— 전처리 조건 구간을 끝냅니다.
L231
접근을 막을 때 사용할 예약 페이지 표의 시작을 기록합니다. 정상 커널 표와의 거리는 RESERVED_SWAPPER_OFFSET 검사로 보장합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L232
예약 루트 페이지 표 한 페이지를 확보합니다. 다음 swapper_pg_dir와의 주소 차이를 이용하는 어셈블리 코드가 있어 크기와 순서를 임의로 바꾸면 안 됩니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L234
정상 커널 매핑을 담을 swapper 루트 페이지 표의 시작을 기록합니다. 초기 임시 매핑 표와 구별되는 커널의 정식 루트 표입니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L235
swapper 루트 표 한 페이지를 예약합니다. 하위 단계 페이지 표 전체가 여기 한 페이지에 모두 들어간다는 뜻은 아닙니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L237
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SEGMENT_ALIGN);
L238
부팅이 끝나면 해제할 수 있는 초기화 영역의 시작입니다. 이후 코드·데이터는 __init_end까지 일반적인 영구 커널 영역과 구분됩니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L239
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __inittext_begin = .;

초기화와 재배치 정보

init text와 alternative 레코드를 배치한 뒤 __initdata_begin에서 초기 idmap 테이블을 예약합니다. init data, per-CPU, hyp 재배치, RELA·RELR 테이블이 이어집니다. __pi_rela_start 등의 심볼은 early_map_kernel의 재배치 코드에서 범위로 사용합니다.

vmlinux.lds.S · L241–L299
241	INIT_TEXT_SECTION(8)
242
243	__exittext_begin = .;
244	.exit.text : {
245		EXIT_TEXT
246	}
247	__exittext_end = .;
248
249	. = ALIGN(4);
250	.altinstructions : {
251		__alt_instructions = .;
252		*(.altinstructions)
253		__alt_instructions_end = .;
254	}
255
256	UNWIND_DATA_SECTIONS
257
258	. = ALIGN(SEGMENT_ALIGN);
259	__inittext_end = .;
260	__initdata_begin = .;
261
262	__pi_init_idmap_pg_dir = .;
263	. += INIT_IDMAP_DIR_SIZE;
264	__pi_init_idmap_pg_end = .;
265
266	.init.data : {
267		INIT_DATA
268		INIT_SETUP(16)
269		INIT_CALLS
270		CON_INITCALL
271		INIT_RAM_FS
272		*(.init.altinstructions .init.bss)	/* from the EFI stub */
273	}
274	.exit.data : {
275		EXIT_DATA
276	}
277
278	RUNTIME_CONST_VARIABLES
279
280	PERCPU_SECTION(L1_CACHE_BYTES)
281	HYPERVISOR_PERCPU_SECTION
282
283	HYPERVISOR_RELOC_SECTION
284
285	.rela.dyn : ALIGN(8) {
286		__pi_rela_start = .;
287		*(.rela .rela*)
288		__pi_rela_end = .;
289	}
290
291	.relr.dyn : ALIGN(8) {
292		__pi_relr_start = .;
293		*(.relr.dyn)
294		__pi_relr_end = .;
295	}
296
297	. = ALIGN(SEGMENT_ALIGN);
298	__initdata_end = .;
299	__init_end = .;
L241
부팅 초기화 전용 함수들을 정렬해 모읍니다. __init 코드의 수명이 끝나면 이 메모리를 돌려줄 수 있도록 일반 .text와 떨어뜨립니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L243
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __exittext_begin = .;
L244
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .exit.text : {
L245
종료용 코드도 일단 이 초기화 영역에 모읍니다. 링크 중 대체 명령 표 등의 참조를 유지한 뒤 초기화 메모리와 함께 정리하려는 배치입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L246
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L247
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __exittext_end = .;
L249
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(4);
L250
CPU 기능에 따라 부팅 시 명령열을 교체할 위치와 대체 코드의 정보를 담는 표입니다. 이 섹션이 실제 실행 경로를 고르는 것이 아니라 alternatives 처리 코드가 읽습니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L251
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __alt_instructions = .;
L252
각 오브젝트가 기록한 대체 명령 메타데이터를 모읍니다. CPU 기능 검사 결과에 맞춰 명령을 패치할 위치·길이 등을 찾는 데 사용합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L253
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __alt_instructions_end = .;
L254
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L256
설정에 따라 .eh_frame을 초기화 영역에 배치합니다. 동적 SCS 패치가 필요한 부팅에서는 초기 코드가 이 자료를 사용하며, 초기화가 끝나면 해당 범위는 초기화 메모리와 함께 해제할 수 있습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L258
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SEGMENT_ALIGN);
L259
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __inittext_end = .;
L260
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __initdata_begin = .;
L262
초기 위치 독립 코드가 identity mapping을 만들 때 사용할 페이지 표 공간의 시작입니다. 영구 idmap_pg_dir와 이름·수명을 구분합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L263
현재 페이지 크기와 주소 변환 단계에 맞춰 계산한 초기 identity-mapping 표 공간을 예약합니다. 필요한 하위 단계 표도 들어가므로 크기를 임의로 PAGE_SIZE로 줄일 수 없습니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L264
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_init_idmap_pg_end = .;
L266
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .init.data : {
L267
초기화 동안만 필요한 변수와 관련 표를 .init.data에 수집합니다. 이들의 사용이 끝나야 초기화 영역 전체를 해제할 수 있습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L268
커널 명령행 옵션 처리기의 이름·함수 연결 정보를 16바이트 정렬로 모읍니다. 부팅 때 전달받은 옵션을 어느 함수가 처리할지 찾는 자료입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L269
등록된 초기화 함수 포인터를 단계별 순서로 모읍니다. 부팅 코드가 이 목록을 순회하여 서브시스템과 장치를 초기화하며, 링커 자체가 함수를 호출하지는 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L270
초기 콘솔 초기화 함수 목록을 일반 initcall 목록과 구분해 모읍니다. 부팅 메시지를 출력할 콘솔을 준비하는 경로가 이 범위를 사용합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L271
빌드에 포함한 초기 루트 파일 시스템 initramfs 이미지와 정보를 모읍니다. 초기 사용자 공간을 준비할 때 풀어 사용할 자료이며, 해당 빌드 기능이 없으면 매크로가 비어 있습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L272
EFI stub가 사용한 대체 명령 정보와 0 초기화 데이터를 커널 초기화 데이터 영역에 넣습니다. 영구 데이터로 남기지 않고 초기화 수명에 맞춰 함께 관리합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L273
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L274
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .exit.data : {
L275
종료용 데이터를 링크 단계에서는 보존하되 초기화 후 해제할 범위에 둡니다. 위의 RUNTIME_DISCARD_EXIT 정책을 이 배치가 구현합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L276
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L278
dentry 해시 표 포인터와 해시 시프트를 사용하는 명령 위치를 모읍니다. 값이 결정되면 ARM64 runtime-const 코드가 MOVZ/MOVK나 LSR의 즉시값을 고쳐 매번 변수를 읽는 대신 확정된 값을 사용할 수 있게 합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L280
일반 커널의 CPU별 변수 원본을 모으고 캐시 라인 기준으로 하위 영역을 정렬합니다. 서로 다른 용도의 값이 불필요하게 같은 캐시 라인을 공유하는 것을 줄이려는 배치입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L281
KVM nVHE의 CPU별 변수 원본을 별도 페이지 정렬 영역에 둡니다. 일반 커널 percpu 범위와 하이퍼바이저용 범위를 섞지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L283
nVHE 하이퍼바이저의 주소 보정 위치 목록을 배치합니다. 아래의 일반 커널 RELA·RELR 표와 별개의 대상입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L285
명시적 덧셈값을 가진 ELF RELA 재배치 기록을 8바이트 정렬로 모읍니다. 초기 코드가 실제 커널 배치 주소에 맞게 주소를 보정할 때 사용합니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L286
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_rela_start = .;
L287
입력 ELF의 RELA 재배치 기록을 모읍니다. __pi_rela_start부터 끝까지의 기록은 어느 위치의 주소를 어떻게 보정할지 초기 코드에 알려 줍니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L288
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_rela_end = .;
L289
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L291
상대 재배치 정보를 압축한 RELR 표를 8바이트 정렬로 둡니다. 위의 RELA와 표현 방식이 달라 별도의 시작·끝 기호를 제공합니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L292
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_relr_start = .;
L293
RELR 형식으로 표현된 주소 보정 위치들을 모읍니다. 기록을 해석하는 초기 코드가 한 항목 또는 비트맵이 가리키는 위치들의 주소를 보정합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L294
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_relr_end = .;
L295
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L297
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SEGMENT_ALIGN);
L298
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __initdata_end = .;
L299
초기화 코드·데이터·각종 부팅용 표가 끝나는 위치입니다. __init_begin부터 이 지점까지는 초기화 완료 후 해제할 수 있는 범위로 관리합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.

일반 데이터·BSS·초기 스택

MMU-off 접근 데이터는 캐시 관리가 이웃 데이터를 건드리지 않도록 2 KiB 경계로 분리합니다. BSS 뒤에는 초기 커널 테이블 공간을 예약하고 __pi_init_pg_end를 정의합니다. 그 다음 4 KiB를 확보한 끝이 early_init_stack입니다. 따라서 head.S에서 쓰는 초기 스택은 BSS부터 init_pg_end까지의 0 초기화 범위 밖에 있습니다.

vmlinux.lds.S · L300–L348
300
301	.data.rel.ro : { *(.data.rel.ro) }
302	ASSERT(SIZEOF(.data.rel.ro) == 0, "Unexpected RELRO detected!")
303
304	_data = .;
305	_sdata = .;
306	RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN)
307
308	HYPERVISOR_DATA_SECTION
309
310	/*
311	 * Data written with the MMU off but read with the MMU on requires
312	 * cache lines to be invalidated, discarding up to a Cache Writeback
313	 * Granule (CWG) of data from the cache. Keep the section that
314	 * requires this type of maintenance to be in its own Cache Writeback
315	 * Granule (CWG) area so the cache maintenance operations don't
316	 * interfere with adjacent data.
317	 */
318	.mmuoff.data.write : ALIGN(SZ_2K) {
319		__mmuoff_data_start = .;
320		*(.mmuoff.data.write)
321	}
322	. = ALIGN(SZ_2K);
323	.mmuoff.data.read : {
324		*(.mmuoff.data.read)
325		__mmuoff_data_end = .;
326	}
327
328	PECOFF_EDATA_PADDING
329	__pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);
330	_edata = .;
331
332	/* start of zero-init region */
333	BSS_SECTION(SBSS_ALIGN, 0, 0)
334	__pi___bss_start = __bss_start;
335
336	. = ALIGN(PAGE_SIZE);
337	__pi_init_pg_dir = .;
338	. += INIT_DIR_SIZE;
339	__pi_init_pg_end = .;
340	/* end of zero-init region */
341
342	. += SZ_4K;		/* stack for the early C runtime */
343	early_init_stack = .;
344
345	. = ALIGN(SEGMENT_ALIGN);
346	__pecoff_data_size = ABSOLUTE(. - __initdata_begin);
347	_end = .;
348	__pi__end = .;
L301
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .data.rel.ro : { *(.data.rel.ro) }
L302
별도 처리되지 않은 .data.rel.ro가 남아 있지 않은지 검사합니다. 주소 재배치 후 읽기 전용으로 둘 데이터가 예상한 배치에서 빠지면 링크를 실패시켜 보호 범위가 어긋나는 것을 막습니다.
L304
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _data = .;
L305
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _sdata = .;
L306
초기값이 있는 쓰기 가능 데이터와 초기 태스크 스택 등을 모읍니다. 캐시 라인·페이지·스택 정렬을 각각 전달하여 서로 다른 정렬 요구를 맞춥니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L308
nVHE 하이퍼바이저가 실행 중 수정할 초기값 있는 데이터를 별도 범위에 배치합니다. KVM이 꺼진 빌드에서는 아무 영역도 추가하지 않습니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L318
MMU를 끈 상태에서 쓰는 데이터를 최대 Cache Writeback Granule에 맞춘 2KiB 경계로 분리합니다. 뒤의 캐시 무효화가 인접한 다른 데이터를 함께 버리지 않게 하려는 배치입니다. 링커가 정하는 섹션 배치와 CPU의 실제 접근 권한은 별개이며, 메모리 권한은 페이지 테이블 설정도 필요합니다.
L319
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __mmuoff_data_start = .;
L320
MMU를 끈 초기 코드가 기록하는 boot_args 같은 .mmuoff.data.write 값을 모읍니다. MMU를 켠 뒤 읽을 때 캐시 정합성을 다뤄야 하므로 일반 데이터와 떨어뜨립니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L321
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L322
MMU-off 쓰기 영역 뒤를 다시 2KiB 경계로 올립니다. 관련 캐시 유지보수로 영향을 받을 범위가 옆 영역과 섞이지 않도록 합니다. 여기서 .은 링커의 현재 배치 위치이며 CPU의 PC 레지스터가 아닙니다.
L323
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .mmuoff.data.read : {
L324
MMU를 끈 CPU가 읽어야 하는 .mmuoff.data.read 데이터를 모읍니다. 앞의 쓰기 영역과 함께 전환 시점의 캐시 관리 대상 경계를 구성합니다. 앞의 *는 링크에 참여한 모든 입력 오브젝트에서 괄호 안 이름과 일치하는 섹션을 모으라는 뜻입니다.
L325
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __mmuoff_data_end = .;
L326
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L328
EFI 빌드이면 PE/COFF가 요구하는 파일 정렬 padding을 여기 넣습니다. _edata와 데이터의 파일 크기를 계산하기 전에 길이를 맞춰야 합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L329
PE/COFF 데이터 섹션이 파일에 실제로 차지하는 길이를 초기화 데이터 시작부터 계산합니다. 뒤의 BSS·초기 페이지 표·스택 등 메모리만 예약하는 부분은 아직 포함하지 않습니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L330
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: _edata = .;
L333
초기값이 0인 전역 변수들의 BSS 영역을 만듭니다. KVM이 켜진 빌드는 hyp BSS를 맨 앞에 놓고 SBSS_ALIGN을 사용해 시작 경계가 어긋나지 않게 합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L334
초기 위치 독립 코드가 BSS의 시작을 참조할 수 있도록 __pi_ 접두사의 별칭을 만듭니다. 별도 BSS를 다시 예약하는 것이 아니라 같은 주소를 가리킵니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L336
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(PAGE_SIZE);
L337
초기 커널 가상 주소 매핑을 만들 임시 페이지 표 공간의 시작입니다. 부팅 초기 C 코드가 이 범위를 표 저장소로 사용합니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L338
커널 페이지 크기와 매핑 단계에 필요한 INIT_DIR_SIZE만큼 임시 페이지 표 공간을 예약합니다. 바로 앞 BSS와 함께 부팅 초기에 0으로 초기화할 범위에 들어갑니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L339
왼쪽 심볼에 오른쪽 식의 링크 시 값을 지정합니다. 점(.)은 현재 출력 주소입니다: __pi_init_pg_end = .;
L342
MMU를 켜기 전 초기 C 함수가 사용할 스택 공간 4KiB를 예약합니다. 정식 태스크 스택이 준비되기 전에 함수 호출과 지역 변수를 보관할 공간입니다. 링커의 현재 배치 위치를 옮겨 공간을 예약합니다. 부팅 중 동적 메모리를 할당하는 함수 호출이 아닙니다.
L343
방금 예약한 4KiB 공간의 높은 주소 쪽 끝을 초기 SP 값으로 지정합니다. AArch64 스택은 SP를 낮추며 사용하므로 head.S가 이 기호를 SP에 넣습니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L345
링커의 현재 출력 위치를 변경합니다. ALIGN은 지정 경계까지 올림합니다: . = ALIGN(SEGMENT_ALIGN);
L346
PE/COFF 데이터 섹션이 메모리에서 필요한 전체 길이를 계산합니다. 파일에 저장된 데이터뿐 아니라 BSS와 초기 표·스택·정렬 공간까지 포함하므로 rawsize와 구분됩니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L347
커널 이미지가 메모리에서 차지하는 마지막 경계를 기록합니다. 뒤의 Image 헤더 크기 계산은 이 주소에서 _text를 뺍니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.
L348
커널 끝 주소를 초기 위치 독립 코드도 참조할 수 있도록 __pi_ 이름으로 제공합니다. 이 줄이 메모리를 추가로 예약하지는 않습니다. 링크 단계에서 이 식의 값을 심벌에 부여합니다. 값을 저장할 런타임 변수를 따로 만드는 것은 아닙니다.

심볼 보완과 링크 시 검사

디버그 정보와 Image 헤더 심볼을 출력하고 image-vars.h의 별칭을 포함합니다. ASSERT는 HYP/idmap 코드 크기, KPTI trampoline 크기, _text의 위치, 페이지 테이블 간격, kexec 코드의 크기와 시작 주소를 검사합니다. 이 조건이 실패하면 부팅 중 분기가 아니라 링크 오류가 발생합니다.

vmlinux.lds.S · L349–L411
349
350	STABS_DEBUG
351	DWARF_DEBUG
352	MODINFO
353	ELF_DETAILS
354
355	HEAD_SYMBOLS
356
357	/*
358	 * Sections that should stay zero sized, which is safer to
359	 * explicitly check instead of blindly discarding.
360	 */
361	.plt : {
362		*(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
363	}
364	ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
365}
366
367#include "image-vars.h"
368
369/*
370 * The HYP init code and ID map text can't be longer than a page each. The
371 * former is page-aligned, but the latter may not be with 16K or 64K pages, so
372 * it should also not cross a page boundary.
373 */
374ASSERT(__hyp_idmap_text_end - __hyp_idmap_text_start <= PAGE_SIZE,
375	"HYP init code too big")
376ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
377	"ID map text too big or misaligned")
378#ifdef CONFIG_HIBERNATION
379ASSERT(__hibernate_exit_text_end - __hibernate_exit_text_start <= SZ_4K,
380       "Hibernate exit text is bigger than 4 KiB")
381ASSERT(__hibernate_exit_text_start == swsusp_arch_suspend_exit,
382       "Hibernate exit text does not start with swsusp_arch_suspend_exit")
383#endif
384#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
385ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
386	"Entry trampoline text too big")
387#endif
388#ifdef CONFIG_KVM
389ASSERT(__hyp_bss_start == __bss_start, "HYP and Host BSS are misaligned")
390#endif
391/*
392 * If padding is applied before .head.text, virt<->phys conversions will fail.
393 */
394ASSERT(_text == KIMAGE_VADDR, "HEAD is misaligned")
395
396ASSERT(swapper_pg_dir - reserved_pg_dir == RESERVED_SWAPPER_OFFSET,
397       "RESERVED_SWAPPER_OFFSET is wrong!")
398
399#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
400ASSERT(swapper_pg_dir - tramp_pg_dir == TRAMP_SWAPPER_OFFSET,
401       "TRAMP_SWAPPER_OFFSET is wrong!")
402#endif
403
404#ifdef CONFIG_KEXEC_CORE
405/* kexec relocation code should fit into one KEXEC_CONTROL_PAGE_SIZE */
406ASSERT(__relocate_new_kernel_end - __relocate_new_kernel_start <= SZ_4K,
407       "kexec relocation code is bigger than 4 KiB")
408ASSERT(KEXEC_CONTROL_PAGE_SIZE >= SZ_4K, "KEXEC_CONTROL_PAGE_SIZE is broken")
409ASSERT(__relocate_new_kernel_start == arm64_relocate_new_kernel,
410       "kexec control page does not start with arm64_relocate_new_kernel")
411#endif
L350
STABS 형식의 디버깅 정보를 ELF에 보존합니다. 실행할 커널 함수가 아니라 디버거가 소스·기호를 해석할 때 사용하는 메타데이터입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L351
DWARF 형식의 소스 행·자료형·변수 위치 등 디버깅 정보를 ELF에 모읍니다. 커널 실행 순서를 추가하는 부분이 아닙니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L352
오브젝트에 포함된 모듈 설명 정보를 .modinfo로 모읍니다. 일반 명령 본문이나 장치 초기화 함수 목록과 구분되는 메타데이터입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L353
ELF의 기호·문자열·섹션 이름 및 도구 설명 정보를 보존합니다. 실행 시 읽을 일반 커널 데이터 영역과 목적이 다른 파일 메타데이터입니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L355
Image 헤더에 들어갈 전체 크기와 엔디언·페이지 크기 등의 플래그 값을 확정합니다. 링커만 알 수 있는 _end−_text를 계산하고 리틀 엔디언 필드로 표현합니다. 이는 공통 링커 스크립트 매크로를 펼쳐 섹션과 경계 심벌을 배치하는 과정입니다. CPU가 호출할 함수는 아닙니다.
L361
이름이 있는 출력 섹션을 정의합니다. 괄호 안 입력 패턴을 모으고 필요한 정렬을 적용합니다: .plt : {
L362
모든 입력 오브젝트에서 패턴에 일치하는 섹션을 현재 출력 구간에 모읍니다: *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
L363
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L364
커널이 실행 중 외부 동적 링커에 의존하는 PLT 연결 코드가 생기지 않았는지 검사합니다. 예상 밖 연결이 있으면 단순히 버려 손상된 이미지를 만들지 않고 링크를 중단합니다.
L365
출력 섹션 또는 SECTIONS 블록의 범위를 구분합니다.
L367
섹션 주소가 확정된 뒤 EFI stub·초기 위치 독립 코드·KVM nVHE 코드가 사용할 심볼 별칭을 정의합니다. 서로 다른 접두사를 쓰는 코드가 허용된 커널 기호만 공유하도록 합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L374
EL2 초기 identity-mapped 코드 전체가 한 커널 페이지에 들어가는지 검사합니다. 해당 초기 매핑 크기로 감당하지 못하는 코드가 생성되면 링크를 중단합니다.
L375
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "HYP init code too big")
L376
일반 MMU 전환 코드가 정렬된 한 4KiB 범위 안에 들어가는지 검사합니다. 단순 길이뿐 아니라 시작 위치의 어긋남도 포함하여 페이지 경계를 넘는 것을 막습니다.
L377
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "ID map text too big or misaligned")
L378
최대절전 복원 코드를 포함한 빌드에서만 아래 크기·시작 주소 검사를 합니다. 기능을 끈 빌드에는 검사할 복원 코드 범위가 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L379
최대절전 복원의 마지막 전환 코드가 복사용 4KiB 범위에 들어가는지 확인합니다. 너무 커지면 부팅 가능한 커널 이미지로 링크하지 않습니다.
L380
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "Hibernate exit text is bigger than 4 KiB")
L381
복원용 코드 범위의 첫 명령이 swsusp_arch_suspend_exit인지 검사합니다. 범위의 시작 주소로 진입하는 코드가 다른 함수나 padding에 들어가는 것을 막습니다.
L382
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "Hibernate exit text does not start with swsusp_arch_suspend_exit")
L383
— 전처리 조건 구간을 끝냅니다.
L384
KPTI 진입 trampoline을 포함하는 빌드에서만 크기 제한을 검사합니다. 이 설정이 꺼져 있으면 별도 trampoline 섹션도 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L385
KPTI trampoline의 실행 코드가 예약된 세 페이지 이내인지 확인합니다. entry.S의 여러 완화 방식별 벡터가 이 제한된 매핑 안에 들어가야 합니다.
L386
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "Entry trampoline text too big")
L387
— 전처리 조건 구간을 끝냅니다.
L388
KVM을 빌드한 경우에만 hyp BSS와 호스트 BSS의 공동 시작 주소를 검증합니다. nVHE의 초기화·메모리 배치가 이 관계에 의존합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L389
nVHE BSS가 전체 커널 BSS 맨 앞에서 시작하는지 확인합니다. 위의 BSS_FIRST_SECTIONS와 SBSS_ALIGN으로 의도한 배치가 링커 결과에서도 성립해야 합니다.
L390
— 전처리 조건 구간을 끝냅니다.
L394
Image 헤더의 시작 _text가 커널 기준 가상 주소와 정확히 같은지 검사합니다. 앞쪽에 뜻하지 않은 padding이 끼면 이미지 상대 오프셋을 이용한 물리·가상 주소 변환이 틀어집니다.
L396
정상 커널 루트 표와 예약 루트 표의 실제 주소 차이가 어셈블리에서 사용하는 RESERVED_SWAPPER_OFFSET와 같은지 검사합니다. 표 전환의 주소 계산이 다른 데이터를 가리키는 것을 막습니다.
L397
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "RESERVED_SWAPPER_OFFSET is wrong!")
L399
KPTI가 있는 빌드에서만 trampoline 루트 표와 정상 커널 루트 표 사이의 고정 거리도 검사합니다. 이 거리는 빠른 진입·복귀 표 전환에 사용됩니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L400
swapper와 trampoline 루트 표의 주소 차이가 TRAMP_SWAPPER_OFFSET와 일치하는지 확인합니다. entry.S의 덧셈·뺄셈으로 표를 바꾸는 코드와 링크 배치를 연결하는 검사입니다.
L401
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "TRAMP_SWAPPER_OFFSET is wrong!")
L402
— 전처리 조건 구간을 끝냅니다.
L404
kexec를 포함한 빌드에서만 새 커널 전환 코드의 크기·제어 페이지·진입 위치를 검증합니다. 꺼진 빌드에는 해당 코드가 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
L406
kexec 재배치 코드가 4KiB 안에 들어가는지 검사합니다. 현재 커널을 덮어쓰면서도 별도 제어 페이지에서 끝까지 실행할 수 있어야 합니다.
L407
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "kexec relocation code is bigger than 4 KiB")
L408
kexec 제어 페이지가 최소 4KiB인지를 확인합니다. 앞에서 허용한 재배치 코드 크기보다 실제 실행 공간이 작아지는 설정을 막습니다.
L409
복사할 kexec 코드 범위가 arm64_relocate_new_kernel에서 시작하는지 확인합니다. 복사한 범위의 첫 주소로 진입했을 때 올바른 함수가 실행되어야 합니다.
L410
앞 ASSERT 조건이 실패할 때 출력할 오류 문구입니다: "kexec control page does not start with arm64_relocate_new_kernel")
L411
— 전처리 조건 구간을 끝냅니다.

매크로 정의와 확장

각 정의는 v6.18.37 원문입니다. 역슬래시 인자는 사용 위치의 값으로 치환되며, 안쪽 매크로와 조건부 블록은 이후 단계에서 다시 처리됩니다.

ALIGN_FUNCTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L87–L87

앞뒤 조건을 포함한 원문

#define ALIGN_FUNCTION()  . = ALIGN(CONFIG_FUNCTION_ALIGNMENT)

ASSERT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/image-vars.h L14–L14

앞뒤 조건을 포함한 원문

#define ASSERT(...)

BSS_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L1152–L1158

앞뒤 조건을 포함한 원문

#define BSS_SECTION(sbss_align, bss_align, stop_align)			\
	. = ALIGN(sbss_align);						\
	__bss_start = .;						\
	SBSS(sbss_align)						\
	BSS(bss_align)							\
	. = ALIGN(stop_align);						\
	__bss_stop = .;

CON_INITCALL

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L948–L949

앞뒤 조건을 포함한 원문

#define CON_INITCALL							\
	BOUNDED_SECTION_POST_LABEL(.con_initcall.init, __con_initcall, _start, _end)

DISCARDS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L1054–L1059

앞뒤 조건을 포함한 원문

#define DISCARDS							\
	/DISCARD/ : {							\
	EXIT_DISCARDS							\
	EXIT_CALL							\
	COMMON_DISCARDS							\
	}

DWARF_DEBUG

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L783–L822

앞뒤 조건을 포함한 원문

#define DWARF_DEBUG							\
		/* DWARF 1 */						\
		.debug          0 : { *(.debug) }			\
		.line           0 : { *(.line) }			\
		/* GNU DWARF 1 extensions */				\
		.debug_srcinfo  0 : { *(.debug_srcinfo) }		\
		.debug_sfnames  0 : { *(.debug_sfnames) }		\
		/* DWARF 1.1 and DWARF 2 */				\
		.debug_aranges  0 : { *(.debug_aranges) }		\
		.debug_pubnames 0 : { *(.debug_pubnames) }		\
		/* DWARF 2 */						\
		.debug_info     0 : { *(.debug_info			\
				.gnu.linkonce.wi.*) }			\
		.debug_abbrev   0 : { *(.debug_abbrev) }		\
		.debug_line     0 : { *(.debug_line) }			\
		.debug_frame    0 : { *(.debug_frame) }			\
		.debug_str      0 : { *(.debug_str) }			\
		.debug_loc      0 : { *(.debug_loc) }			\
		.debug_macinfo  0 : { *(.debug_macinfo) }		\
		.debug_pubtypes 0 : { *(.debug_pubtypes) }		\
		/* DWARF 3 */						\
		.debug_ranges	0 : { *(.debug_ranges) }		\
		/* SGI/MIPS DWARF 2 extensions */			\
		.debug_weaknames 0 : { *(.debug_weaknames) }		\
		.debug_funcnames 0 : { *(.debug_funcnames) }		\
		.debug_typenames 0 : { *(.debug_typenames) }		\
		.debug_varnames  0 : { *(.debug_varnames) }		\
		/* GNU DWARF 2 extensions */				\
		.debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) }	\
		.debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) }	\
		/* DWARF 4 */						\
		.debug_types	0 : { *(.debug_types) }			\
		/* DWARF 5 */						\
		.debug_addr	0 : { *(.debug_addr) }			\
		.debug_line_str	0 : { *(.debug_line_str) }		\
		.debug_loclists	0 : { *(.debug_loclists) }		\
		.debug_macro	0 : { *(.debug_macro) }			\
		.debug_names	0 : { *(.debug_names) }			\
		.debug_rnglists	0 : { *(.debug_rnglists) }		\
		.debug_str_offsets	0 : { *(.debug_str_offsets) }

ELF_DETAILS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L834–L838

앞뒤 조건을 포함한 원문

#define ELF_DETAILS							\
		.comment 0 : { *(.comment) }				\
		.symtab 0 : { *(.symtab) }				\
		.strtab 0 : { *(.strtab) }				\
		.shstrtab 0 : { *(.shstrtab) }

ENTRY

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/linux/linkage.h L118–L119

앞뒤 조건을 포함한 원문

#define ENTRY(name) \
	SYM_FUNC_START(name)

ENTRY_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L625–L629

앞뒤 조건을 포함한 원문

#define ENTRY_TEXT							\
		ALIGN_FUNCTION();					\
		__entry_text_start = .;					\
		*(.entry.text)						\
		__entry_text_end = .;

EXIT_DATA

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L734–L738

앞뒤 조건을 포함한 원문

#define EXIT_DATA							\
	*(.exit.data .exit.data.*)					\
	*(.fini_array .fini_array.*)					\
	*(.dtors .dtors.*)						\

EXIT_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L739–L742

앞뒤 조건을 포함한 원문

#define EXIT_TEXT							\
	*(.exit.text)							\
	*(.text.exit)							\

HEAD_SYMBOLS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/image.h L63–L65

앞뒤 조건을 포함한 원문

#define HEAD_SYMBOLS						\
	DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);	\
	DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);

HEAD_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L650–L650

앞뒤 조건을 포함한 원문

#define HEAD_TEXT  KEEP(*(.head.text))

HIBERNATE_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L105–L109

앞뒤 조건을 포함한 원문

#define HIBERNATE_TEXT					\
	ALIGN_FUNCTION();				\
	__hibernate_exit_text_start = .;		\
	*(.hibernate_exit.text)				\
	__hibernate_exit_text_end = .;
arch/arm64/kernel/vmlinux.lds.S L111–L111

앞뒤 조건을 포함한 원문

#define HIBERNATE_TEXT

HYPERVISOR_DATA_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L26–L33

앞뒤 조건을 포함한 원문

#define HYPERVISOR_DATA_SECTION					\
	HYP_SECTION_NAME(.data) : {				\
		. = ALIGN(PAGE_SIZE);				\
		__hyp_data_start = .;				\
		*(HYP_SECTION_NAME(.data))			\
		. = ALIGN(PAGE_SIZE);				\
		__hyp_data_end = .;				\
	}
arch/arm64/kernel/vmlinux.lds.S L64–L64

앞뒤 조건을 포함한 원문

#define HYPERVISOR_DATA_SECTION

HYPERVISOR_EXTABLE

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L10–L14

앞뒤 조건을 포함한 원문

#define HYPERVISOR_EXTABLE					\
	. = ALIGN(SZ_8);					\
	__start___kvm_ex_table = .;				\
	*(__kvm_ex_table)					\
	__stop___kvm_ex_table = .;
arch/arm64/kernel/vmlinux.lds.S L62–L62

앞뒤 조건을 포함한 원문

#define HYPERVISOR_EXTABLE

HYPERVISOR_PERCPU_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L35–L39

앞뒤 조건을 포함한 원문

#define HYPERVISOR_PERCPU_SECTION				\
	. = ALIGN(PAGE_SIZE);					\
	HYP_SECTION_NAME(.data..percpu) : {			\
		*(HYP_SECTION_NAME(.data..percpu))		\
	}
arch/arm64/kernel/vmlinux.lds.S L65–L65

앞뒤 조건을 포함한 원문

#define HYPERVISOR_PERCPU_SECTION

HYPERVISOR_RELOC_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L41–L46

앞뒤 조건을 포함한 원문

#define HYPERVISOR_RELOC_SECTION				\
	.hyp.reloc : ALIGN(4) {					\
		__hyp_reloc_begin = .;				\
		*(.hyp.reloc)					\
		__hyp_reloc_end = .;				\
	}
arch/arm64/kernel/vmlinux.lds.S L66–L66

앞뒤 조건을 포함한 원문

#define HYPERVISOR_RELOC_SECTION

HYPERVISOR_RODATA_SECTIONS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L16–L24

앞뒤 조건을 포함한 원문

#define HYPERVISOR_RODATA_SECTIONS				\
	HYP_SECTION_NAME(.rodata) : {				\
		. = ALIGN(PAGE_SIZE);				\
		__hyp_rodata_start = .;				\
		*(HYP_SECTION_NAME(.data..ro_after_init))	\
		*(HYP_SECTION_NAME(.rodata))			\
		. = ALIGN(PAGE_SIZE);				\
		__hyp_rodata_end = .;				\
	}
arch/arm64/kernel/vmlinux.lds.S L63–L63

앞뒤 조건을 포함한 원문

#define HYPERVISOR_RODATA_SECTIONS

HYPERVISOR_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L87–L96

앞뒤 조건을 포함한 원문

#define HYPERVISOR_TEXT					\
	. = ALIGN(PAGE_SIZE);				\
	__hyp_idmap_text_start = .;			\
	*(.hyp.idmap.text)				\
	__hyp_idmap_text_end = .;			\
	__hyp_text_start = .;				\
	*(.hyp.text)					\
	HYPERVISOR_EXTABLE				\
	. = ALIGN(PAGE_SIZE);				\
	__hyp_text_end = .;

HYP_SECTION_NAME

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/include/asm/hyp_image.h L29–L29

앞뒤 조건을 포함한 원문

#define HYP_SECTION_NAME(NAME)	.hyp##NAME

IDMAP_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L98–L102

앞뒤 조건을 포함한 원문

#define IDMAP_TEXT					\
	. = ALIGN(SZ_4K);				\
	__idmap_text_start = .;				\
	*(.idmap.text)					\
	__idmap_text_end = .;

INIT_CALLS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L934–L946

앞뒤 조건을 포함한 원문

#define INIT_CALLS							\
		__initcall_start = .;					\
		KEEP(*(.initcallearly.init))				\
		INIT_CALLS_LEVEL(0)					\
		INIT_CALLS_LEVEL(1)					\
		INIT_CALLS_LEVEL(2)					\
		INIT_CALLS_LEVEL(3)					\
		INIT_CALLS_LEVEL(4)					\
		INIT_CALLS_LEVEL(5)					\
		INIT_CALLS_LEVEL(rootfs)				\
		INIT_CALLS_LEVEL(6)					\
		INIT_CALLS_LEVEL(7)					\
		__initcall_end = .;

INIT_DATA

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L705–L728

앞뒤 조건을 포함한 원문

#define INIT_DATA							\
	KEEP(*(SORT(___kentry+*)))					\
	*(.init.data .init.data.*)					\
	KERNEL_CTORS()							\
	MCOUNT_REC()							\
	*(.init.rodata .init.rodata.*)					\
	FTRACE_EVENTS()							\
	TRACE_SYSCALLS()						\
	KPROBE_BLACKLIST()						\
	ERROR_INJECT_WHITELIST()					\
	CLK_OF_TABLES()							\
	RESERVEDMEM_OF_TABLES()						\
	TIMER_OF_TABLES()						\
	CPU_METHOD_OF_TABLES()						\
	CPUIDLE_METHOD_OF_TABLES()					\
	KERNEL_DTB()							\
	IRQCHIP_OF_MATCH_TABLE()					\
	ACPI_PROBE_TABLE(irqchip)					\
	ACPI_PROBE_TABLE(timer)						\
	THERMAL_TABLE(governor)						\
	EARLYCON_TABLE()						\
	LSM_TABLE()							\
	EARLY_LSM_TABLE()						\
	KUNIT_INIT_TABLE()

INIT_RAM_FS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L974–L979

앞뒤 조건을 포함한 원문

#define INIT_RAM_FS							\
	. = ALIGN(4);							\
	__initramfs_start = .;						\
	KEEP(*(.init.ramfs))						\
	. = ALIGN(8);							\
	KEEP(*(.init.ramfs.info))
include/asm-generic/vmlinux.lds.h L981–L981

앞뒤 조건을 포함한 원문

#define INIT_RAM_FS

INIT_SETUP

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L925–L927

앞뒤 조건을 포함한 원문

#define INIT_SETUP(initsetup_align)					\
		. = ALIGN(initsetup_align);				\
		BOUNDED_SECTION_POST_LABEL(.init.setup, __setup, _start, _end)

INIT_TEXT_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L1135–L1141

앞뒤 조건을 포함한 원문

#define INIT_TEXT_SECTION(inittext_align)				\
	. = ALIGN(inittext_align);					\
	.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {		\
		_sinittext = .;						\
		INIT_TEXT						\
		_einittext = .;						\
	}

IRQENTRY_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L631–L635

앞뒤 조건을 포함한 원문

#define IRQENTRY_TEXT							\
		ALIGN_FUNCTION();					\
		__irqentry_text_start = .;				\
		*(.irqentry.text)					\
		__irqentry_text_end = .;

KEXEC_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L115–L119

앞뒤 조건을 포함한 원문

#define KEXEC_TEXT					\
	ALIGN_FUNCTION();				\
	__relocate_new_kernel_start = .;		\
	*(.kexec_relocate.text)				\
	__relocate_new_kernel_end = .;
arch/arm64/kernel/vmlinux.lds.S L121–L121

앞뒤 조건을 포함한 원문

#define KEXEC_TEXT

KPROBES_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L619–L623

앞뒤 조건을 포함한 원문

#define KPROBES_TEXT							\
		ALIGN_FUNCTION();					\
		__kprobes_text_start = .;				\
		*(.kprobes.text)					\
		__kprobes_text_end = .;

LOCK_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L613–L617

앞뒤 조건을 포함한 원문

#define LOCK_TEXT							\
		ALIGN_FUNCTION();					\
		__lock_text_start = .;					\
		*(.spinlock.text)					\
		__lock_text_end = .;

MODINFO

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L840–L841

앞뒤 조건을 포함한 원문

#define MODINFO								\
		.modinfo : { *(.modinfo) . = ALIGN(8); }

PECOFF_EDATA_PADDING

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L157–L158

앞뒤 조건을 포함한 원문

#define PECOFF_EDATA_PADDING	\
	.pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
arch/arm64/kernel/vmlinux.lds.S L160–L160

앞뒤 조건을 포함한 원문

#define PECOFF_EDATA_PADDING

PERCPU_SECTION

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L1096–L1100

앞뒤 조건을 포함한 원문

#define PERCPU_SECTION(cacheline)					\
	. = ALIGN(PAGE_SIZE);						\
	.data..percpu	: AT(ADDR(.data..percpu) - LOAD_OFFSET) {	\
		PERCPU_INPUT(cacheline)					\
	}

RO_DATA

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L461–L549

앞뒤 조건을 포함한 원문

#define RO_DATA(align)							\
	. = ALIGN((align));						\
	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
		__start_rodata = .;					\
		*(.rodata) *(.rodata.*) *(.data.rel.ro*)		\
		SCHED_DATA						\
		RO_AFTER_INIT_DATA	/* Read only after init */	\
		. = ALIGN(8);						\
		BOUNDED_SECTION_BY(__tracepoints_ptrs, ___tracepoints_ptrs) \
		*(__tracepoints_strings)/* Tracepoints: strings */	\
	}								\
									\
	.rodata1          : AT(ADDR(.rodata1) - LOAD_OFFSET) {		\
		*(.rodata1)						\
	}								\
									\
	/* PCI quirks */						\
	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_early,  _pci_fixups_early,  __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_header, _pci_fixups_header, __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_final,  _pci_fixups_final,  __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_enable, _pci_fixups_enable, __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_resume, _pci_fixups_resume, __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_suspend, _pci_fixups_suspend, __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_resume_early, _pci_fixups_resume_early, __start, __end) \
		BOUNDED_SECTION_PRE_LABEL(.pci_fixup_suspend_late, _pci_fixups_suspend_late, __start, __end) \
	}								\
									\
	FW_LOADER_BUILT_IN_DATA						\
	TRACEDATA							\
									\
	PRINTK_INDEX							\
									\
	/* Kernel symbol table: Normal symbols */			\
	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
		__start___ksymtab = .;					\
		KEEP(*(SORT(___ksymtab+*)))				\
		__stop___ksymtab = .;					\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
		__start___ksymtab_gpl = .;				\
		KEEP(*(SORT(___ksymtab_gpl+*)))				\
		__stop___ksymtab_gpl = .;				\
	}								\
									\
	/* Kernel symbol table: Normal symbols */			\
	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
		__start___kcrctab = .;					\
		KEEP(*(SORT(___kcrctab+*)))				\
		__stop___kcrctab = .;					\
	}								\
									\
	/* Kernel symbol table: GPL-only symbols */			\
	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
		__start___kcrctab_gpl = .;				\
		KEEP(*(SORT(___kcrctab_gpl+*)))				\
		__stop___kcrctab_gpl = .;				\
	}								\
									\
	/* Kernel symbol table: strings */				\
        __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
		*(__ksymtab_strings)					\
	}								\
									\
	/* __*init sections */						\
	__init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) {		\
		*(.ref.rodata)						\
	}								\
									\
	/* Built-in module parameters. */				\
	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
		BOUNDED_SECTION_BY(__param, ___param)			\
	}								\
									\
	/* Built-in module versions. */					\
	__modver : AT(ADDR(__modver) - LOAD_OFFSET) {			\
		BOUNDED_SECTION_BY(__modver, ___modver)			\
	}								\
									\
	KCFI_TRAPS							\
									\
	RO_EXCEPTION_TABLE						\
	NOTES								\
	BTF								\
									\
	. = ALIGN((align));						\
	__end_rodata = .;

RUNTIME_CONST_VARIABLES

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L958–L960

앞뒤 조건을 포함한 원문

#define RUNTIME_CONST_VARIABLES						\
		RUNTIME_CONST(shift, d_hash_shift)			\
		RUNTIME_CONST(ptr, dentry_hashtable)

RW_DATA

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L1121–L1134

앞뒤 조건을 포함한 원문

#define RW_DATA(cacheline, pagealigned, inittask)			\
	. = ALIGN(PAGE_SIZE);						\
	.data : AT(ADDR(.data) - LOAD_OFFSET) {				\
		INIT_TASK_DATA(inittask)				\
		NOSAVE_DATA						\
		PAGE_ALIGNED_DATA(pagealigned)				\
		CACHE_HOT_DATA(cacheline)				\
		CACHELINE_ALIGNED_DATA(cacheline)			\
		READ_MOSTLY_DATA(cacheline)				\
		DATA_DATA						\
		CONSTRUCTORS						\
	}								\
	BUG_TABLE							\

SCHED_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L605–L609

앞뒤 조건을 포함한 원문

#define SCHED_TEXT							\
		ALIGN_FUNCTION();					\
		__sched_text_start = .;					\
		*(.sched.text)						\
		__sched_text_end = .;

SOFTIRQENTRY_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L637–L641

앞뒤 조건을 포함한 원문

#define SOFTIRQENTRY_TEXT						\
		ALIGN_FUNCTION();					\
		__softirqentry_text_start = .;				\
		*(.softirqentry.text)					\
		__softirqentry_text_end = .;

STABS_DEBUG

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L825–L831

앞뒤 조건을 포함한 원문

#define STABS_DEBUG							\
		.stab 0 : { *(.stab) }					\
		.stabstr 0 : { *(.stabstr) }				\
		.stab.excl 0 : { *(.stab.excl) }			\
		.stab.exclstr 0 : { *(.stab.exclstr) }			\
		.stab.index 0 : { *(.stab.index) }			\
		.stab.indexstr 0 : { *(.stab.indexstr) }

TEXT_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/asm-generic/vmlinux.lds.h L591–L601

앞뒤 조건을 포함한 원문

#define TEXT_TEXT							\
		ALIGN_FUNCTION();					\
		*(.text.asan.* .text.tsan.*)				\
		*(.text.unknown .text.unknown.*)			\
		TEXT_SPLIT						\
		TEXT_UNLIKELY						\
		. = ALIGN(PAGE_SIZE);					\
		TEXT_HOT						\
		*(TEXT_MAIN .text.fixup)				\
		NOINSTR_TEXT						\
		*(.ref.text)

TRAMP_TEXT

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L125–L131

앞뒤 조건을 포함한 원문

#define TRAMP_TEXT					\
	. = ALIGN(PAGE_SIZE);				\
	__entry_tramp_text_start = .;			\
	*(.entry.tramp.text)				\
	. = ALIGN(PAGE_SIZE);				\
	__entry_tramp_text_end = .;			\
	*(.entry.tramp.rodata)
arch/arm64/kernel/vmlinux.lds.S L133–L133

앞뒤 조건을 포함한 원문

#define TRAMP_TEXT

UNWIND_DATA_SECTIONS

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/kernel/vmlinux.lds.S L137–L142

앞뒤 조건을 포함한 원문

#define UNWIND_DATA_SECTIONS				\
	.eh_frame : {					\
		__pi___eh_frame_start = .;		\
		*(.eh_frame)				\
		__pi___eh_frame_end = .;		\
	}
arch/arm64/kernel/vmlinux.lds.S L144–L144

앞뒤 조건을 포함한 원문

#define UNWIND_DATA_SECTIONS

상수·구조체 오프셋

S_*·THREAD_*·FREGS_* 등의 구조체 오프셋은 빌드한 C 구조체 배치에서 생성됩니다. 숫자를 고정하지 않고 원래 기호를 사용했습니다.

asm-offsets.c의 생성 식

맨 위로 ↑