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.outcomplete 输出添加到您的问题中。 @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 文件中“为时已晚”(偏移量很大),即使它是第一部分的主要内容,如果未能解决你的问题,请参考以下文章

GRUB 可以加载没有多重引导标头的 ELF 文件吗?

c_cpp 根据标头中的信息计算磁盘上ELF文件的大小

如何编译一个简单的 multiboot2 裸机可执行文件?

为啥 Windows gcc (cygwin) 不写 ELF 标头?

在 AWS Lambda 上使用 nodejs“ref”模块时出现“无效的 ELF 标头”

如何在Balena上运行的raspberry pi 3上修复无效的ELF标头错误?