[c] 符号与链接

[c] 符号与链接

我们知道,一个可执行文件的生成过程经历了一些步骤:

预处理->编译->汇编->链接

最终的步骤,是将不同的.o目标文件链接在一起,形成一个可执行文件,不同的.o文件将会引用其他.o文件内的变量或函数,那么它们是怎么找到对应的变量或函数的地址的呢?

程序装载

一个程序是怎么装载进内存的呢? 很显然,当我们在bash下直接输入程序名时,该程序就被启动了,比如"./a",就启动了当前路径下的程序a

但是我们知道,实际上shell也是一个程序,这其实是在一个程序下去启动另一个程序

实际上,会首先调用fork(),然后在子进程中中进行系统调用"execve()",执行新的程序,而父进程则"waitpid"等待子进程结束(父进程就是bash,借此我们也可以自己实现一个简单的shell)

因此,程序被执行/被装载进内存依赖一个系统调用: “execve()”

静态链接

这种链接方法会将静态链接库和自己的代码合在一起生成一个较大的可执行文件

动态链接

程序可以调用不存在于静态文件中的函数或变量

加载时

称为隐式动态链接

常规的链接手段,当使用诸如"gcc a.c -o a.out -lpthread"时,这个libpthread.so就会在程序加载时一起链接加载到内存

好处是,静态可执行程序是不需要包含整个.so动态链接库的

运行时

称为显式动态链接

还可以在程序中显式的加载动态链接库,这个在windows系统编程中是常见的,比如go语言中加载win32的api

dll := syscall.NewLazyDLL("kernel32.dll")
messageBox , _ := syscall.GetProcAddress(dll, "MessageBoxW")

通过GetProcAddress显式调用函数