链接器如何找到主函数?

时间:2013-07-17 19:31:53

标签: assembly x86 x86-64

链接器如何在x86-64 ELF格式的可执行文件中找到main函数?

2 个答案:

答案 0 :(得分:2)

非常通用的概述,链接器将地址分配给由符号main标识的代码块。就像对象文件中的所有符号一样。

实际上,它并没有分配一个真实的地址,而是分配一个相对于某个基地的地址,当程序执行时,它将被加载器转换为一个真实的地址。

实际入口点不太可能是main,而是在crt中调用main的一些符号。默认情况下,LD会查找符号start,除非您指定something different

链接代码最终位于可执行文件的.text部分,看起来像这样(非常简化):

Address | Code
1000      someFunction
...
2000      start
2001        call 3000
...
3000      main
...

当链接器写入ELF头时,它会将入口点指定为地址2000。

您可以通过使用main之类的内容转储可执行文件的内容来获取objdump的相对地址。要在运行时获取实际地址,您只需读取符号funcptr ptr = main;,其中funcptr被定义为指向签名为main的函数的指针。

typedef int (*funcptr)(int argc, char* argv[]);

int main(int argc, char* argv[])
{
    funcptr ptr = main;
    printf("%p\n", ptr);
    return 0;
}

无论是否已剥离符号,都将正确解析main的地址,因为链接器将首先将符号main解析为其相对地址。

像这样使用objdump:

$ objdump -f funcptr.exe 

funcptr.exe:     file format pei-i386
architecture: i386, flags 0x0000013a:
EXEC_P, HAS_DEBUG, HAS_SYMS, HAS_LOCALS, D_PAGED
start address 0x00401000

专门寻找main,在我的机器上我得到了这个:

$ objdump -D funcptr.exe | grep main
  40102c:       e8 af 01 00 00          call   4011e0 <_cygwin_premain0>
  401048:       e8 a3 01 00 00          call   4011f0 <_cygwin_premain1>
  401064:       e8 97 01 00 00          call   401200 <_cygwin_premain2>
  401080:       e8 8b 01 00 00          call   401210 <_cygwin_premain3>
00401170 <_main>:
  401179:       e8 a2 00 00 00          call   401220 <___main>
004011e0 <_cygwin_premain0>:
004011f0 <_cygwin_premain1>:
00401200 <_cygwin_premain2>:
00401210 <_cygwin_premain3>:
00401220 <___main>:

请注意,我在Windows上使用Cygwin,因此您的结果会略有不同。看起来main生活在00401170对我来说。

答案 1 :(得分:0)

在Binutils上,它由以下两者决定:

  • -e CLI选项
  • 链接描述文件

您可以使用以下命令查看链接描述文件:

ld --verbose

我的包含:

ENTRY(_start)

然后在链接时,glibc提供的包含crt1.o符号的_start对象文件与main.o一起传递给链接器。

这些目标文件为argv做了一些设置,然后调用main函数。

您可以使用gcc -v隐藏这些额外的目标文件。

记录于:https://sourceware.org/binutils/docs/ld/Entry-Point.html#Entry-Point

  

在程序中执行的第一条指令称为入口点。您可以使用ENTRY链接描述文件命令设置入口点。参数是符号名称:

 ENTRY(symbol)
  

有几种方法可以设置入口点。链接器将按顺序尝试以下每个方法来设置入口点,并在其中一个成功时停止:

     
      
  • `-e&#39;进入命令行选项;
  •   
  • 链接描述文件中的ENTRY(符号)命令;
  •   
  • 目标特定符号的值,如果已定义;对于许多目标而言,这是开始,但是基于PE和BeOS的系统例如检查可能的条目符号列表,匹配找到的第一个符号。
  •   
  • `.text&#39;的第一个字节的地址部分,如果存在;
  •   
  • 地址0。
  •   

另请参阅:is there a GCC compiler/linker option to change the name of main?