链接器的秘密
问题:源码被编译后生成目标文件,这些文件如何生成最终的可执行程序?
链接器的主要作用就是把各个模块之间的相互引用的部分处理好,使得各个模块之间能够正确的衔接
源文件 func.c
#include <stdio.h>
int* g_pointer;
void func()
{
g_pointer = (int*)"D.T.Software";
return;
}
原文件:test.c
#include <stdio.h>
int g_global = 0;
int g_test = 1;
extern int* g_pointer;
extern void func();
int main(int argc, char *argv[])
{
printf("&g_global = %p\n", &g_global);
printf("&g_test = %p\n", &g_test);
printf("&g_pointer = %p\n", &g_pointer);
printf("g_pointer = %p\n", g_pointer);
printf("&func = %p\n", &func);
printf("&main = %p\n", &main);
func();
return 0;
}
原文件:
#include <stdio.h>
#include <stdlib.h>
int program()
{
printf("D.T.Software\n");
exit(0);
}
1目标文件的特点:
1.各个段没有具体的起始地址,只有段大小信息
2.各个标识符没有实际地址,只有段中的相对地址
3.段和标识符的实际地址需要链接器具体确定
2链接器的工作内容
1.将目标文件和库文件整合为最终的可执行程序。
2.合并各个目标文件中的段(.test, .data, .bsss)
3.确定各个段和段之间的标识符的最终地址(重定位)
3 main函数的位置
3.1 mian函数的位置
问题main函数是第一个被执行的函数吗?
默认情况下(对gcc 编译器):
1.程序加载后,_start()函数是第一个被调用执行的函数(_start()函数的入口地址就是代码段(.text)的起始地址
2._start()函数准好参数(main函数、初始化函数libc_csu_fini,终止函数libc_csu_init)后立即调用_libc_start_main()函数
3._libc_start_main()函数初始化运行环境后调用main()函数
4._start 函数的地址是真个代码段的起始地址
3.1 _libc_start_main() 函数的作用:
1.调用_libc_csu_init()函数(完成必要的初始化操作)
2.启动程序的第一个线程(主线程),main()为线程入口
3.注册_libc_csu_fini()函数(程序运行终止时被调用)
3.2程序的启动过程:
4自定义程序入口函数
gcc 提供 -e 选项用于在链接时指定入口函数
自定义入口函数必须使用 -nostartfiles 选项进行链接
#include <stdio.h>
#include <stdlib.h>
int program() // entry function
{
printf(" Hello BT \n");
exit(0);
}
首先直接编译程序:
报错,找不到main函数,默认情况下,连接器工作是会去链接系统总提供的启动文件,当而默认的启动文件中最终会调用main函数。
使用编译选项 gcc -e program -nostartfiles program.c 则编译运行正常。
思考:
链接选项 -nostartfiles 的意义是什么?
在通常情况下,链接时都会使用系统启动文,该编译选项指定不使用系统的启动文件。
链接器根据说明原则完成具体的工作?
链接脚本。
5 重要链接选项
-nostartfiles // 指定入口函数
-nodefaultlibs // 不使用默认库文件
-nostdlib // 不使用标准库函数
转载于:https://blog.51cto.com/11134889/2072456