使用gnu链接器更改入口点

时间:2017-02-17 15:37:34

标签: c assembly ld

我有一个_start标签的汇编文件作为.text细分中的第一件事。我希望这个标签成为我申请的切入点。

每当我将此文件与另一个具有名为main的函数的文件一起传递时,无论如何,main函数最终都会成为我的应用程序的入口点。

我正在使用GNU链接器并尝试了-e _start标志,同时更改了输入文件顺序。只要存在main函数,它就会成为入口点。如果我重命名main函数,它工作正常,我的_start标签成为入口点。

编辑:似乎是因为编译器的-O2标志。

as.s

.text
.global  _start
_start:
jmp main

的main.c

int main(){
    return 0;
}

编译

gcc -O2 -c as.s -o as.o
gcc -O2 -c main.c -o main.o
ld -e _start as.o main.o -o test

输出

00000000004000b0 <main>:
  4000b0:   31 c0                   xor    %eax,%eax
  4000b2:   c3                      retq   

00000000004000b3 <_start>:
  4000b3:   e9 f8 ff ff ff          jmpq   4000b0 <main>

有什么想法吗?

1 个答案:

答案 0 :(得分:5)

看来您的问题确实是如何在生成的可执行文件中将所有其他函数放在特定函数之前?

首先,这样做只在某些情况下有价值。 ELF 可执行文件的入口点编码在 ELF 标头中。可执行文件中的入口点的放置是不相关的。

一个特殊情况是非兼容mulitboot的内核,其中自定义引导加载程序加载由 GCC 生成并转换为二进制输出的内核。查看您的问题历史表明,引导加载程序/内核开发可能符合您的要求。

使用 GCC 时,您不能假设生成的代码将按您想要的顺序排列。正如您所发现的那样,选项(如优化)可能会相互重新排序,或完全消除一些。

将函数放在 ELF 可执行文件中的一种方法是将其放入自己的部分,然后创建一个链接描述文件以首先定位该部分。应该与 C 一起使用的示例链接描述文件link.ld将是:

/*OUTPUT_FORMAT("elf32-i386");*/
OUTPUT_FORMAT("elf64-x86-64");

ENTRY(_start);

SECTIONS
{
    /* This should be your memory offset (VMA) where the code and data
     * will be loaded. In Linux this is 0x400000, multiboot loader is
     * 0x100000 etc */
    . = 0x400000;

    /* Place special section .text.prologue before everything else */
    .text : {
        *(.text.prologue);
        *(.text*);
    }

    /* Output the data sections */
    .data : {
        *(.data*);
    }

    .rodata : {
        *(.rodata*);
    }

    /* The BSS section for uniitialized data */
    .bss : {
        __bss_start = .;
        *(COMMON);
        *(.bss);
        . = ALIGN(4);
        __bss_end = .;
    }

    /* Size of the BSS section in case it is needed */
    __bss_size = ((__bss_end)-(__bss_start));

    /* Remove the note that may be placed before the code by LD */
    /DISCARD/ : {
        *(.note.gnu.build-id);
    }
}

此脚本在任何其他代码之前显式放置.text.prologue部分中的内容。我们只需要将_start放入该部分。您的as.s文件可以修改为执行此操作:

.global  _start

# Start a special section called .text.prologue making it
# allocatable and executable
.section .text.prologue, "ax"

_start:
jmp main

.text
# All other regular code in the normal .text section

你可以像这样编译,汇编和链接它们:

gcc -O2 -c main.c -o main.o
gcc -O2 -c as.s -o as.o
ld -Tlink.ld main.o as.o -o test

objdump -D test应在_start之前显示功能main

test:     file format elf32-i386


Disassembly of section .text:

00400000 <_start>:
  400000:       e9 0b 00 00 00          jmp    400010 <main>
  400005:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%eax,%eax,1)
  40000c:       00 00 00
  40000f:       90                      nop

00400010 <main>:
  400010:       31 c0                   xor    %eax,%eax
  400012:       c3                      ret