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.
我有一个带有_start标签的程序集文件,作为.text段中的第一个东西。我希望这个标签成为我申请的切入点。
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.
每当我将此文件与另一个具有main函数的文件一起传递时,无论如何,该main函数最终都成为我的应用程序的入口点。
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.
我正在使用GNU链接器并尝试了-e _start标志,同时更改了输入文件顺序。只要存在一个main函数,它就会成为入口点。如果我重命名main函数,它工作正常,我的_start标签成为入口点。
EDIT: Seems like it is because of -O2
flag to the compiler.
编辑:似乎是因为编译器的-O2标志。
as.s
.text
.global _start
_start:
jmp main
main.c
int main(){
return 0;
}
Compile
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
Output
00000000004000b0 <main>:
4000b0: 31 c0 xor %eax,%eax
4000b2: c3 retq
00000000004000b3 <_start>:
4000b3: e9 f8 ff ff ff jmpq 4000b0 <main>
Any ideas?
1 个解决方案
#1
5
It appears your question really is How can I place a particular function before all others in the generated executable?
看来您的问题确实是如何在生成的可执行文件中将所有其他函数放在特定函数之前?
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.
首先,这样做只在某些情况下才有价值。 ELF可执行文件具有在ELF头中编码的入口点。可执行文件中入口点的放置不相关。
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.
使用GCC时,您不能假设生成的代码将按您想要的顺序排列。正如您所发现的那样,选项(如优化)可能会相互重新排序函数或完全消除一些函数。
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:
将函数放在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);
}
}
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:
此脚本在任何其他代码之前显式放置.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
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
An objdump -D test
should show the function _start
before main
:
objdump -D测试应该在main之前显示函数_start:
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
#1
5
It appears your question really is How can I place a particular function before all others in the generated executable?
看来您的问题确实是如何在生成的可执行文件中将所有其他函数放在特定函数之前?
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.
首先,这样做只在某些情况下才有价值。 ELF可执行文件具有在ELF头中编码的入口点。可执行文件中入口点的放置不相关。
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.
使用GCC时,您不能假设生成的代码将按您想要的顺序排列。正如您所发现的那样,选项(如优化)可能会相互重新排序函数或完全消除一些函数。
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:
将函数放在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);
}
}
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:
此脚本在任何其他代码之前显式放置.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
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
An objdump -D test
should show the function _start
before main
:
objdump -D测试应该在main之前显示函数_start:
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