이 파일은 왜 필요한가요?
여기서는 CPU에게 일을 시키는 명령보다, EFI 로더가 읽을 파일 설명서를 만드는 줄이 많습니다. .long이나 .short는 실행 동작이 아니라 숫자를 이미지에 써 넣는 지시문입니다. “이 이미지의 어느 위치부터 실행할까?”, “어느 범위가 코드인가?”라는 질문에 로더가 답할 수 있도록 헤더를 만듭니다.
명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.
기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고
먼저 알아둘 개념: 전처리·어셈블·링크·실행, 어셈블러 지시문, 주소와 주소가 가리키는 내용, 정렬과 경계, 매크로와 실제 CPU 명령
처음 읽을 때
코드처럼 생긴 파일이라도 모든 줄을 CPU가 실행하는 것은 아닙니다. .long을 볼 때는 파일 안에 4바이트 칸 하나를 만든다고 생각해 보세요.
더 깊이 살펴볼 때
PE의 파일 오프셋, RVA, ELF 섹션, 런타임 VA는 서로 다른 좌표계입니다. 디버그 디렉터리를 왜 .init.rodata로 옮기는지 이 차이로 설명할 수 있습니다.
한 줄씩 레지스터와 메모리 상태 보기
각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.
소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.
일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.
화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.
‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.
총 133개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.
먼저 그림으로 살펴보기
MZ 서명인 첫 명령
#include <linux/pe.h>UEFI가 읽을 PE/COFF 헤더의 서명, ARM64 기계 종류, 섹션 속성 같은 상수를 가져옵니다. 이 파일의 .long·.short는 대부분 CPU 명령이 아니라 로더에게 제공할 헤더 필드를 만드는 데 사용됩니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
7행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <linux/sizes.h>SZ_64K처럼 바이트 크기를 나타내는 상수를 가져옵니다. 이미지 섹션과 헤더의 정렬 크기를 읽을 때 단위를 분명하게 하기 위한 정의입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
8행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.macro efi_signature_nop커널 이미지 첫 명령을 만들 때 쓰는 매크로입니다. EFI 지원 이미지이면 명령 바이트의 시작이 MZ 서명이 되게 하고, 미지원 이미지이면 보통 NOP를 둡니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
10행 그림 · 어셈블·링크 단계
매크로 본문: efi_signature_nop
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
#ifdef CONFIG_EFICONFIG_EFI는 ARM64 커널의 UEFI 부팅·인터페이스 지원 설정이며 EFI stub도 선택합니다. 이 설정이 켜진 이미지에는 UEFI 로더가 알아볼 MZ 서명을 첫 명령 바이트에 넣습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
11행 그림 · 전처리 단계
매크로 본문: efi_signature_nop
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.L_head:이미지 헤더 시작 주소를 표시합니다. 뒤의 PE 필드들이 사용하는 RVA는 이 시작에서 얼마 떨어졌는지로 계산합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
12행 그림 · 위치에 이름 붙이기
매크로 본문: efi_signature_nop
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ccmp x18, #0, #0xd, pl이 CCMP의 기계어 바이트가 MZ로 시작하도록 명령을 골랐습니다. 부팅 흐름에서는 의미 있는 계산 결과로 사용하지 않으며, 핵심 목적은 같은 바이트를 UEFI가 실행 파일 서명으로 인식하게 하는 것입니다. 실행하면 PL 조건(N=0)일 때 x18과 0을 비교해 NZCV를 갱신하고, 조건이 거짓이면 NZCV에 즉시값 0xd를 넣습니다. x18 자체는 바꾸지 않습니다.
17행 그림 · 조건에 따른 플래그 갱신
매크로 본문: efi_signature_nop
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 efi_signature_nop의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
#elseEFI를 지원하지 않는 빌드에서 사용할 첫 명령을 선택하는 분기입니다. UEFI 부팅 가능 이미지라는 MZ 표시를 넣지 않습니다.
18행 그림 · 전처리 단계
매크로 본문: efi_signature_nop
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
nopEFI 미지원 이미지의 첫 명령에 일반 NOP를 넣습니다. 이미지 시작 바이트로 EFI 부팅 가능 여부를 검사하는 부트로더가 잘못 판단하지 않도록 합니다.
24행 그림 · 동기화·캐시·대기 상태
매크로 본문: efi_signature_nop
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 efi_signature_nop의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
#endifEFI 지원 여부에 따른 첫 명령 선택을 마칩니다.
25행 그림 · 전처리 단계
매크로 본문: efi_signature_nop
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
26행 그림 · 어셈블·링크 단계
매크로 본문: efi_signature_nop
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
PE 파일 헤더와 선택 헤더
.macro __EFI_PE_HEADERUEFI가 ARM64 커널을 실행 파일로 적재하는 데 필요한 PE/COFF 헤더와 섹션표를 내보내는 매크로입니다. 헤더의 숫자들은 실행 중 계산되는 값이 아니라 조립·링크 단계에서 이미지에 기록됩니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
28행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
#ifdef CONFIG_EFICONFIG_EFI가 켜진 경우에만 실제 PE/COFF 헤더를 만듭니다. 꺼진 빌드는 아래 else에서 PE 헤더 오프셋을 0으로 설정합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
29행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.set .Lpe_header_offset, . - .L_head이미지 시작 .L_head에서 현재 PE 헤더까지의 바이트 거리를 계산합니다. Image 헤더가 이 값을 통해 PE 헤더 위치를 알려줄 수 있게 합니다. 이름에 식의 값을 부여하는 어셈블러 지시문입니다. 실행 중 일반 레지스터나 메모리에 값을 쓰는 명령은 아닙니다.
30행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_NT_SIGNATURE이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. PE 파일 서명인 PE와 두 NUL 바이트(0x00004550)를 기록합니다. 로더가 뒤의 바이트를 PE/COFF 헤더로 해석하는 기준입니다.
31행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short IMAGE_FILE_MACHINE_ARM64 // Machine이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 대상 CPU 종류를 ARM64(0xaa64)로 기록합니다. UEFI 로더가 이 실행 이미지의 명령어 아키텍처를 구분합니다.
32행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short .Lsection_count // NumberOfSections이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 뒤에서 계산할 PE 섹션 개수를 기록합니다. 이 파일에서는 .text와 .data 두 섹션의 설명이 이어집니다.
33행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // TimeDateStamp이 .long은 CPU 명령이 아니라 어셈블러에게 4바이트 정수 데이터를 내보내도록 하는 지시문입니다. 상수 0은 어셈블 단계에서 바로 00 00 00 00으로 기록됩니다. 이 자리는 COFF TimeDateStamp 필드이며, 이 이미지에서는 빌드 시각을 넣지 않습니다.
34행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // PointerToSymbolTable이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. COFF 심볼표의 파일 위치를 0으로 기록합니다. 이 부팅 이미지에 별도의 COFF 심볼표를 제공하지 않는다는 뜻입니다.
35행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // NumberOfSymbols이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. COFF 심볼표의 항목 수도 0으로 기록하여 앞의 심볼표 위치 0과 맞춥니다.
36행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short .Lsection_table - .Loptional_header // SizeOfOptionalHeader이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. optional header 시작부터 섹션표 직전까지의 크기를 기록합니다. 로더는 이 길이를 사용해 섹션표가 시작하는 위치를 찾습니다.
37행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short IMAGE_FILE_DEBUG_STRIPPED | \이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. COFF Characteristics 비트 조합의 첫 부분입니다. IMAGE_FILE_DEBUG_STRIPPED로 COFF 디버그 정보가 제거된 이미지임을 표시합니다. 아래의 선택적 PE 디버그 디렉터리와는 구분되는 필드입니다.
38행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
IMAGE_FILE_EXECUTABLE_IMAGE | \같은 Characteristics 필드에 EXECUTABLE_IMAGE 비트를 더하여 실행 가능한 이미지임을 표시합니다. 앞줄에서 시작한 식이나 매크로 인자에 이어지는 부분입니다. |로 연결한 비트들은 하나의 값으로 합쳐집니다.
39행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
IMAGE_FILE_LINE_NUMS_STRIPPED // CharacteristicsLINE_NUMS_STRIPPED 비트까지 합쳐 COFF 소스 줄 번호 정보가 없음을 표시합니다. 세 줄은 각각 별도 필드가 아니라 OR로 합쳐진 하나의 16비트 필드를 만듭니다.
40행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
.Loptional_header:PE optional header의 시작 위치입니다. 이름과 달리 실행 이미지의 적재 주소·크기·진입점 등 핵심 정보가 이 영역에 들어갑니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
42행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC // PE32+ format이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 64비트 PE32+ 형식을 나타내는 0x020b를 기록합니다. 로더가 이후 필드의 크기와 배치를 이 형식으로 해석하게 합니다.
43행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.byte 0x02 // MajorLinkerVersion이 .byte은 실행 명령이 아니라 어셈블 단계에서 상수를 1바이트 정수로 기록하는 지시문입니다. PE MajorLinkerVersion 필드에 이 헤더가 정한 0x02를 기록합니다. Linux 커널의 주 버전 6을 의미하는 값은 아닙니다.
44행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.byte 0x14 // MinorLinkerVersion이 .byte은 실행 명령이 아니라 어셈블 단계에서 상수를 1바이트 정수로 기록하는 지시문입니다. PE MinorLinkerVersion 필드에 0x14를 기록합니다. 바로 앞 값과 함께 헤더 형식상 링커 버전 필드를 채우며 Linux의 6.18.37 표시는 아닙니다.
45행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __initdata_begin - .Lefi_header_end // SizeOfCode이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. PE의 코드 크기를 헤더 끝부터 __initdata_begin 전까지의 길이로 기록합니다. 뒤의 .text 섹션이 차지하는 범위와 맞춘 값입니다.
46행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __pecoff_data_size // SizeOfInitializedData이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. 링커가 계산한 PE 데이터 영역의 메모리 크기를 기록합니다. 원본 파일의 데이터 바이트 수와 메모리에 필요한 크기는 뒤의 .data 섹션에서 별도 필드로 구분합니다.
47행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // SizeOfUninitializedData이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 별도 uninitialized-data 크기 필드는 0으로 둡니다. 뒤의 .data VirtualSize와 SizeOfRawData 차이로 파일에 없는 메모리 영역을 포함하므로 커널 전체에 BSS가 없다는 뜻은 아닙니다.
48행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __efistub_efi_pe_entry - .L_head // AddressOfEntryPoint이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. UEFI가 처음 호출할 EFI stub의 efi_pe_entry 위치를 이미지 시작 기준 RVA로 기록합니다. 일반 부트로더가 Image의 첫 명령으로 들어오는 경로와 진입 방식이 다릅니다.
49행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_header_end - .L_head // BaseOfCode이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 코드 영역이 시작하는 헤더 끝의 위치를 이미지 시작 기준 오프셋으로 기록합니다.
50행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // ImageBase이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE ImageBase 필드를 0으로 둡니다. 실제 적재 위치를 여기의 고정 가상 주소로 요구하지 않으며 각 위치는 이미지 기준 오프셋으로 표현합니다.
52행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long SEGMENT_ALIGN // SectionAlignment이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 메모리에 적재할 PE 섹션의 정렬을 SEGMENT_ALIGN, 즉 이 버전 ARM64에서는 64KiB로 지정합니다. 커널의 기본 페이지 크기를 선택하는 필드가 아닙니다.
53행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long PECOFF_FILE_ALIGNMENT // FileAlignment이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 파일 안의 섹션 데이터 정렬을 PECOFF_FILE_ALIGNMENT인 512바이트로 기록합니다. 앞의 메모리 섹션 정렬과 서로 다른 조건입니다.
54행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MajorOperatingSystemVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 요구 운영체제 주 버전 필드를 0으로 둡니다. UEFI 부팅용 이미지에서 특정 Windows 버전을 요구하는 값으로 사용하지 않습니다.
55행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MinorOperatingSystemVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 요구 운영체제 부 버전 필드도 0으로 둡니다.
56행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. Linux EFI stub 인터페이스의 주 버전값 3을 기록합니다. 이 버전부터는 비트마스크로도 해석되어 initrd의 EFI 장치 경로 제공과 initrd= 장치 경로 지정 기능 지원을 나타냅니다. Linux 커널 버전 6.18.37과는 별개입니다.
57행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. EFI stub 인터페이스의 부 버전은 0으로 기록합니다. include/linux/pe.h는 이 필드를 0으로 유지하도록 정의합니다.
58행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MajorSubsystemVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 요구 subsystem 주 버전 필드를 0으로 둡니다. 뒤의 Subsystem 종류 필드는 별도로 EFI application을 지정합니다.
59행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MinorSubsystemVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 요구 subsystem 부 버전 필드도 0으로 둡니다.
60행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Win32VersionValue이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. PE의 예약된 Win32VersionValue 필드를 0으로 채웁니다.
61행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long _end - .L_head // SizeOfImage이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. 이미지 시작부터 _end까지의 전체 메모리 크기를 기록합니다. 로더는 코드와 데이터뿐 아니라 파일에 모두 들어 있지 않은 메모리 공간까지 고려해야 합니다.
63행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_header_end - .L_head // SizeOfHeaders이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 이미지 시작부터 실제 코드 앞까지의 길이를 헤더 전체 크기로 기록합니다. 정렬 때문에 추가된 헤더 뒤 패딩도 이 범위에 포함됩니다.
66행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // CheckSum이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. PE CheckSum 필드는 0으로 둡니다. 이 필드가 0이라는 사실만으로 Secure Boot 서명 검사 여부를 판단할 수는 없습니다.
67행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. Subsystem을 EFI_APPLICATION으로 지정합니다. UEFI는 이 커널 이미지의 EFI stub을 EFI 응용 프로그램 진입 규약으로 실행합니다.
68행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short IMAGE_DLLCHARACTERISTICS_NX_COMPAT // DllCharacteristics이 .short은 CPU 명령이 아니라 빌드할 때 값을 2바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. NX_COMPAT를 표시하여 실행 불가 메모리 보호와 양립하는 이미지임을 알립니다. 이 헤더 비트 자체가 ARM의 실행 금지 비트를 하드웨어에 설정하는 명령은 아닙니다.
69행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // SizeOfStackReserve이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE의 스택 예약 크기를 0으로 기록합니다. 이 필드는 Linux 태스크의 THREAD_SIZE를 지정하는 곳이 아닙니다.
70행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // SizeOfStackCommit이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE의 초기 스택 commit 크기도 0으로 기록합니다. 실제 커널 스택 구성은 부팅과 태스크 초기화 코드가 담당합니다.
71행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // SizeOfHeapReserve이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE의 힙 예약 크기를 0으로 기록합니다. Linux의 커널 메모리 할당기 용량을 여기서 정하지 않습니다.
72행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // SizeOfHeapCommit이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE의 초기 힙 commit 크기도 0으로 기록합니다.
73행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // LoaderFlags이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 예약된 LoaderFlags 필드를 0으로 채웁니다.
74행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long (.Lsection_table - .) / 8 // NumberOfRvaAndSizes이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 이 위치 뒤부터 섹션표 전까지의 길이를 8로 나눠 data directory 항목 수를 기록합니다. 각 항목이 32비트 위치와 32비트 크기로 이루어지므로 8바이트 단위입니다.
75행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // ExportTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. 내보내기 테이블의 위치·크기를 모두 0으로 둡니다. 이 EFI 부팅 이미지에서 PE export table을 제공하지 않습니다.
77행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // ImportTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. 가져오기 테이블도 비워 둡니다. UEFI 서비스는 PE DLL import 방식으로 연결하는 것이 아니라 펌웨어가 전달한 인터페이스를 사용합니다.
78행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // ResourceTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE resource table은 제공하지 않으므로 위치와 크기를 0으로 기록합니다.
79행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // ExceptionTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE exception directory 항목을 비워 둡니다. 이는 ARM 예외 벡터가 없다는 뜻이 아니라 PE 형식의 해당 메타데이터를 제공하지 않는다는 뜻입니다.
80행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // CertificationTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. 원본 이미지의 인증서 테이블 항목을 0으로 둡니다. 이후 별도의 이미지 서명 도구가 추가하는 인증서 정보와 구분해야 합니다.
81행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.quad 0 // BaseRelocationTable이 .quad은 실행 명령이 아니라 어셈블 단계에서 상수를 8바이트 정수로 기록하는 지시문입니다. PE base relocation directory는 제공하지 않습니다. Linux 커널 자체의 재배치 처리 유무는 별도 코드와 설정에 따르며 이 항목만으로 결정되지 않습니다.
82행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
디버그 디렉터리
#if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)CONFIG_DEBUG_EFI는 디버그 UEFI에서 사용할 이미지 디버그 정보를 넣는 설정입니다. CONFIG_ARM64_BTI_KERNEL은 커널의 간접 분기 도착점을 검사하는 BTI 지원 설정입니다. 둘 중 하나라도 켜면 PE debug directory를 만들어, 전자는 심볼 파일 위치를, 후자는 BTI 호환 특성을 전달합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
84행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_debug_table - .L_head // DebugTable이 .long은 CPU가 실행할 뺄셈 명령이 아니라 4바이트 정수 필드를 만드는 어셈블러 지시문입니다. .L_head는 이미지 시작점이고 .Lefi_debug_table은 디버그 디렉터리의 위치입니다. 디렉터리가 별도의 .init.rodata에 있으므로, 링크로 섹션 배치가 정해질 때 두 위치의 차이를 계산해 PE 헤더의 DebugTable RVA로 채웁니다. 부팅할 때 로더는 이미 기록된 이 오프셋을 읽어 디렉터리를 찾습니다.
85행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_debug_table_size이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 조건에 따라 생성한 debug directory 전체 크기를 기록합니다. DEBUG_EFI와 BTI 중 무엇을 켰는지에 따라 들어가는 항목 수가 달라집니다.
86행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
__INITRODATA디버그 디렉터리를 .init.rodata에 배치하도록 섹션을 바꿉니다. RVA로 참조되는 데이터는 PE 섹션이 덮는 범위에 있어야 하는데 헤더 자체는 섹션으로 선언되지 않기 때문입니다. 이는 빌드 중 출력할 바이트의 섹션을 선택하는 지시문이며, 실행 중 PC나 SP를 옮기지 않습니다.
98행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.align 2디버그 디렉터리를 4바이트 경계에 맞춥니다. 이곳의 .align 2는 2바이트가 아니라 2의 2승 바이트 정렬입니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.
100행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.Lefi_debug_table:PE data directory에서 가리킬 디버그 디렉터리 시작입니다. 아래 설정에 따라 CodeView 항목과 확장 이미지 특성 항목이 들어갑니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
101행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#ifdef CONFIG_DEBUG_EFI디버그 정보를 포함한 EFI 빌드에서 CodeView 항목을 추가합니다. CONFIG_DEBUG_EFI는 EFI와 DEBUG_INFO에 의존하며, 디버그 펌웨어에서 vmlinux 심볼을 찾는 데 필요한 메타데이터를 제공합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
102행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Characteristics이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. CodeView 디버그 디렉터리 항목의 Characteristics는 0으로 둡니다. 선택적 속성을 추가하지 않습니다.
104행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // TimeDateStamp이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 이 디버그 항목의 타임스탬프를 0으로 기록합니다.
105행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MajorVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. CodeView 디렉터리 항목의 주 버전을 0으로 기록합니다.
106행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MinorVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. CodeView 디렉터리 항목의 부 버전을 0으로 기록합니다.
107행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_DEBUG_TYPE_CODEVIEW // Type이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 디버그 정보 종류를 CodeView로 지정합니다. 뒤의 NB10 payload와 vmlinux 경로를 이 형식으로 해석하게 합니다.
108행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_debug_entry_size // SizeOfData이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 뒤에 배치할 CodeView payload의 전체 바이트 크기를 기록합니다.
109행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // RVA이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. CodeView payload의 RVA는 0으로 둡니다. payload는 PE 섹션 바깥 헤더 뒤에 놓을 수 있으며 다음 FileOffset 필드로 파일에서 찾습니다.
110행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_debug_entry - .L_head // FileOffset이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 이미지 파일 시작부터 CodeView payload까지의 위치를 기록합니다. 메모리 RVA 대신 파일 오프셋으로 해당 데이터를 찾게 합니다.
111행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifDEBUG_EFI가 추가하는 CodeView 디렉터리 항목을 마칩니다. BTI용 항목은 별도 조건으로 이어집니다.
112행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#ifdef CONFIG_ARM64_BTI_KERNEL커널 BTI 설정이 켜졌으면 확장 이미지 특성을 알리는 디렉터리 항목을 추가합니다. BTI는 간접 분기가 허용된 명령 위치에 도착하는지 검사하는 기능입니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
113행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Characteristics이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 확장 이미지 특성 디렉터리의 Characteristics 필드를 0으로 둡니다.
114행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // TimeDateStamp이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 이 확장 특성 항목의 타임스탬프를 0으로 기록합니다.
115행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MajorVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 확장 특성 디렉터리의 주 버전을 0으로 기록합니다.
116행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // MinorVersion이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. 확장 특성 디렉터리의 부 버전을 0으로 기록합니다.
117행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS // Type이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 디버그 디렉터리의 Type을 EX_DLLCHARACTERISTICS로 지정합니다. 아래 payload는 디버그 심볼 경로가 아니라 확장 이미지 호환 플래그로 해석됩니다.
118행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 4 // SizeOfData이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 확장 이미지 특성 payload의 길이는 32비트 플래그 하나이므로 4바이트입니다.
119행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // RVA이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 확장 특성 payload 역시 RVA를 0으로 두고 다음 파일 오프셋으로 참조합니다.
120행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_dll_characteristics_ex - .L_head // FileOffset이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 헤더 뒤에 놓일 확장 특성 플래그의 파일 위치를 기록합니다.
121행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifBTI 설정에 따른 확장 특성 디렉터리 항목을 마칩니다.
122행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.set .Lefi_debug_table_size, . - .Lefi_debug_table실제로 생성한 디렉터리 시작부터 현재 위치까지의 차이를 크기로 계산합니다. 앞의 data directory 크기 필드는 이 값을 사용합니다. 이름에 식의 값을 부여하는 어셈블러 지시문입니다. 실행 중 일반 레지스터나 메모리에 값을 쓰는 명령은 아닙니다.
123행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.previous디버그 디렉터리를 만들기 전의 헤더 섹션으로 돌아갑니다. 이후 섹션표와 payload는 다시 이미지 헤더 쪽에 이어 붙습니다. 이는 빌드 중 출력할 바이트의 섹션을 선택하는 지시문이며, 실행 중 PC나 SP를 옮기지 않습니다.
124행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifDEBUG_EFI 또는 BTI 때문에 추가한 디버그 디렉터리 생성을 마칩니다.
125행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
두 섹션의 크기와 권한
.Lsection_table:PE 섹션표 시작입니다. 각 섹션 항목은 40바이트이며, 로더에게 파일 범위·메모리 범위와 접근 속성을 알려줍니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
128행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.ascii ".text\0\0\0"첫 PE 섹션 이름을 .text로 기록하고 8바이트 이름 필드의 나머지를 NUL로 채웁니다. .ascii는 문자열 끝에 NUL을 자동으로 붙이지 않으므로, 소스에 쓴 \0만 실제 0바이트로 들어갑니다.
129행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __initdata_begin - .Lefi_header_end // VirtualSize이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. PE .text 섹션이 메모리에서 차지할 크기를 헤더 끝부터 __initdata_begin 직전까지로 지정합니다.
130행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_header_end - .L_head // VirtualAddress이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. PE .text 섹션의 이미지 기준 시작 위치를 기록합니다.
131행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __initdata_begin - .Lefi_header_end // SizeOfRawData이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. 파일에서 가져올 .text 데이터 크기를 기록합니다. 이 섹션에서는 위의 메모리 크기와 같은 식을 사용합니다.
132행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long .Lefi_header_end - .L_head // PointerToRawData이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. 파일에서 .text 바이트가 시작하는 위치를 기록합니다. 이 이미지 배치에서는 RVA와 파일 오프셋이 같은 식으로 계산됩니다.
133행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // PointerToRelocations이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. 이 PE .text 섹션에는 별도 COFF relocation 목록을 두지 않으므로 그 파일 위치를 0으로 둡니다.
135행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // PointerToLineNumbers이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. PE .text의 COFF 줄 번호 테이블 위치를 0으로 둡니다. 설명 페이지의 소스 줄 번호와는 무관한 파일 형식 필드입니다.
136행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // NumberOfRelocations이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. PE .text의 COFF relocation 항목 개수를 0으로 기록합니다.
137행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // NumberOfLineNumbers이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. PE .text의 COFF 줄 번호 항목 개수도 0으로 기록합니다.
138행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_SCN_CNT_CODE | \이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. PE .text의 속성에 코드 포함(CNT_CODE) 비트를 넣습니다. 이어지는 두 줄과 OR로 합쳐 하나의 32비트 필드를 만듭니다.
139행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
IMAGE_SCN_MEM_READ | \같은 .text 속성에 읽기 허용을 추가합니다. 앞줄에서 시작한 식이나 매크로 인자에 이어지는 부분입니다. |로 연결한 비트들은 하나의 값으로 합쳐집니다.
140행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
IMAGE_SCN_MEM_EXECUTE // Characteristics같은 .text 속성에 실행 허용을 추가합니다. 이 조합에는 쓰기 허용 비트가 포함되지 않습니다. 앞줄에서 시작한 식이나 매크로 인자에 이어지는 부분입니다. |로 연결한 비트들은 하나의 값으로 합쳐집니다.
141행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
.ascii ".data\0\0\0"두 번째 PE 섹션 이름을 .data로 기록하고 나머지 이름 필드를 NUL로 채웁니다. .ascii는 문자열 끝에 NUL을 자동으로 붙이지 않으므로, 소스에 쓴 \0만 실제 0바이트로 들어갑니다.
143행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __pecoff_data_size // VirtualSize이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. PE .data가 메모리에서 차지하는 전체 크기를 기록합니다. 파일에서 읽어 올 데이터보다 클 수 있으므로 SizeOfRawData와 따로 둡니다.
144행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __initdata_begin - .L_head // VirtualAddress이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. __initdata_begin을 .data 섹션의 이미지 기준 시작 위치로 기록합니다.
145행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __pecoff_data_rawsize // SizeOfRawData이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. PE .data에 대해 실제 파일에 들어 있는 바이트 수를 기록합니다. 메모리에만 필요한 뒤쪽 공간은 VirtualSize와 구분됩니다.
146행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long __initdata_begin - .L_head // PointerToRawData이 .long은 4바이트 데이터 필드를 만드는 지시문입니다. 식에 필요한 심벌 값은 링크 단계에서 확정되어 이 필드에 들어가며, 부팅 중 CPU가 이 식을 명령으로 계산하지 않습니다. 파일에서 .data를 읽어 올 시작 오프셋을 기록합니다.
147행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // PointerToRelocations이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. PE .data의 별도 COFF relocation 목록 위치를 0으로 둡니다.
149행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // PointerToLineNumbers이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. PE .data의 COFF 줄 번호 테이블 위치도 0으로 둡니다.
150행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // NumberOfRelocations이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. PE .data의 COFF relocation 항목 개수를 0으로 기록합니다.
151행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.short 0 // NumberOfLineNumbers이 .short은 실행 명령이 아니라 어셈블 단계에서 상수를 2바이트 정수로 기록하는 지시문입니다. PE .data의 COFF 줄 번호 항목 개수도 0으로 기록합니다.
152행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. PE .data의 속성에 초기화 데이터 포함 비트를 넣습니다. 뒤의 읽기·쓰기 비트와 합쳐 한 필드를 만듭니다.
153행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
IMAGE_SCN_MEM_READ | \PE .data를 읽을 수 있음을 표시합니다. 앞줄에서 시작한 식이나 매크로 인자에 이어지는 부분입니다. |로 연결한 비트들은 하나의 값으로 합쳐집니다.
154행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
IMAGE_SCN_MEM_WRITE // CharacteristicsPE .data에 쓰기 허용을 추가합니다. 이 조합에는 실행 허용 비트가 없어 .text와 다른 적재 권한을 표현합니다. 앞줄에서 시작한 식이나 매크로 인자에 이어지는 부분입니다. |로 연결한 비트들은 하나의 값으로 합쳐집니다.
155행 그림 · 앞줄에서 이어지는 인수
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 별도의 CPU 명령이 아니라 앞줄의 비트 조합이나 매크로 인자에 이어지는 줄입니다.
.set .Lsection_count, (. - .Lsection_table) / 40섹션표 전체 바이트 수를 항목 크기 40으로 나눠 섹션 개수를 계산합니다. 위에서 .text와 .data 두 항목을 만들었으므로 결과는 2입니다. 이름에 식의 값을 부여하는 어셈블러 지시문입니다. 실행 중 일반 레지스터나 메모리에 값을 쓰는 명령은 아닙니다.
157행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
부가 데이터와 헤더 끝
#ifdef CONFIG_DEBUG_EFIDEBUG_EFI가 켜졌을 때 디렉터리가 가리킬 CodeView payload를 만듭니다. 디렉터리 구조 자체와 그 구조가 가리키는 데이터의 위치는 서로 다릅니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
159행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.Lefi_debug_entry:CodeView 디버그 payload의 시작 주소입니다. 앞의 SizeOfData와 FileOffset은 이 위치와 크기를 사용합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
160행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.ascii "NB10" // SignatureCodeView의 NB10 형식을 나타내는 네 문자 서명을 넣습니다. 뒤에 붙는 필드와 파일 경로를 해당 형식의 데이터로 알아보게 합니다. .ascii는 문자열 끝에 NUL을 자동으로 붙이지 않으므로, 소스에 쓴 \0만 실제 0바이트로 들어갑니다.
162행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Unknown이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. NB10 payload의 이 32비트 필드를 0으로 채웁니다. 원문에서 Unknown으로 표시한 자리이며 vmlinux 경로는 뒤의 ASCIZ에 들어갑니다.
163행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Unknown2이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. NB10 payload의 두 번째 추가 32비트 필드도 0으로 채웁니다.
164행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long 0 // Unknown3이 .long은 실행 명령이 아니라 어셈블 단계에서 상수를 4바이트 정수로 기록하는 지시문입니다. NB10 payload의 세 번째 추가 32비트 필드도 0으로 채워 경로 문자열 앞의 고정 크기 영역을 완성합니다.
165행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.asciz VMLINUX_PATH빌드 시 정해진 vmlinux의 절대 경로를 NUL 종료 문자열로 넣습니다. 디버그 펌웨어가 심볼 파일 위치를 찾도록 제공하는 정보이며 실행 중 커널이 이 경로의 파일을 여는 명령은 아닙니다.
167행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.set .Lefi_debug_entry_size, . - .Lefi_debug_entryNB10 서명·고정 필드·경로 문자열을 포함한 payload 크기를 계산합니다. 앞의 CodeView 디렉터리 SizeOfData에 들어갈 값입니다. 이름에 식의 값을 부여하는 어셈블러 지시문입니다. 실행 중 일반 레지스터나 메모리에 값을 쓰는 명령은 아닙니다.
169행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifDEBUG_EFI용 CodeView payload 생성을 마칩니다.
170행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_DEBUG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#ifdef CONFIG_ARM64_BTI_KERNEL커널 BTI 설정이 켜졌을 때 확장 이미지 특성 payload를 만듭니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
171행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.Lefi_dll_characteristics_ex:앞의 EX_DLLCHARACTERISTICS 디렉터리가 파일 오프셋으로 가리킬 플래그 위치입니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
172행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.long IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT이 .long은 CPU 명령이 아니라 빌드할 때 값을 4바이트 정수로 기록하는 지시문입니다. 어셈블러가 확정할 수 있는 상수·같은 섹션 안의 차이는 어셈블 단계에서 계산합니다. FORWARD_CFI_COMPAT 비트를 기록하여 간접 분기 보호와 호환되는 이미지임을 로더에 알립니다. 여기서는 BTI 지원 빌드가 이 표시를 제공하며, 플래그를 기록하는 것 자체가 CPU의 BTI 검사를 켜는 명령은 아닙니다.
173행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifBTI용 확장 특성 payload 생성을 마칩니다.
174행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI / #ifdef CONFIG_ARM64_BTI_KERNEL
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.balign SEGMENT_ALIGN헤더 끝을 SEGMENT_ALIGN인 64KiB 경계까지 정렬합니다. 앞서 선언한 .text 시작 위치와 섹션 정렬 조건을 실제 바이트 배치로 맞추는 단계입니다. .balign의 인자는 바이트 단위의 정렬 크기이며, 어셈블 단계에서 필요한 패딩을 넣습니다.
176행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.Lefi_header_end:PE 헤더와 패딩이 끝나고 코드 영역이 시작하는 위치입니다. 코드 크기·BaseOfCode·SizeOfHeaders 등의 계산이 이 라벨을 기준으로 합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.
177행 그림 · 위치에 이름 붙이기
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#elseCONFIG_EFI를 끈 이미지의 처리입니다. 위의 PE/COFF 헤더와 선택적 디버그 데이터를 만들지 않습니다.
178행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: #ifdef CONFIG_EFI
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.set .Lpe_header_offset, 0x0PE 헤더 오프셋을 0으로 정의하여 이 이미지에 EFI용 PE 헤더가 없음을 나타냅니다. 이름에 식의 값을 부여하는 어셈블러 지시문입니다. 실행 중 일반 레지스터나 메모리에 값을 쓰는 명령은 아닙니다.
179행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endifEFI 지원 여부에 따른 헤더 생성 분기를 마칩니다.
180행 그림 · 전처리 단계
매크로 본문: __EFI_PE_HEADER
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
181행 그림 · 어셈블·링크 단계
매크로 본문: __EFI_PE_HEADER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
설명한 뒤 함께 생각해 볼 질문
Image 앞 64바이트가 PE 헤더 전체인가요?
공통 Image 헤더 뒤에 추가 PE/COFF 데이터가 이어집니다. 두 범위의 길이를 합쳐서 읽어야 합니다.
MZ 서명은 그냥 문자열인가요?
이 위치는 CPU 명령으로도 읽힙니다. EFI 구성에서는 CCMP 명령의 바이트가 MZ 서명을 이루도록 사용합니다.
EFI 진입점과 primary_entry는 같은가요?
EFI 로더는 헤더의 __efistub_efi_pe_entry를 사용합니다. 일반 Image 시작의 B primary_entry와 구분됩니다.
주석을 포함한 전체 원문
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3* Copyright (C) 2013 - 2017 Linaro, Ltd.4* Copyright (C) 2013, 2014 Red Hat, Inc.5*/67#include <linux/pe.h>8#include <linux/sizes.h>910.macro efi_signature_nop11#ifdef CONFIG_EFI12.L_head:13/*14* This ccmp instruction has no meaningful effect except that15* its opcode forms the magic "MZ" signature required by UEFI.16*/17ccmp x18, #0, #0xd, pl18#else19/*20* Bootloaders may inspect the opcode at the start of the kernel21* image to decide if the kernel is capable of booting via UEFI.22* So put an ordinary NOP here, not the "MZ.." pseudo-nop above.23*/24nop25#endif26.endm2728.macro __EFI_PE_HEADER29#ifdef CONFIG_EFI30.set .Lpe_header_offset, . - .L_head31.long IMAGE_NT_SIGNATURE32.short IMAGE_FILE_MACHINE_ARM64 // Machine33.short .Lsection_count // NumberOfSections34.long 0 // TimeDateStamp35.long 0 // PointerToSymbolTable36.long 0 // NumberOfSymbols37.short .Lsection_table - .Loptional_header // SizeOfOptionalHeader38.short IMAGE_FILE_DEBUG_STRIPPED | \39IMAGE_FILE_EXECUTABLE_IMAGE | \40IMAGE_FILE_LINE_NUMS_STRIPPED // Characteristics4142.Loptional_header:43.short IMAGE_NT_OPTIONAL_HDR64_MAGIC // PE32+ format44.byte 0x02 // MajorLinkerVersion45.byte 0x14 // MinorLinkerVersion46.long __initdata_begin - .Lefi_header_end // SizeOfCode47.long __pecoff_data_size // SizeOfInitializedData48.long 0 // SizeOfUninitializedData49.long __efistub_efi_pe_entry - .L_head // AddressOfEntryPoint50.long .Lefi_header_end - .L_head // BaseOfCode5152.quad 0 // ImageBase53.long SEGMENT_ALIGN // SectionAlignment54.long PECOFF_FILE_ALIGNMENT // FileAlignment55.short 0 // MajorOperatingSystemVersion56.short 0 // MinorOperatingSystemVersion57.short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion58.short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion59.short 0 // MajorSubsystemVersion60.short 0 // MinorSubsystemVersion61.long 0 // Win32VersionValue6263.long _end - .L_head // SizeOfImage6465// Everything before the kernel image is considered part of the header66.long .Lefi_header_end - .L_head // SizeOfHeaders67.long 0 // CheckSum68.short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem69.short IMAGE_DLLCHARACTERISTICS_NX_COMPAT // DllCharacteristics70.quad 0 // SizeOfStackReserve71.quad 0 // SizeOfStackCommit72.quad 0 // SizeOfHeapReserve73.quad 0 // SizeOfHeapCommit74.long 0 // LoaderFlags75.long (.Lsection_table - .) / 8 // NumberOfRvaAndSizes7677.quad 0 // ExportTable78.quad 0 // ImportTable79.quad 0 // ResourceTable80.quad 0 // ExceptionTable81.quad 0 // CertificationTable82.quad 0 // BaseRelocationTable8384#if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)85.long .Lefi_debug_table - .L_head // DebugTable86.long .Lefi_debug_table_size8788/*89* The debug table is referenced via its Relative Virtual Address (RVA),90* which is only defined for those parts of the image that are covered91* by a section declaration. Since this header is not covered by any92* section, the debug table must be emitted elsewhere. So stick it in93* the .init.rodata section instead.94*95* Note that the payloads themselves are permitted to have zero RVAs,96* which means we can simply put those right after the section headers.97*/98__INITRODATA99100.align 2101.Lefi_debug_table:102#ifdef CONFIG_DEBUG_EFI103// EFI_IMAGE_DEBUG_DIRECTORY_ENTRY104.long 0 // Characteristics105.long 0 // TimeDateStamp106.short 0 // MajorVersion107.short 0 // MinorVersion108.long IMAGE_DEBUG_TYPE_CODEVIEW // Type109.long .Lefi_debug_entry_size // SizeOfData110.long 0 // RVA111.long .Lefi_debug_entry - .L_head // FileOffset112#endif113#ifdef CONFIG_ARM64_BTI_KERNEL114.long 0 // Characteristics115.long 0 // TimeDateStamp116.short 0 // MajorVersion117.short 0 // MinorVersion118.long IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS // Type119.long 4 // SizeOfData120.long 0 // RVA121.long .Lefi_dll_characteristics_ex - .L_head // FileOffset122#endif123.set .Lefi_debug_table_size, . - .Lefi_debug_table124.previous125#endif126127// Section table128.Lsection_table:129.ascii ".text\0\0\0"130.long __initdata_begin - .Lefi_header_end // VirtualSize131.long .Lefi_header_end - .L_head // VirtualAddress132.long __initdata_begin - .Lefi_header_end // SizeOfRawData133.long .Lefi_header_end - .L_head // PointerToRawData134135.long 0 // PointerToRelocations136.long 0 // PointerToLineNumbers137.short 0 // NumberOfRelocations138.short 0 // NumberOfLineNumbers139.long IMAGE_SCN_CNT_CODE | \140IMAGE_SCN_MEM_READ | \141IMAGE_SCN_MEM_EXECUTE // Characteristics142143.ascii ".data\0\0\0"144.long __pecoff_data_size // VirtualSize145.long __initdata_begin - .L_head // VirtualAddress146.long __pecoff_data_rawsize // SizeOfRawData147.long __initdata_begin - .L_head // PointerToRawData148149.long 0 // PointerToRelocations150.long 0 // PointerToLineNumbers151.short 0 // NumberOfRelocations152.short 0 // NumberOfLineNumbers153.long IMAGE_SCN_CNT_INITIALIZED_DATA | \154IMAGE_SCN_MEM_READ | \155IMAGE_SCN_MEM_WRITE // Characteristics156157.set .Lsection_count, (. - .Lsection_table) / 40158159#ifdef CONFIG_DEBUG_EFI160.Lefi_debug_entry:161// EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY162.ascii "NB10" // Signature163.long 0 // Unknown164.long 0 // Unknown2165.long 0 // Unknown3166167.asciz VMLINUX_PATH168169.set .Lefi_debug_entry_size, . - .Lefi_debug_entry170#endif171#ifdef CONFIG_ARM64_BTI_KERNEL172.Lefi_dll_characteristics_ex:173.long IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT174#endif175176.balign SEGMENT_ALIGN177.Lefi_header_end:178#else179.set .Lpe_header_offset, 0x0180#endif181.endm
