Linker 如何将文本文件的内容作为节添加到ELF文件中?

Linker 如何将文本文件的内容作为节添加到ELF文件中?,linker,x86,nasm,elf,objcopy,Linker,X86,Nasm,Elf,Objcopy,我有一个正在组装和链接的NASM程序集文件(在Intel-64 Linux上) 有一个文本文件,我希望文本文件的内容显示在结果二进制文件中(基本上是字符串)。二进制文件是ELF可执行文件 我的计划是在ELF文件中创建一个新的只读数据节(相当于传统的.rodata节) 理想情况下,有一个工具可以将文件逐字添加为elf文件中的新部分,或者有一个链接器选项可以包含文件逐字 这是可能的吗?这是可能的,并且最容易使用BINUTILS中的。您可以有效地将数据文件作为二进制输入,然后将其输出为可链接到程序的对

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

有一个文本文件,我希望文本文件的内容显示在结果二进制文件中(基本上是字符串)。二进制文件是ELF可执行文件

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

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


这是可能的吗?

这是可能的,并且最容易使用BINUTILS中的。您可以有效地将数据文件作为二进制输入,然后将其输出为可链接到程序的对象文件格式

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\u txt
并用于创建符号

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

Idx Name          Size      VMA               LMA               File off  Algn
  0 .data         0000002c  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
您特别请求的是一个
.rodata
节,该节还将指定只读标志。您可以使用
--rename部分
选项将
.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
既然有了一个对象文件,如何在C代码中使用它(作为示例)。生成的符号有点不寻常,下面有一个合理的解释:

一个常见的问题是在尝试使用链接器脚本中定义的值时获取垃圾数据。这通常是因为他们正在取消对符号的引用。链接器脚本中定义的符号(例如_ebss=.;)只是一个符号,而不是变量。如果使用外部uint32\u t\u ebss访问符号;然后尝试使用_ebss,代码将尝试从_ebss指示的地址读取32位整数

解决方法是将_ebss的地址作为&_ebss使用,或者将其定义为无大小的数组(extern char _ebss[]),并强制转换为整数。(数组表示法防止意外读取_ebs,因为必须显式取消引用数组)

记住这一点,我们可以创建名为
main.C
的C文件:

#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;
}
输出应该类似于:

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

NASM的用法示例本质上与C代码类似。以下名为
nmain.asm
的汇编程序使用以下命令将相同的字符串写入标准输出:

这可以通过以下方式进行组装和链接:

nasm -f elf64 -o nmain.o nmain.asm
gcc -m64 -nostdlib nmain.o myfile.o
输出应显示为:

the
quick
brown
fox
jumps
over
the
lazy
dog

非常有教育意义,是雨天的“珍宝”!我不明白为什么_size参数会如此巨大,按照这种方法,我原来的.dat文件是973字节,objcopy o文件是1584字节,
(size\u t)二进制文件\u myfile\u txt\u size
是94570554139597:\
(\u end-\u start)
是正确的973大小。我误解了什么?@Thorcaller:你能把你所有的C代码都放在一个粘贴箱里吗?
nasm -f elf64 -o nmain.o nmain.asm
gcc -m64 -nostdlib nmain.o myfile.o
the
quick
brown
fox
jumps
over
the
lazy
dog