【发布时间】:2017-06-21 21:09:33
【问题描述】:
出于特定原因,我需要将.text 部分放在我的 ELF 文件的最后。
我试图以这种方式实现这一点:
我采用默认的大型链接器脚本并将.text 部分移动到SECTIONS { ... } 部分的最后。
$ readelf -S beronew
[ #] Name Type Address Offset
Size Size.Ent Flags - - Alignment
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .data PROGBITS 00000000006000b0 000000b0
000000000000003b 0000000000000000 WA 0 0 1
[ 2] .text PROGBITS 0000000000a000f0 000000f0
00000000000003e9 0000000000000000 AX 0 0 1
[ 3] .shstrtab STRTAB 0000000000000000 000004d9
0000000000000027 0000000000000000 0 0 1
[ 4] .symtab SYMTAB 0000000000000000 00000680
0000000000000438 0000000000000018 5 41 8
[ 5] .strtab STRTAB 0000000000000000 00000ab8
0000000000000258 0000000000000000 0 0 1
我看到ld 在我的“结束”部分之后添加了额外的部分。为了替换它们,我使用了-nostdlib -s 链接器选项(不使用stdlib(以防万一)并省略所有符号信息)。
再运行一次$ readelf -S beronew:
[ #] Name Type Address Offset
Size Size.Ent Flags - - Alignment
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .data PROGBITS 00000000006000b0 000000b0
000000000000003b 0000000000000000 WA 0 0 1
[ 2] .text PROGBITS 0000000000a000f0 000000f0
00000000000003e9 0000000000000000 AX 0 0 1
[ 3] .shstrtab STRTAB 0000000000000000 000004d9
0000000000000017 0000000000000000 0 0 1
节头字符串表还在。我试过$strip -R .shstrtab beronew。没有效果,部分还在。
这部分只有 0x17 字节长,但我无法实现我的目标。然后我查看了我的文件的 hexdump:
$ hexdump beronew
...
00004d0 0060 c748 bfc6 6000 0000 732e 7368 7274
00004e0 6174 0062 642e 7461 0061 742e 7865 0074
00004f0 0000 0000 0000 0000 0000 0000 0000 0000
*
0000530 000b 0000 0001 0000 0003 0000 0000 0000
0000540 00b0 0060 0000 0000 00b0 0000 0000 0000
0000550 003b 0000 0000 0000 0000 0000 0000 0000
...
我看到的是在部分之后还有另一个代码。根据 ELF 结构,文件末尾是Section header table。所以即使我以某种方式删除了.shstrtab 部分,最后仍然会有这个标题。
所以我的问题是 如何将我的 .text 部分放在文件的最后? 我真的不需要删除所有部分和标题,所以如果你知道(更好) 方法来实现这一点,我们将不胜感激。
.
.
附:对于那些想知道我为什么需要这个的人:
此 ELF 文件 (beronew) 包含 rutime 库。它将用作另一个文件的“标题”,该文件生成带有操作码形式的一些逻辑的 asm 指令。这个操作码将被添加到beronew 的最后。然后我将在.text 的部分标题中修补sh_size 字段,以便能够运行我最近添加的“代码”。
(还有一个问题:如果“文本”部分是文件中的最后一个部分,我需要修补这些吗?)
附言我知道这是一个糟糕的架构,但它是我的课程项目 - 将在 Win32 中以这种方式构建的应用程序移植到 Linux64,现在我被困在合并运行时库“头”文件和“逻辑”的地方部分原因是我不能将 .text 部分放在 ELF 的末尾。
再次感谢!
.
更新:
根据 fuz 的评论,我尝试将 PHDRS 添加到简单的链接器脚本中,如下所示:
PHDRS
{
headers PT_PHDR PHDRS ;
data PT_LOAD ;
bss PT_LOAD ;
text PT_LOAD ;
}
SECTIONS
{
. = 0x200000;
.data : { *(.data) *(COMMON) } :data
.bss : { *(.bss) } :bss
.text : { *(.text) } :text
}
但它现在似乎不起作用。
【问题讨论】:
-
请注意,加载器不关心节,它只关心程序头,因此修补
sh_size是无效的。为你的程序添加一个额外的(空的)程序头可能会更容易修补? -
@fuz 也许我没听懂你的意思,你的意思是我应该修补程序标题(我没有看到任何对我有用的或与部分相关的字段)而不是部分标题?或添加额外的程序头(从未听说过第二个头)?
-
一个 ELF 二进制文件包含许多程序头文件,这些头文件告诉程序加载器(在内核中)在哪里加载二进制文件的哪些部分。这是加载程序唯一关心的部分,它忽略了所有其他标题。如果你想在 ELF 二进制文件中添加额外的东西,你可以通过只操作程序头来轻松地做到这一点。请参阅here 了解如何执行此操作。
-
ELF格式有两个视图,对应ELF感兴趣的两个东西:链接器视图和加载器视图。开头的单个 ELF 标头是两个视图唯一共享的部分;链接器对段进行操作,加载程序对段进行操作。 ELF 文件中的任何给定字节都可以属于一个节、一个段,或者两者都不属于。只有可分配段中的字节才会加载到内存中。您提出的 hack 将生成属于最后一个类别的文件并将其附加到文件中:不在任何部分(包括 .text)中,也不在任何段中。你不能只是追加并希望它会起作用!
-
GNU 链接器只提供了一种排序方式将部分加载到内存中的方式。它没有提供一种方法来排序事物在可执行文件本身中的实际布局方式。您需要编写自己的程序来生成或修改 ELF 可执行文件。由于
.shstrtab部分用于存储部分本身的名称,并且正如上面 cmets 解释的那样,在加载和运行可执行文件时实际上并未使用这些部分,因此解决方案可能涉及编写一个删除部分表的程序和.shstrtab从可执行文件中引用的部分。