multiboot2 标头在 ELF 文件中“为时已晚”(偏移量很大),即使它是第一部分
Posted
技术标签:
【中文标题】multiboot2 标头在 ELF 文件中“为时已晚”(偏移量很大),即使它是第一部分【英文标题】:multiboot2 header comes "too late" in ELF file (to large offset), even if it is the very first section 【发布时间】:2021-09-29 04:17:04 【问题描述】:在我的最终ELF
中找不到multiboot2
标头,因为在二进制文件中它位于偏移量0x334e0
,但multiboot2 规范只告诉第一个32KiB
,即0x8000
字节, 被检查。因此,它来得太晚了。
我不知道如何解决这个问题。 ELF 标头是否过于臃肿? multiboot2 标头本身是正确的,即检查 multiboot2 标头的几个工具告诉它是正确的。当我将标题与其他代码链接在一起时,它只是不起作用。如果我调整工具来验证 multiboot2 标头,即 bootimage
[1] 比第一个 32KiB
查看更多,它也可以。
我的链接器脚本(GNU ld
):
/** The "start"-symbol from start.asm. */
ENTRY(start)
SECTIONS
/* Multiboot2-Header must be 64-bit (8 byte) aligned according to spec. */
. = ALIGN(8);
.multiboot2_header :
/* ensure that the multiboot header is at the beginning */
*(.multiboot2_header)
.text :
*(.text)
readelf -WSl <my-elf>
告诉我们,.multiboot2_header
部分确实是第一个:
There are 1526 section headers, starting at offset 0x3ca8d8:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .multiboot2_header PROGBITS 0000000000000000 0334e8 000048 00 0 0 8
[ 2] .debug_abbrev PROGBITS 0000000000000000 033530 00ecea 00 0 0 1
[ 3] .debug_info PROGBITS 0000000000000000 04221a 0f0391 00 0 0 1
[ 4] .debug_aranges PROGBITS 0000000000000000 1325ab 019f40 00 0 0 1
[ 5] .debug_ranges PROGBITS 0000000000000000 14c4eb 0301d0 00 0 0 1
[ 6] .debug_str PROGBITS 0000000000000000 17c6bb 0c5de1 01 MS 0 0 1
[ 7] .debug_pubnames PROGBITS 0000000000000000 24249c 035215 00 0 0 1
[ 8] .debug_pubtypes PROGBITS 0000000000000000 2776b1 058c44 00 0 0 1
[ 9] .debug_frame PROGBITS 0000000000000000 2d02f8 033b60 00 0 0 8
[10] .debug_line PROGBITS 0000000000000000 303e58 08390a 00 0 0 1
[11] .debug_loc PROGBITS 0000000000000000 387762 0038d8 00 0 0 1
[12] .comment PROGBITS 0000000000000000 38b03a 000013 01 MS 0 0 1
[13] .symtab SYMTAB 0000000000000000 38b050 0089d0 18 15 803 8
[14] .shstrtab STRTAB 0000000000000000 393a20 01cec9 00 0 0 1
[15] .strtab STRTAB 0000000000000000 3b08e9 019fee 00 0 0 1
[16] .rodata._ZN137_$LT$rust_multiboot2_64_bit_kernel..logger..BootStageAwareLogger$u20$as$u20$rust_multiboot2_64_bit_kernel..boot_stage..BootStageAware$GT$15next_boot_stage17h5918ecf04a4f1232E PROGBITS 0000000000000000 000160 000010 00 A 0 0 4
...
[179] .rodata..L__unnamed_94 PROGBITS 00000000000045a8 004708 00007f 00 A 0 0 1
[180] .eh_frame_hdr PROGBITS 0000000000004628 004788 00000c 00 A 0 0 4
[181] .eh_frame PROGBITS 0000000000004638 004798 00001c 00 A 0 0 8
[182] .text PROGBITS 0000000000004654 0047b4 00001b 00 AX 0 0 4
[183] .text._ZN29rust_multiboot2_64_bit_kernel6logger20BootStageAwareLogger13apply_to_each17h77f9f12abd1f054eE PROGBITS 0000000000004670 0047d0 000130 00 AX 0 0 16
...
[1388] .text._ZN54_$LT$u32$u20$as$u20$core..ops..bit..Shl$LT$i32$GT$$GT$3shl17h0ba8101e5b58ae12E PROGBITS 0000000000030390 0304f0 000049 00 AX 0 0 16
[1389] .text._ZN58_$LT$$RF$u32$u20$as$u20$core..ops..bit..Shl$LT$i32$GT$$GT$3shl17h518033907a793365E PROGBITS 00000000000303e0 030540 000021 00 AX 0 0 16
[1390] .text.memcpy PROGBITS 0000000000030410 030570 00004e 00 AX 0 0 16
[1391] .text.memset PROGBITS 0000000000030460 0305c0 0000a4 00 AX 0 0 16
[1392] .text.memcmp PROGBITS 0000000000030510 030670 000179 00 AX 0 0 16
[1393] .data.rel.ro..L__unnamed_1 PROGBITS 0000000000030690 0307f0 0002c0 00 WA 0 0 8
[1394] .data.rel.ro..L__unnamed_2 PROGBITS 0000000000030950 030ab0 000300 00 WA 0 0 8
...
[1515] .data.rel.ro..L__unnamed_169 PROGBITS 00000000000332e0 033440 000018 00 WA 0 0 8
[1516] .got PROGBITS 00000000000332f8 033458 000090 00 WA 0 0 8
[1517] .bss._ZN29rust_multiboot2_64_bit_kernel6logger6LOGGER17h0a7e2a9a53f2b5ddE NOBITS 0000000000033388 0334e8 000018 00 WA 0 0 8
[1518] .bss NOBITS 00000000000333a0 0334e8 020000 00 WA 0 0 8
[1519] .bss._ZN29rust_multiboot2_64_bit_kernel3mb225MULTIBOOT2_INFO_STRUCTURE17h67db2667e3bd19ceE NOBITS 00000000000533a0 0334e8 000018 00 WA 0 0 8
[1520] .bss._ZN29rust_multiboot2_64_bit_kernel5panic13PANIC_HANDLER17h02bbbbc17c579b55E NOBITS 00000000000533b8 0334e8 00000c 00 WA 0 0 4
[1521] .bss._ZN29rust_multiboot2_64_bit_kernel5xuefi10UEFI_ST_BS17ha7c24b049d2b76abE NOBITS 00000000000533c8 0334e8 000008 00 WA 0 0 8
[1522] .bss._ZN29rust_multiboot2_64_bit_kernel10boot_stage10BOOT_STAGE17he05c77811885a1c6E NOBITS 00000000000533d0 0334e8 000001 00 WA 0 0 1
[1523] .bss._ZN29rust_multiboot2_64_bit_kernel11kernelalloc9ALLOCATOR17h93bce260f0439187E NOBITS 00000000000533d1 0334e8 000001 00 WA 0 0 1
[1524] .bss._ZN3log5STATE17hdfa5c64bc29aed3eE NOBITS 00000000000533d8 0334e8 000008 00 WA 0 0 8
[1525] .bss._ZN3log20MAX_LOG_LEVEL_FILTER17h84bf10c3ec44ab54E NOBITS 00000000000533e0 0334e8 000008 00 WA 0 0 8
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),
l (large), p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x4654
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000160 0x0000000000000000 0x0000000000000000 0x004654 0x004654 R 0x10
LOAD 0x0047b4 0x0000000000004654 0x0000000000004654 0x02c035 0x02c035 R E 0x10
LOAD 0x0307f0 0x0000000000030690 0x0000000000030690 0x002cf8 0x022d58 RW 0x8
GNU_EH_FRAME 0x004788 0x0000000000004628 0x0000000000004628 0x00000c 0x00000c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0
Section to Segment mapping:
Segment Sections...
00 .rodata._ZN137_$LT$rust_multib...
01 .text .text._ZN29rust_multiboot2_64_bit_kernel6logger2...
02 .data.rel.ro..L__unnamed_1 .data.rel.ro..L__unnamed_2 ...
03 .eh_frame_hdr
04
在那里你可以看到文件中的标题“来得太晚了”。我该如何解决这个问题?如何将其移动到 ELF 文件中的较小偏移量,即更靠近文件开头?
PS:ELF get 由 cargo/rustc/llvm 组装,在我的例子中,它使用 GNU ld
和自定义链接脚本。
【问题讨论】:
不清楚文件中您的部分之前的内容,并且您已经删除了readelf
输出的所有相关部分。考虑将readelf -WSl a.out
的complete 输出添加到您的问题中。
@EmployedRussian 我添加了输出
【参考方案1】:
Section to Segment mapping:
Segment Sections...
00 .rodata._ZN137_$LT$rust_multib...
01 .text .text._ZN29rust_multiboot2_64_bit_kernel6logger2...
...
很明显.rodata._ZN....
部分在文件中的偏移量较低,而.text
实际上并不是第一个。
您需要将 .rodata...
移动到单独的段中(通过调整链接描述文件),或您需要为 ELF 标头禁用单独的 RO
段(这将允许 .text
在第一段)。见this答案。
【讨论】:
即使将.rodata : *(.rodata .rodata.* )
作为.text
和.multiboot2_header
之后的附加部分,问题仍然存在。
我唯一可行的解决方案是将 multiboot2 标头添加到 .text
段的开头。这可行,但我仍然想了解如何通过单独的部分来实现这一目标。以上是关于multiboot2 标头在 ELF 文件中“为时已晚”(偏移量很大),即使它是第一部分的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Windows gcc (cygwin) 不写 ELF 标头?