11

关于 elf 文件头的一个快速问题,我似乎找不到任何关于如何在 elf 头中添加/更改字段的有用信息。我希望能够更改幻数并在标题中添加构建日期,可能还有其他一些东西。

据我了解,链接器会创建标头信息,但我在 LD 脚本中看不到任何引用它的内容(尽管我是 ld 脚本的新手)。

我正在使用 gcc 并为 ARM 构建。

谢谢!

更新:

  • 好的,也许我的第一个问题应该是:是否可以在链接时创建/编辑头文件?
4

9 回答 9

10

我不知道可以执行此操作的链接器脚本命令,但您可以使用objcopy命令在链接后执行此操作。--add-section选项可用于将包含任意数据的部分添加到 ELF 文件。如果 ELF 标头不包含您想要的字段,只需创建一个新部分并将它们添加到那里。

于 2008-10-24T16:14:28.700 回答
7

此链接(teensy elf binary)是某人对另一个问题的回答,但它详细介绍了 ELF 标头的复杂性。

于 2008-10-26T10:49:12.323 回答
2

我相当确定一个足够复杂的 ld 脚本可以做你想做的事。但是,我不知道如何。

另一方面,elfsh可以轻松地对 elf 对象进行各种操作,所以试一试。

于 2008-10-24T16:50:07.880 回答
2

您可以创建一个包含信息字段(如版本号)的目标文件,并链接该文件,以便它们包含在生成的 ELF 二进制文件中。

标识

例如,作为构建过程的一部分,您可以生成 - 比如说 -info.c包含一个或多个#ident指令:

#ident "Build: 1.2.3 (Halloween)"
#ident "Environment: example.org"

编译它:

$ gcc -c info.c

检查是否包含信息:

$ readelf -p .comment info.o
String dump of section '.comment':
  [     1]  Build: 1.2.3 (Halloween)
  [    1a]  Environment: example.org
  [    33]  GCC: (GNU) 7.2.1 20170915 (Red Hat 7.2.1-2)

或者,您可以使用objdump -s --section .comment info.o. 请注意,默认情况下,GCC 也会编写自己的注释。

链接 ELF 可执行文件后检查信息:

$ gcc -o main main.o info.o
$ readelf -p .comment main 
String dump of section '.comment':
  [     0]  GCC: (GNU) 7.2.1 20170915 (Red Hat 7.2.1-2)
  [    2c]  Build: 1.2.3 (Halloween)
  [    45]  Environment: example.org

评论区

在 C 翻译单元中使用#ident基本上等同于.comment在汇编文件中创建一个节。例子:

$ cat info.s
.section .comment
.string "Build: 1.2.3 (Halloween)"
.string "Environment: example.org"
$ gcc -c info.s
$ readelf -p .comment info.o
String dump of section '.comment':
  [     0]  Build: 1.2.3 (Halloween)
  [    19]  Environment: example.org

使用不常见的部分名称也可以(例如.section .blahblah)。但是.comment被其他工具使用和理解。GNU as 也理解该.ident指令,这就是 GCC 所翻译#ident的内容。

带符号

对于您还想从 ELF 可执行文件本身访问的数据,您需要创建符号。

对象复制

假设您想包含一些存储在数据文件中的魔术字节:

$ cat magic.bin 
2342

使用GNU objcopy转换为目标文件:

$ objcopy -I binary -O elf64-x86-64 -B i386 \
    --rename-section .data=.rodata,alloc,load,readonly,data,contents \
    magic.bin magic.o

检查符号:

$ nm  magic.o  
0000000000000005 R _binary_magic_bin_end
0000000000000005 A _binary_magic_bin_size
0000000000000000 R _binary_magic_bin_start

示例用法:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

extern const char _binary_magic_bin_start[];
extern const char _binary_magic_bin_end[];
extern const unsigned char _binary_magic_bin_size;
static const size_t magic_bin_size = (uintptr_t) &_binary_magic_bin_size;

int main()
{
  char s[23];
  memcpy(s, _binary_magic_bin_start,
      _binary_magic_bin_end - _binary_magic_bin_start);
  s[magic_bin_size] = 0;
  puts(s);
  return 0;
}

将所有内容链接在一起:

$ gcc -g -o main_magic main_magic.c magic.o

GNU ld

GNU ld还能够使用兼容 objcopy 的命名方案将数据文件转换为目标文件:

$ ld -r -b binary magic.bin -o magic-ld.o

与 objcopy 不同的是,它将符号放入.data而不是.rodata部分,但(参见objdump -h magic.o)。

公司

如果 GNU objcopy 不可用,可以使用GNU as .incbin指令来创建目标文件(用 汇编gcc -c incbin.s):

    .section .rodata

    .global _binary_magic_bin_start
    .type _binary_magic_bin_start, @object
_binary_magic_bin_start:
    .incbin "magic.bin"
    .size _binary_magic_bin_start, . - _binary_magic_bin_start

    .global _binary_magic_bin_size
    .type _binary_magic_bin_size, @object
    .set _binary_magic_bin_size, . - _binary_magic_bin_start

    .global _binary_magic_bin_end
    .type _binary_magic_bin_end, @object
    .set _binary_magic_bin_end, _binary_magic_bin_start + _binary_magic_bin_size
    ; an alternate  way to include the size    
    .global _binary_magic_bin_len
    .type _binary_magic_bin_len, @object
    .size _binary_magic_bin_len, 8
_binary_magic_bin_len:
    .quad _binary_magic_bin_size

xxd

一种更便携的替代方案,它不需要 GNU objcopy 或 GNU,因为它可以创建一个中间 C 文件并编译和链接它。例如xxd

$ xxd -i magic.bin | sed 's/\(unsigned\)/const \1/' > magic.c
$ gcc -c magic.c
$ nm magic.o
0000000000000000 R magic_bin
0000000000000008 R magic_bin_len
$ cat magic.c
const unsigned char magic_bin[] = {
  0x32, 0x33, 0x34, 0x32, 0x0a
};
const unsigned int magic_bin_len = 5;
于 2017-11-02T21:24:13.060 回答
0

你也许可以使用 libmelf,一个关于 Freshmeat 的死项目,但可以从 LOPI 获得 - http://www.ipd.bth.se/ska/lopi.html

否则,您可以自己获取规范并(覆盖)编写标题。

于 2008-10-24T12:55:13.720 回答
0

我已经有一段时间没有这样做了,但是您不能将任意数据附加到可执行文件中。如果您总是附加固定大小的数据,那么恢复您附加的任何内容都是微不足道的。可变大小不会更难。可能比弄乱 w/elf 标头并可能破坏您的可执行文件更容易。

于 2008-10-24T13:00:12.587 回答
0

在 Solaris 中,您可以使用elfedit,但我认为您确实在为 Linux 寻求解决方案。Linux 不是 Unix :P

于 2008-10-24T16:53:52.957 回答
0

我没有读完这本书,但John Levine的 iirc Linkers and Loaders 有血淋淋的细节,你需要能够做到这一点。

于 2008-10-25T00:08:12.440 回答
-1

在 Linux 控制台中:

$人ld

$ ld --详细

高温高压

于 2008-10-28T12:30:53.960 回答