使用gcc直接编译成机器码无需链接

Bol*_*dar 1 c linux x86 gcc

我想让 gcc 将我的 c 代码编译成 x86-32 linux 二进制代码,但周围没有任何库。我只想在开始时指定一个地址,它应该假设它已经加载到那里。然后我将手动从输出中构建一个 elf 文件并设置所有内容。

我知道如何使用 NASM 做这样的事情,但我有一些更复杂的事情,我不想只使用汇编程序。我不需要任何库,我将使用带有内联 asm 的纯系统调用。如果它失去一些便携性,我也不太在意。

我尝试了一些,但找不到办法做到这一点。有人不仅可以为我提供正确的设置,还可以为我提供有关编译和链接器参数的一些背景知识吗?我尝试搜索 gcc 手册,但发现它非常混乱。

Nom*_*mal 5

我想让 gcc 将我的 c 代码编译成 x86-32 linux 二进制代码,但周围没有任何库。

这意味着您编写独立的C 代码。(当标准库可用时,您就有了一个托管环境;如果没有,则是一个独立的环境。)

要将例如 foo.c 编译为可执行文件 foo,请确保它具有_start()函数,然后使用

gcc -march=i686 -mtune=generic -m32 -ffreestanding -nostdlib -nostartfiles foo.c -o foo
Run Code Online (Sandbox Code Playgroud)

GNU 工具链使用_start符号的地址来编码 ELF 文件中可执行文件的起始地址。

此答案是 x86-64 的实际示例。对于 x86-32(或任何其他架构),您需要调整SYSCALL_宏。


在评论中,OP 解释说他们想要一个二进制 blob,而不是一个 ELF 可执行文件。

在这种情况下,最好告诉编译器生成位置无关的可执行文件。例如,'blob.c':

void do_something(int arg)
{
    /* Do something with arg, perhaps a syscall,
       or inline assembly? */
}

void loop_something(int from, int to)
{
    int  arg;

    if (from <= to)
        for (arg = from; arg <= to; arg++)
            do_something(arg);
    else
        for (arg = from; arg <= to; arg--)
            do_something(arg);
}

void _start(void)
{
    loop_something(2, 5);
    do_something(6);
    loop_something(5, 2);
    do_something(1);
}    
Run Code Online (Sandbox Code Playgroud)

我建议声明除_startas之外的所有函数static,以避免任何全局偏移表 (GOT) 或过程链接表 (PLT) 引用(如<__x86.get_pc_thunk.bx>调用)。

使用例如将其编译为与位置无关的可执行文件

gcc -march=i686 -mtune=generic -m32 -O2 -fPIE -ffreestanding -nostdlib -nostartfiles blob.c -o blob
Run Code Online (Sandbox Code Playgroud)

剥它,

strip --strip-all blob
Run Code Online (Sandbox Code Playgroud)

并转储二进制文件的内容:

objdump -fd blob
Run Code Online (Sandbox Code Playgroud)

在此输出中,有两行重要的行:

start address 0x08048120
Run Code Online (Sandbox Code Playgroud)

它告诉_start符号的地址,和

080480e0 <.text>:
Run Code Online (Sandbox Code Playgroud)

它以十六进制表示代码的偏移量。后者减去前者(0x08048120 - 0x080480e0 = 0x40 = 64)得到起始符号的偏移量。

最后,使用以下命令将代码转储到原始二进制文件“blob.raw”中

objcopy -O binary -j .text blob blob.raw
Run Code Online (Sandbox Code Playgroud)