一个非常通用的概述,链接器将地址分配给由符号标识的代码块main
。正如它对目标文件中的所有符号所做的那样。
实际上,它并不分配真实地址,而是分配相对于某个基址的地址,该基址将在程序执行时由加载器转换为真实地址。
实际的切入点不太可能main
但 crt 中的一些符号调用 main. LD 默认查找符号start
除非你指定有些不同 http://www.math.utah.edu/docs/info/ld_3.html#SEC19.
链接的代码最终位于.text
可执行文件的部分,可能看起来像这样(非常简单):
Address | Code
1000 someFunction
...
2000 start
2001 call 3000
...
3000 main
...
当链接器写入 ELF 头时,它将指定入口点为地址 2000。
可以得到相对地址main
通过转储可执行文件的内容objdump
。要在运行时获取实际地址,您只需读取符号即可funcptr ptr = main;
where 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
for me.