【发布时间】: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
.interpwhich I observed to be (one of?) the first section(s) in the generated file。在这个特定的链接器脚本中,文件开头有很多部分(我假设)来自正在使用的工具链 - 这就是为什么真正的.init和.text远远落后于 GRUB 检查的初始 8KiB . -
也就是说,我仍然不知道如何编写链接器脚本以正确生成布局 - 这可能是不可能的。除了上述技巧之外,我能想到的唯一方法是在生成 ELF 二进制文件后对其进行编辑。