如何将文本文件的内容添加为ELF文件中的部分?

时间:2017-02-14 20:02:25

标签: linker x86 nasm elf objcopy

我有一个NASM程序集文件,我正在组装和链接(在Intel-64 Linux上)。

有一个文本文件,我希望文本文件的内容出现在生成的二进制文件中(基本上是一个字符串)。二进制文件是ELF可执行文件。

我的计划是在ELF文件中创建一个新的只读数据部分(相当于传统的./部分)。

理想情况下,会有一个工具可以逐字添加文件作为elf文件中的新部分,或者是一个逐字包含文件的链接器选项。

这可能吗?

1 个答案:

答案 0 :(得分:21)

使用 BINUTILS 中的OBJCOPY可以轻松完成此操作。您有效地将数据文件作为二进制输入,然后将其输出为可链接到您的程序的目标文件格式。

OBJCOPY 甚至会生成一个开始和结束符号以及数据区域的大小,以便您可以在代码中引用它们。基本的想法是你要告诉它你的输入文件是二进制文件(即使它是文本);您将瞄准x86-64目标文件;指定输入文件名和输出文件名。

假设我们有一个名为myfile.txt的输入文件,其内容为:

the
quick
brown
fox
jumps
over
the
lazy
dog

这样的事情将成为一个起点:

objcopy --input binary \
    --output elf64-x86-64 \
    --binary-architecture i386:x86-64 \
    myfile.txt myfile.o

如果要生成32位对象,可以使用:

objcopy --input binary \
    --output elf32-i386 \
    --binary-architecture i386 \
    myfile.txt myfile.o

输出将是一个名为myfile.o的目标文件。如果我们使用 OBJDUMP objdump -x myfile.o这样的命令查看目标文件的标题,我们会看到如下内容:

myfile.o:     file format elf64-x86-64
myfile.o
architecture: i386:x86-64, flags 0x00000010:
HAS_SYMS
start address 0x0000000000000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .data         0000002c  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 g       .data  0000000000000000 _binary_myfile_txt_start
000000000000002c g       .data  0000000000000000 _binary_myfile_txt_end
000000000000002c g       *ABS*  0000000000000000 _binary_myfile_txt_size

默认情况下,它会创建一个包含文件内容的.data部分,并创建一些可用于引用数据的符号。

_binary_myfile_txt_start
_binary_myfile_txt_end
_binary_myfile_txt_size

这实际上是起始字节,结束字节的地址,以及从文件myfile.txt放入对象的数据大小。 OBJCOPY 将基于输入文件名的符号。 myfile.txt被修改为myfile_txt并用于创建符号。

一个问题是创建了一个.data部分,它是读/写/数据,如下所示:

Idx Name          Size      VMA               LMA               File off  Algn
  0 .data         0000002c  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA

您具体要求的.rodata部分也指定了 READONLY 标志。您可以使用--rename-section选项将.data更改为.rodata并指定所需的标记。您可以将其添加到命令行:

--rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA

当然,如果您想使用与.rodata相同的标记来调用除.rodata之外的部分,您可以将上面一行中的objcopy --input binary \ --output elf64-x86-64 \ --binary-architecture i386:x86-64 \ --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA \ myfile.txt myfile.o 更改为您要用于的名称部分。

应该生成所需对象类型的命令的最终版本是:

main.c

现在您有了一个目标文件,如何在 C 代码中使用它(作为示例)。生成的符号有点不寻常,OS Dev Wiki

有合理的解释
  

一个常见问题是在尝试使用链接描述文件中定义的值时获取垃圾数据。这通常是因为他们取消引用该符号。链接描述文件中定义的符号(例如_ebss =。;)只是一个符号,而不是一个变量。如果使用extern uint32_t _ebss访问该符号;然后尝试使用_ebss代码将尝试从_ebss指示的地址读取32位整数。

     

对此的解决方案是将_ebss的地址用作& _ebss或将其定义为unsized数组(extern char _ebss [];)并转换为整数。 (数组表示法可防止从_ebss中意外读取,因为必须明确地取消引用数组)

记住这一点,我们可以创建名为#include <stdint.h> #include <stdlib.h> #include <stdio.h> /* These are external references to the symbols created by OBJCOPY */ extern char _binary_myfile_txt_start[]; extern char _binary_myfile_txt_end[]; extern char _binary_myfile_txt_size[]; int main() { char *data_start = _binary_myfile_txt_start; char *data_end = _binary_myfile_txt_end; size_t data_size = (size_t)_binary_myfile_txt_size; /* Print out the pointers and size */ printf ("data_start %p\n", data_start); printf ("data_end %p\n", data_end); printf ("data_size %zu\n", data_size); /* Print out each byte until we reach the end */ while (data_start < data_end) printf ("%c", *data_start++); return 0; } C 文件:

gcc -O3 main.c myfile.o

您可以编译并链接:

data_start 0x4006a2
data_end   0x4006ce
data_size  44
the
quick
brown
fox
jumps
over
the
lazy
dog

输出应该类似于:

nmain.asm

NASM 使用示例在性质上与 C 代码类似。以下名为bits 64 global _start extern _binary_myfile_txt_start extern _binary_myfile_txt_end extern _binary_myfile_txt_size section .text _start: mov eax, 1 ; SYS_Write system call mov edi, eax ; Standard output FD = 1 mov rsi, _binary_myfile_txt_start ; Address to start of string mov rdx, _binary_myfile_txt_size ; Length of string syscall xor edi, edi ; Return value = 0 mov eax, 60 ; SYS_Exit system call syscall 的汇编程序使用Linux x86-64 System Calls将相同的字符串写入标准输出:

nasm -f elf64 -o nmain.o nmain.asm
gcc -m64 -nostdlib nmain.o myfile.o

这可以通过以下方式组合和链接:

the
quick
brown
fox
jumps
over
the
lazy
dog

输出应显示为:

destroyAllWindows();