【问题标题】:In Assembly, How to insert data(or code, or symbol) at start of section?在汇编中,如何在节的开头插入数据(或代码或符号)?
【发布时间】:2019-04-26 15:53:36
【问题描述】:

我想在特定部分的开头插入一些数据(或代码或符号)。
假设在 <.got> 部分的开头插入数据0x11223344。

# gcc -o test test.s
.global main

.section .got.plt
.byte 0x11, 0x22, 0x33, 0x44

main:
 nop

但是,如您所见,
编译后,在 <.got.plt> 的 end 处附加数据。

Disassembly of section .got.plt:

080495dc <_GLOBAL_OFFSET_TABLE_>:
 80495dc:   f0 94                   lock xchg %eax,%esp
 80495de:   04 08                   add    $0x8,%al
    ...
 80495e8:   86 82 04 08 11 22       xchg   %al,0x22110804(%edx)
 80495ee:   33                      .byte 0x33
 80495ef:   44                      inc    %esp


问题:

我可以在节的开头插入数据(或代码或符号)吗?
(..是否有任何编译选项或类似汇编指令的东西?)

【问题讨论】:

  • GOT 部分是由链接器自动生成的,所以这个部分可能很难做到。通常,对于这样的事情,您需要编写自定义链接器脚本。

标签: assembly x86 binary compiler-construction elf


【解决方案1】:

这是一个链接问题,而不是组装问题。

如果您要求 GCC(或更好的 ld)显示带有 -Wl,--verbose 的链接脚本,您会找到该行

.got.plt        : { *(.got.plt)  *(.igot.plt) }

指示链接器获取所有.got.plt 部分,按照遇到的顺序。

通常,链接器会将通配符匹配的文件和部分按照在链接过程中出现的顺序放置。

来自here

由于您使用 CRT 进行编译,这意味着它自己的目标文件,您的目标文件在它之后。
我不知道这种排序是标准化的还是跨不同版本的 GCC 的任何东西,我认为它可以随时更改。

您应该能够确认将-v 和-Wl,-M 添加到GCC 的命令行;第一个将向您展示 GCC 如何调用链接器,对我来说是:

/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccref9XH.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o

很难看出来,但是test.s 目标文件是/tmp/ccref9XH.o(在完整输出的上面几行组装)并且一些CRT 目标文件在它之前被传递给collect2。

第二个选项将显示输出和输入部分之间的映射:

.got.plt        0x0000000000601000       0x25
 *(.got.plt)
 .got.plt       0x0000000000601000       0x20 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o
                0x0000000000601000                _GLOBAL_OFFSET_TABLE_
 .got.plt       0x0000000000601020        0x5 /tmp/ccisjx2P.o
                0x0000000000601024                main

显示crt1.o 的.got.plt 部分位于第一位(请注意,您将main 留在了.got.plt 部分中)。


我还没有找到一种令人满意的方法来克服这个问题。
一种可能性是复制链接描述文件并将.got.plt 定义更改为:

.got.plt        : { *(.got.plt.pre) *(.got.plt)  *(.igot.plt) }

然后您可以将您的数据放入.got.plt.pre(注意:未经测试)。
但这是可维护性的噩梦。

我正在尝试使用ld 中的--sort-section=name 将SORT 命令添加到链接器脚本中输入的每个通配符部分。
这应该根据“文件或部分名称”对齐部分。
经过几次尝试后,我查看了源代码,它实际上只是部分名称,所以在这里没有用。

我已恢复为--sort-section=alignment。
首先,文件test.s必须用gcc -c test.s -o test.o组装成一个目标文件。
这里的问题是使test.o 中的.plt.got 部分的对齐方式大于8(其他.plt.got 部分使用的对齐)。
我检查了objcopy,但什么也没找到,也许有人会找到合适的命令?
我亲自使用十六进制编辑器修补了test.o 文件,使该部分对齐为 32 字节。
然后调用gcc -Wl,--sort-section=alignment test.o -o test 会生成一个ELF,其中test.s 部分在其他部分之前。

然而,这是一个繁琐的解决方案,尽管人们可以轻松地开发一种工具来更改 ELF 部分的对齐方式,但我希望找到一个现有的工具。

很抱歉,以上都不是您问题的正确答案。

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 2019-06-28
    • 2010-12-31
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多