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