【问题标题】:ELF file headersELF 文件头
【发布时间】:2023-03-15 09:15:03
【问题描述】:

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

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

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

谢谢!

更新:

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

【问题讨论】:

    标签: linux unix embedded


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 太棒了!谢谢你,帮助我解决另一个问题!
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        您可以创建一个包含信息字段(如版本号)的目标文件,并链接该文件,以便它们包含在生成的 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)。

        incbin

        如果 GNU objcopy 不可用,可以使用 GNU as .incbin directive 创建目标文件(使用 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;
        

        【讨论】:

          【解决方案5】:

          您也许可以使用 libmelf,这是一个关于freshmeat 的死项目,但可从 LOPI - http://www.ipd.bth.se/ska/lopi.html

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • 好主意,我可能会以这种方式进行校验和,也应该可以添加构建日期等。但是我仍然很想知道你是否可以更改 elf 文件头知道我花了很多时间看它!
            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

                在 Linux 控制台中:

                $ 人 ld

                $ ld --verbose

                HTH

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-08-13
                  • 2015-06-01
                  • 1970-01-01
                  • 2011-03-16
                  • 1970-01-01
                  • 2014-12-21
                  • 2012-02-11
                  相关资源
                  最近更新 更多