【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
ld - the GNU linker
1. 链接器的主要作用
把各个模块(.o 目标文件)之间相互引用的部分处理好, 使得各个模块(.o 目标文件)之间能够正常地衔接, 最终生成可执行程序.
链接器整合的对象是目标文件(*.o), 离开链接器, 目标文件就像无头苍蝇一样无法执行.
目标文件的秘密
- 各个段没有具体的起始地址, 只有段大小信息;
- 各个标识符没有实际地址, 只有段中的相对地址;
- 段与标识符的实际地址需要链接器具体确定.
$nm file.o
0000000000000000 T func
U _GLOBAL_OFFSET_TABLE_
0000000000000013 T main
U puts
2. 链接器的工作内容
将目标文件与库文件整合成为最终的可执行程序:
- 合并各个目标文件中的段(.text .data .bss)
- 确定各个段和段中标识符的最终地址(重定位)
$nm file
0000000000000830 t atexit
0000000000201010 B __bss_start
0000000000201010 b called.4604
0000000000201014 b completed.7698
U __cxa_atexit@@GLIBC_2.2.5
w __cxa_finalize@@GLIBC_2.2.5
0000000000201000 D __data_start
0000000000201000 W data_start
00000000000006a0 t deregister_tm_clones
0000000000000690 T _dl_relocate_static_pie
0000000000000730 t __do_global_dtors_aux
0000000000200da8 t __do_global_dtors_aux_fini_array_entry
0000000000201008 D __dso_handle
0000000000200db0 d _DYNAMIC
0000000000201010 D _edata
0000000000201018 B _end
0000000000000849 T etext
0000000000000840 T _fini
0000000000000770 t frame_dummy
0000000000200da0 t __frame_dummy_init_array_entry
0000000000000a1c r __FRAME_END__
000000000000077a T func
0000000000200fa0 d _GLOBAL_OFFSET_TABLE_
0000000000000640 T __gmon_start__
0000000000000858 r __GNU_EH_FRAME_HDR
00000000000005a0 T _init
0000000000200da8 t __init_array_end
0000000000200da0 t __init_array_start
000000000000084c R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000820 T __libc_csu_fini
00000000000007b0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000000793 T main
U _mcleanup@@GLIBC_2.2.5
U mcount@@GLIBC_2.2.5
U __monstartup@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
00000000000006e0 t register_tm_clones
0000000000000610 T _start
0000000000201010 D __TMC_END__
由上述结果可见, func.o的0000000000000000 T func和0000000000000013 T main被成功整合到了最终的可执行文件中, 且由相对地址变成了绝对地址(即当程序运行时会被放置的地址): 000000000000077a T func和0000000000000793 T main.
3. 结语
在本文章中, 我只想表现出链接器的作用, 而没有告诉大家怎么使用ld命令. 因为我发现, ld命令还真的挺难用的. 举个例子, 还是回到了我们的file,c文件.
$ld file.o
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
file.o: In function `func':
file.c:(.text+0xc): undefined reference to `puts'
实际上我们的gcc也是调用了ld命令完成了链接操作, 具体的链接参数(链接脚本)可以通过以下方式获得:
$ld --verbose > default.lds
ld命令我没有细看, 毕竟我觉得看太深对自己没有用处, 而且, gcc不香吗?
$gcc file.o -o file