-
Notifications
You must be signed in to change notification settings - Fork 6
vmlinux
커널 이미지 빌드시 vmlinux.ld.S(linux-5.1.15\arch\arm64\kernel)을 이용하여 vmlinux.ld(linux-5.1.15\arch\arm64\kernel) 파일을 생성합니다.
즉, 어셈블러로 작성된 vmlinux.ld.S 파일에서 링커가 참조 할수 있는 vmlinux.ld 파일을 생성합니다.
링커는 링커스크립트(= vmlinux.ld)를 참조하여 vmlinux를 만듭니다.
빌드된 커널 이미지는 ELF 포멧으로 구성되어 있습니다.
vmlinux.ld (linux-5.1.15\vmlinux_readelf)
vmlinux elf (linux-5.1.15\vmlinux_readelf)
분석중인 head.S에서는 3개의 section을 가지고 있습니다.
73: __HEAD (#define __HEAD .section ".head.text","ax")
84: b stext
105: __INIT (#define __INIT .section ".init.text","ax")
117: ENTRY(stext)
137: preserve_boot_args
287: __create_page_tables
423: __primary_switched
474: .section ".idmap.text","awx"
476: ENTRY(kimage_vaddr)
487: ENTRY(el2_setup)
679: ENTRY(__boot_cpu_mode)
686: ENTRY(__early_cpu_boot_status)
695: ENTRY(secondary_holding_pen)
713: ENTRY(secondary_entry)
776: ENTRY(__enable_mmu)
802: ENTRY(__cpu_secondary_check52bitva)
참고로 vmlinux.ld.S의 idmap 관련 입니다.
#define IDMAP_TEXT \
. = ALIGN(SZ_4K); \
__idmap_text_start = .; \
*(.idmap.text) \
__idmap_text_end = .;
.text : { /* Real text segment */
_stext = .; /* Text and read-only data */
__exception_text_start = .;
*(.exception.text)
__exception_text_end = .;
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
ENTRY_TEXT
TEXT_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
HYPERVISOR_TEXT
IDMAP_TEXT
HIBERNATE_TEXT
TRAMP_TEXT
*(.fixup)
*(.gnu.warning)
. = ALIGN(16);
*(.got) /* Global offset table */
}
.idmap.text 는 .text section에 포함됩니다.
vmlinux elf에서 section을 확인해 보면 아래와 같습니다.
Section Headers:
[Nr] Name Type Address Offset Flags
* [ 1] .head.text PROGBITS ffff000010080000 00010000 AX
* [ 2] .text PROGBITS ffff000010081000 00011000 AX
[ 3] .rodata PROGBITS ffff000010ba0000 00b30000 WA
[ 4] .pci_fixup PROGBITS ffff0000110c3490 01053490 A
[ 5] __ksymtab PROGBITS ffff0000110c5670 01055670 A
[ 6] __ksymtab_gpl PROGBITS ffff0000110cf218 0105f218 A
[ 7] __ksymtab_strings PROGBITS ffff0000110da740 0106a740 A
[ 8] __param PROGBITS ffff00001110ee88 0109ee88 A
[ 9] __modver PROGBITS ffff0000111125b0 010a25b0 A
[10] __ex_table PROGBITS ffff000011113000 010a3000 A
[11] .notes NOTE ffff000011115528 010a5528 A
* [12] .init.text PROGBITS ffff000011120000 010b0000 AX
[13] .exit.text PROGBITS ffff000011185c8c 01115c8c AX
[14] .altinstructions PROGBITS ffff00001118aac8 0111aac8 A
[15] .altinstr_replace PROGBITS ffff0000111caf38 0115af38 AX
[16] .init.data PROGBITS ffff0000111e8000 01178000 WA
[17] .data..percpu PROGBITS ffff00001126f000 011ff000 WA
[18] .data PROGBITS ffff000011280000 01210000 WA
[19] __bug_table PROGBITS ffff000011419ca0 013a9ca0 WA
[20] .mmuoff.data.writ PROGBITS ffff00001142c000 013bc000 WA
[21] .mmuoff.data.read PROGBITS ffff00001142c800 013bc800 WA
[22] .pecoff_edata_pad PROGBITS ffff00001142c808 013bc808 WA
[23] .bss NOBITS ffff00001142d000 013bca00 WA
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
Section Heaers
[Nr] Name Address Size
* [ 1] .head.text ffff000010080000 00001000 4KB
* [ 2] .text ffff000010081000 00B11740 약 12MB
* [12] .init.text ffff000011120000 00065C8C 약 197KB
부트로더는 커널이미지를 RAM에 로딩하고 Kernel의 Entry Point(b stext)를 호출 해줍니다.
이때 부트로더는 커널이미지에서 64-byte 헤더를 읽어 정보를 취득합니다.
The decompressed kernel image contains a 64-byte header as follows:
u32 code0; /* Executable code */
u32 code1; /* Executable code */
u64 text_offset; /* Image load offset, little endian */
u64 image_size; /* Effective Image size, little endian */
u64 flags; /* kernel flags, little endian */
u64 res2 = 0; /* reserved */
u64 res3 = 0; /* reserved */
u64 res4 = 0; /* reserved */
u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
u32 res5; /* reserved (used for PE COFF offset) */
Header notes:
- As of v3.17, all fields are little endian unless stated otherwise.
- code0/code1 are responsible for branching to stext.
- when booting through EFI, code0/code1 are initially skipped.
res5 is an offset to the PE header and the PE header has the EFI
entry point (efi_stub_entry). When the stub has done its work, it
jumps to code0 to resume the normal boot process.
- Prior to v3.17, the endianness of text_offset was not specified. In
these cases image_size is zero and text_offset is 0x80000 in the
endianness of the kernel. Where image_size is non-zero image_size is
little-endian and must be respected. Where image_size is zero,
text_offset can be assumed to be 0x80000.
- The flags field (introduced in v3.17) is a little-endian 64-bit field
composed as follows:
Bit 0: Kernel endianness. 1 if BE, 0 if LE.
Bit 1-2: Kernel Page size.
0 - Unspecified.
1 - 4K
2 - 16K
3 - 64K
Bit 3: Kernel physical placement
0 - 2MB aligned base should be as close as possible
to the base of DRAM, since memory below it is not
accessible via the linear mapping
1 - 2MB aligned base may be anywhere in physical
memory
Bits 4-63: Reserved.
vmlinux 64Byte Header 분석
code0/code1 = are responsible for branching to stext.
text_offset = 0x00000000-00080000
image_size = 0x00000000-01420000
flags = 0x00000000-0000000A : LE, 4K, 2MB aligned base may be anywhere in physical memory
res2 = 0x00000000-00000000
res3 = 0x00000000-00000000
res4 = 0x00000000-00000000
magic = 0x644D5241
res5 = 0x00000040
부트로더는 커널 이미지를 RAM의 2MB 정렬된 위치에 놓고 code0/code1을 이용해서 stext로 분기합니다.
Pinciples of ARM memory maps(참고자료/arm/principles_of_arm_memory_maps.pdf) 문서에 보면 아래와 같이 Guide를 하고 있습니다.
| | Physical Address in Soc | | 2 GBytes (32-bit map) | 0x00 8000 0000 ~ 0x00 FFFF FFFF | | 30 GBytes (36-bit map) | 0x08 8000 0000 ~ 0x0F FFFF FFFF | | 32 GBytes (40-bit map) | 0x88 0000 0000 ~ 0x8F FFFF FFFF |
계산하기 쉽게 DRAM의 영역이 0x88 0000 0000 (40-bit map) 부터 시작한다고 가정합니다. 그리고 vmlinux(커널 이미지) 물리 메모리의 맨 처음에 올라간다고 가정합니다.
vmlinux_section 의 정보에 따라 Section의 위치를 해보면 다음과 같습니다.
가상주소 물리주소
DRAM : 0x88 0000 0000
0 .head.text : ffff000010080000 0x88 1008 0000
1 .text : ffff000010081000 0x88 1008 1000
11 .init.text : ffff000011120000 0x88 1112 0000
stext : ffff000011120000 0x88 1112 0000