简体   繁体   English

ELF 文件头

[英]ELF file headers

A quick question about elf file headers, I can't seem to find anything useful on how to add/change fields in the elf header.关于 elf 文件头的一个快速问题,我似乎找不到任何关于如何在 elf 头中添加/更改字段的有用信息。 I'd like to be able to change the magic numbers and to add a build date to the header, and probably a few other things.我希望能够更改幻数并将构建日期添加到标题中,可能还有其他一些事情。

As I understand it the linker creates the header information, but I don't see anything in the LD script that refers to it (though i'm new to ld scripts).据我了解,链接器创建了标头信息,但我在 LD 脚本中没有看到任何引用它的内容(尽管我是 ld 脚本的新手)。

I'm using gcc and building for ARM.我正在使用 gcc 并为 ARM 构建。

thanks!谢谢!

Updates:更新:

  • ok maybe my first question should be: is it possible to create/edit the header file at link time?好吧,也许我的第一个问题应该是:是否可以在链接时创建/编辑头文件?

I don't know of linker script commands that can do this, but you can do it post-link using the objcopy command.我不知道可以执行此操作的链接器脚本命令,但您可以使用objcopy命令在链接后执行此操作。 The --add-section option can be used to add a section containing arbitrary data to the ELF file. --add-section选项可用于向 ELF 文件添加包含任意数据的部分。 If the ELF header doesn't contain the fields you want, just make a new section and add them there.如果 ELF 标头不包含您想要的字段,只需创建一个新部分并将它们添加到那里。

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

I'm fairly sure that a sufficiently complex ld script can do what you want.我相当确定一个足够复杂的 ld 脚本可以做你想做的事。 However, I have no idea how.但是,我不知道如何。

On the other hand, elfsh can easily do all sorts of manipulations to elf objects, so give it a whirl.另一方面, elfsh可以轻松地对 elf 对象进行各种操作,所以试一试吧。

You can create an object file with informative fields like a version number and link that file such that they are included in the resulting ELF binary.您可以创建一个带有信息字段(如版本号)的目标文件并链接该文件,以便它们包含在生成的 ELF 二进制文件中。

Ident身份

For example, as part of you build process, you can generate - say - info.c that contains one or more #ident directives:例如,当你构建过程的一部分,您可以生成-比如说- info.c包含一个或多个#ident指令:

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

Compile it:编译它:

$ gcc -c info.c

Check if the information is included:检查信息是否包含:

$ 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)

Alternatively, you can use objdump -s --section .comment info.o .或者,您可以使用objdump -s --section .comment info.o Note that GCC also writes its own comment, by default.请注意,默认情况下,GCC 也会编写自己的注释。

Check the information after linking an ELF executable:链接 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

Comment Section评论部分

Using #ident in a C translation unit is basically equivalent to creating a .comment section in an assembler file.在 C 翻译单元中使用#ident基本上等同于在汇编程序文件中创建一个.comment部分。 Example:例子:

$ 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

Using an uncommon section name works, as well (eg .section .blahblah ).使用不常见的部分名称也可以(例如.section .blahblah )。 But .comment is used and understood by other tools.但是.comment被其他工具使用和理解。 GNU as also understands the .ident directive, and this is what GCC translates #ident to. GNU as 也理解.ident指令,这就是 GCC 将#ident翻译成的。

With Symbols带符号

For data that you also want to access from the ELF executable itself you need to create symbols.对于您还想从 ELF 可执行文件本身访问的数据,您需要创建符号。

Objcopy对象拷贝

Say you want to include some magic bytes stored in a data file:假设您想包含一些存储在数据文件中的魔术字节:

$ cat magic.bin 
2342

Convert into a object file with GNU objcopy :使用GNU objcopy转换为目标文件:

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

Check for the symbols:检查符号:

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

Example usage:用法示例:

#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;
}

Link everything together:将所有内容链接在一起:

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

GNU ld GNU ld

GNU ld is also able to turn data files into object files using an objcopy compatible naming scheme: GNU ld还能够使用与 objcopy 兼容的命名方案将数据文件转换为目标文件:

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

Unlike objcopy, it places the symbols into the .data instead of the .rodata section, though (cf. objdump -h magic.o ).与 objcopy 不同,它将符号放入.data而不是.rodata部分(参见objdump -h magic.o )。

incbin incbin

In case GNU objcopy isn't available, one can use the GNU as .incbin directive to create the object file (assemble with gcc -c incbin.s ):如果 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 xxd

A more portable alternative that doesn't require GNU objcopy nor GNU as is to create an intermediate C file and compile and link that.一种更便携的替代方案,它不需要 GNU objcopy 或 GNU,因为它可以创建一个中间 C 文件并编译和链接它。 For example with xxd :例如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;

You might be able to use libmelf, a dead project on freshmeat, but available from LOPI - http://www.ipd.bth.se/ska/lopi.html您也许可以使用 libmelf,这是一个关于新鲜肉的死项目,但可以从 LOPI 获得 - http://www.ipd.bth.se/ska/lopi.html

Otherwise, you can get the spec and (over)write the header yourself.否则,您可以获取规范并(覆盖)自己编写标题。

I haven't done this in awhile, but can't you just append arbitrary data to an executable.我已经有一段时间没有这样做了,但是您不能将任意数据附加到可执行文件中。 If you always append fixed-size data it would be trivial to recover anything you append.如果您总是附加固定大小的数据,那么恢复您附加的任何内容将是微不足道的。 Variable size wouldn't be much harder.可变大小不会更难。 Probably easier than messing w/ elf headers and potentially ruining you executables.可能比弄乱 elf 标头并可能破坏您的可执行文件更容易。

In Solaris you can use elfedit but I think you are really asking solutions for Linux.在 Solaris 中,您可以使用elfedit,但我认为您确实在询问 Linux 的解决方案。 Linux Is Not UniX :P Linux 不是 Unix :P

我没有读完这本书,但约翰·莱文 (John Levine ) 的 iirc Linkers and Loaders有你需要能够做到这一点的血腥细节。

In Linux Console:在 Linux 控制台中:

$ man ld $ man ld

$ ld --verbose $ ld --详细

HTH HTH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM