如何告诉/强制 GNU ld 将部分/符号放在输出 ELF 文件的特定部分?
Posted
技术标签:
【中文标题】如何告诉/强制 GNU ld 将部分/符号放在输出 ELF 文件的特定部分?【英文标题】:How to tell / force GNU ld to put a section/symbol in a specific part of the output ELF file? 【发布时间】:2013-11-23 15:21:41 【问题描述】:那会很长,所以喝点咖啡/茶/yerba吧。
总结
如何告诉/强制 GNU ld 放置一个部分/符号 在输出 ELF 文件的特定部分?
具体来说,我不是在询问符号的物理/加载地址 但关于文件内的偏移量。
背景
我正在尝试采用真实世界的 BSD 内核并使其兼容
GRUB 可多重引导和引导。
为了使 ELF 映像与 Multiboot 兼容且可识别
通过 GRUB,需要在第一个中嵌入一个幻数 (0x1BADB002
)
8KiB 的文件。
我指的是Multiboot 0.6.96。
由于原始内核是相当大的一段代码,
我将使用基于Bare Bones kernel from OSDev wiki 的示例。
由于该内核已经兼容 Multiboot,我将使用
extra_symbol
以 0xCAFEBABE
作为我的问题的示例。
boot.s
包含:
.set CAFEBABE, 0xCAFEBABE
; ... snip ...
.section .extras
extra_symbol:
.long CAFEBABE
.text
中的额外符号
最简单的选择是将具有该值的符号放入.text
其他部分之前的部分:
.text BLOCK(4K) : ALIGN(4K)
*(.extras)
*(.multiboot)
*(.text)
这个例子很好,但对于真正的 BSD 内核.text
在文件中的 0x2000 (8KiB) 之后开始。这种方法不是一种选择。
.text
之前的额外部分?
另一种选择是将整个.extras
部分放在.text
之前。
在我的天真中,我希望在.text
之前放置这样一个部分
链接器脚本也会使其更早地出现在输出 ELF 中:
SECTIONS
// ... some stuff ...
.extras : *(.extras)
.text BLOCK(4K) : ALIGN(4K)
*(.multiboot)
*(.text)
// ... more stuff ...
但事实并非如此:
$ i586-elf-readelf -S myos.bin
There are 10 section headers, starting at offset 0x6078:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .extras PROGBITS 00100000 006010 000004 00 0 0 1
[ 2] .comment PROGBITS 00000000 006014 000011 01 MS 0 0 1
[ 3] .text PROGBITS 00001000 001000 0001e4 00 AX 0 0 4096
[ 4] .rodata.str1.1 PROGBITS 000011e4 0011e4 000016 01 AMS 0 0 1
[ 5] .eh_frame PROGBITS 000011fc 0011fc 000104 00 A 0 0 4
[ 6] .bss PROGBITS 00002000 002000 004010 00 WA 0 0 4096
[ 7] .shstrtab STRTAB 00000000 006025 000050 00 0 0 1
[ 8] .symtab SYMTAB 00000000 006208 000210 10 9 19 4
[ 9] .strtab STRTAB 00000000 006418 000130 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
实际上,节在节头表中排在第一位,但它的
文件中的偏移量 (0x6010
) 在.text
之后。事实上,它甚至
在.bss
之后。
问题
ELF 规范明确指出:
虽然图中显示了紧随其后的程序头表 ELF 头,以及节后的节头表,实际 文件可能不同。此外,节和段没有指定的顺序。 只有 ELF 头在文件中有固定的位置。
我如何利用它并告诉 GNU ld 放置我的extra_symbol
(可能是整个 .extras
部分)在文件中的任何其他部分之前,
最好在 ELF 标头之后?
【问题讨论】:
您是否尝试指定您的部分的加载地址?像: .extras : *(.extras) >ROM AT> ROM 其中 ROM 在内存块中定义,例如: MEMORY ROM : ORIGIN = 0x1000, LENGTH = 0x1000 您甚至可以制作自己的内存块 MEMORY SIGNATURE :原点 = 0x....,长度 = 4 .extras : *(.extras) >SIGNATURE AT> SIGNATURE 我尝试了多种设置负载和虚拟地址以及使用内存块的组合。 readelf 输出中的相关地址确实发生了变化。 xxd 打印的二进制文件中 0xCAFEBABE 的偏移量没有。我将用我尝试过的组合的详细信息更新问题(现在不能这样做)。 @erszcz 到目前为止有任何更新吗? @yeputons 不幸的是,我最终使用 hack 将图像识别为 Multiboot。 I placed the MB header in.interp
which I observed to be (one of?) the first section(s) in the generated file。在这个特定的链接器脚本中,文件开头有很多部分(我假设)来自正在使用的工具链 - 这就是为什么真正的 .init
和 .text
远远落后于 GRUB 检查的初始 8KiB .
也就是说,我仍然不知道如何编写链接器脚本以正确生成布局 - 这可能是不可能的。除了上述技巧之外,我能想到的唯一方法是在生成 ELF 二进制文件后对其进行编辑。
【参考方案1】:
为了将部分放在.text
之前,您是否已经尝试使其分配(A
)和可执行(X
)?
如果.interp
hack 有效,那么当然也可以。
【讨论】:
感谢您的回复,但我目前无法检查:(这个问题现在已经快 4 岁了。【参考方案2】:我遇到了同样的问题——多重引导签名是在 .text 部分之后加载的——并且使用 Florian 的指针,这就是我强制在 ELF 文件开头加载示例部分的方式。
.section .multiboot, "ax", @progbits
.align 4
.long MAGIC
.long FLAGS
...
即通过在节声明处标记可分配和可执行
【讨论】:
感谢您的评论和验证 Florian 的建议!我想是时候将他的答案标记为已接受了 :) 迟到总比没有好。 如此,如此:-)以上是关于如何告诉/强制 GNU ld 将部分/符号放在输出 ELF 文件的特定部分?的主要内容,如果未能解决你的问题,请参考以下文章