使用gnu链接器更改入口点

use*_*580 0 c assembly gcc ld

我有一个带有_start标签的程序集文件,作为该.text段中的第一件事.我希望这个标签成为我申请的入口点.

每当我将这个文件与另一个调用了函数的文件一起传递时main,main无论如何,该函数最终都成为我的应用程序的入口点.

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

编辑:好像是因为-O2编译器的标志.

屁股

.text
.global  _start
_start:
jmp main
Run Code Online (Sandbox Code Playgroud)

main.c中

int main(){
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

产量

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

00000000004000b3 <_start>:
  4000b3:   e9 f8 ff ff ff          jmpq   4000b0 <main>
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Mic*_*tch 6

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

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

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


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

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

/*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);
    }
}
Run Code Online (Sandbox Code Playgroud)

此脚本显式放置.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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

一个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
Run Code Online (Sandbox Code Playgroud)