【问题标题】:How to control the section to segment mapping in an ELF file?如何控制 ELF 文件中的段到段映射?
【发布时间】:2013-10-16 01:40:44
【问题描述】:

所以我知道我们可以将自定义部分添加到 ELF 文件中,并强制将函数和结构映射到自定义部分。 这可以通过__atribute__ section("sectionname") 完成 这是我当前 ELF 的 readelf 输出,它有一个自定义部分名称 .my_custom_section,其中包含一个名为 ver_info 的结构

结构:

typedef struct version_info
{
  int     dd ;
  int      mm;
  int    yy;
  int      hr;
  int      min;
  char      *software_type;
  char   *software_version;
  char    *hex_tools_version;
} version_info;

version_info ver_info __attribute__ ((section(".my_custom_section"))) = {7, 10, 2013, 17, 17, "some_type", "some_sw_version", "some_version"} ;

这是精灵读取的样子:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .hash             HASH            000000d4 0000d4 00003c 04   A  2   0  4
  [ 2] .dynsym           DYNSYM          00000110 000110 0000a0 10   A  3   5  4
  [ 3] .dynstr           STRTAB          000001b0 0001b0 000026 00   A  0   0  1
  [ 4] .rela.dyn         RELA            000001d8 0001d8 000024 0c   A  2   0  4
  [ 5] .plt              PROGBITS        00001000 001000 000000 00  AX  0   0 16
  [ 6] .text             PROGBITS        00001000 001000 00001c 00  AX  0   0  4
  [ 7] .rodata           PROGBITS        00002000 002000 000027 00   A  0   0  1
  [ 8] .dynamic          DYNAMIC         00004000 003000 000078 08  WA  3   0  4
  [ 9] .got              PROGBITS        00004078 003078 000000 00  WA  0   0  4
  [10] .got.plt          PROGBITS        00004078 003078 000010 04  WA  0   0  8
  [11] .my_custom_sectio PROGBITS        00004088 003088 000020 00  WA  0   0  4
  [12] .bss              NOBITS          000040c0 0030a8 000000 00  WA  0   0  1
  [13] .comment          PROGBITS        00000000 0030a8 000028 01  MS  0   0  1
  [14] .shstrtab         STRTAB          00000000 0030d0 000081 00      0   0  1
  [15] .symtab           SYMTAB          00000000 0033fc 000180 10     16  19  4
  [16] .strtab           STRTAB          00000000 00357c 000075 00      0   0  1

Program Headers:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x001fc 0x001fc R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x0001c 0x0001c R E 0x1000
  LOAD           0x002000 0x00002000 0x00002000 0x00027 0x00027 R   0x1000
  LOAD           0x003000 0x00004000 0x00004000 0x000a8 0x000c0 RW  0x1000
  DYNAMIC        0x003000 0x00004000 0x00004000 0x00078 0x00078 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     .hash .dynsym .dynstr .rela.dyn
   01     .text
   02     .rodata
   03     .dynamic .got.plt .my_custom_section
   04     .dynamic

在这种情况下,我的自定义部分与 .dynamic、.got.plt 部分合并并映射到段 03。我想将此部分映射为一个独立的段本身。

我们可以控制将部分映射到段吗?你会怎么做呢?

编辑:
1. 这个结构符号为什么不用dlsym:我不太热衷于将这个结构添加为动态符号的原因是我正在编写一个API来读取版本信息(我计划将其包含在一个单独的段中),这将最终决定我是否应该 dlopen 这个 SO 文件。这是避免打开过时的 SO 的安全措施的一部分。

2.使用自定义链接器脚本:我现在使用的自定义链接器脚本添加了以下部分:

.my_custom_section() :
  {
    KEEP (*version_info.o (.rodata* ))
  }

这确实让我可以创建一个所需名称的部分并将我的数据放入其中。但我仍在努力避免此部分与.rodata 或其他部分混为一谈。

我确信通过在链接描述文件中指定一些配置可以让我将此部分映射为一个独立的段,但这正是我想要弄清楚的。

【问题讨论】:

    标签: c elf


    【解决方案1】:

    这是您必须给链接器的指令。具体操作方式取决于您使用的链接器。

    对于 GNU ld,“正确”的方法是使用自定义链接器脚本,您可以使用 -T 选项提供该脚本。您可以通过键入ld --verbose 查看默认链接描述文件。其他链接器的情况类似:BSD 链接器(Mac OSX 使用的)使用命令文件(用-order_file 指定),Solaris 链接器使用映射文件(用-M 指定),等等。他们都做几乎相同的事情。

    请注意,每个平台和每个 CPU 系列通常都有自己的链接规范,因此适用于 x86_64 目标的 GNU ld 链接描述文件可能无法在 ARM 上运行,即使它们都是 Linux。 BSD 家族也有类似的情况。一般来说,您应该获取您平台的链接描述文件并根据需要进行修改。如果这是针对自定义平台的(例如,它是固件,您正在编写自己的操作系统,或者您拥有什么),您可能应该只从头开始编写自己的链接器脚本。

    如果这是需要跨平台的代码,那么就没有好的解决方案。有一些“错误”的方法可以做到这一点,例如使用objcopy 进行黑客攻击,但我不推荐它们。

    话虽如此,您可能应该问问自己这是否真的是您想要的。如果您需要一些自定义工具或框架(例如动态链接加载器)可以轻松找到的数据,您不能使用dlsym 或等效的吗?

    编辑:7 年后,我才注意到有更多信息。我希望这还不算太晚!

    GNU ld 还有两个你可能不知道的commands in its linker scripts:PHDRS 和 SECTIONS。我从来没有使用过它们,但它们会做你想做的事。

    【讨论】:

    • 查找对问题的修改。我进行了编辑以避免冗长的评论。
    【解决方案2】:

    它可能已经与您无关,但它是您正在寻找的PHDRS 命令。这是来自Using LD, the GNU linker - PHDRS的示例(稍作修改)

    PHDRS
    {
      headers PT_PHDR PHDRS ;
      interp PT_INTERP ;
      text PT_LOAD FILEHDR PHDRS ;
      data PT_LOAD ;
      dynamic PT_DYNAMIC ;
    }
    
    SECTIONS
    {
      . = SIZEOF_HEADERS;
      .interp : { *(.interp) } :text :interp
      .text : { *(.text) } :text
      .rodata : { *(.rodata) } :text /* explicitly put in :text */
      ...
      . = . + 0x1000; /* move to a new page in memory */
      .data : { *(.data) } :data
      .dynamic : { *(.dynamic) } :data :dynamic
      ...
    }
    

    这里有 5 个段:headers, interp, text, data, dynamic。 查看明确放入text 段的rodata 部分

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-18
      • 2020-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多