使用gnu链接器更改入口点 [英] Change entry point with gnu linker

查看:202
本文介绍了使用gnu链接器更改入口点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an assembly file with a _start label as the first thing in the .text segment. I would like this label to be the entry point of my application.

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

Whenever I pass this file together with another file that have a function called main, that main function ends up being the entry point of my application no matter what.

我正在使用GNU链接器,并尝试过-e _start标志以及更改输入文件的顺序.只要存在main函数,它将成为入口点.如果我重命名main函数,则它可以正常工作,而我的_start标签成为入口点.

I am using the GNU linker and have tried the -e _start flag, along with changing the input file order. As long as there exist a main function, it will become the entry point.. If I rename the main function, it works fine and my _start label becomes the entry point.

似乎是由于对编译器的-O2标志.

Seems like it is because of -O2 flag to the compiler.

原样

.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>

有什么想法吗?

推荐答案

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

第一件事是,仅在某些情况下这样做才有价值. ELF 可执行文件的入口点编码在 ELF 标头中.入口点在可执行文件中的位置无关.

First thing is that doing this only has value in certain circumstances. An ELF executable has the entry point encoded in the ELF header. The placement of the entry point in the executable isn't relevant.

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

One special circumstance is a non-mulitboot compatible kernel where a custom bootloader loads a kernel that was generated by GCC and converted to binary output. Looking through your question history suggests that bootloader / kernel development might be a possibility for your requirement.

使用 GCC 时,您不能假定生成的代码将按照您想要的顺序排列.正如您所发现的那样,选项(如优化)可能会使功能彼此相对重新排序或完全消除某些功能.

When using GCC you can't assume that the generated code will be in the order you want. As you have found out options (like optimizations) may reorder the functions relative to each other or eliminate some altogether.

将函数首先放置在 ELF 可执行文件中的一种方法是将其放置在其自己的节中,然后创建一个链接程序脚本以将该节首先放置.应该与 C 一起使用的示例链接脚本link.ld为:

One way to put a function first in an ELF executable is to place it into its own section and then create a linker script to position that section first. An example linker script link.ld that should work with C would be:

/*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文件可以修改为执行以下操作:

This script explicitly places whatever is in the section .text.prologue before any other code. We just need to place _start into that section. Your as.s file could be modified to do this:

.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

您将像这样编译,组装和链接它们:

You'd compile, assemble and link them like this:

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应该在main之前显示函数_start:

An objdump -D test should show the function _start before 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

这篇关于使用gnu链接器更改入口点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆