Linux x86-64 静态链接程序的运行过程

2017-05-09  本文已影响0人  ThdLee

本文主要讲述在Linux x86-64中,静态链接程序(即不使用任何共享库(shared libaray)的程序)的运行过程。

序章

C/C++程序员在写程序时,总是默认程序是从main函数开始的,我们会认为这理所当然,但事实上,当程序在执行到main函数时,很多事情已经完成了。我们可以看看一下几个例子:

#include <stdio.h>
int a = 10;
int main(int argc, const char * argv[]) {
    printf("%d\n", argc);
    printf("%d\n", a);
    return 0;
}

在运行main函数的时候,全局变量a已经初始化完成,并且main的两个参数argcargv已经被传了进来。

#include <stdio.h>
__attribute((constructor)) void before_main()
{
    printf("%s\n",__FUNCTION__);
}

__attribute((destructor)) void after_main()
{
    printf("%s\n",__FUNCTION__);
}
int main(int argc, const char * argv[]) {
    return 0;
}

执行结果:

before_main
main
after_main

构造函数before_main会在main函数开始之前被调用,析构函数after_main会在main函数结束之后被调用。

而C++中,main函数之前所能执行的代码还会更多。所以,main函数既不是一个程序的开始,也不是一个程序的结束。那么,一个程序到底是怎样开始和结束的呢,main函数前后到底发生了那些事呢?这就是我们要讨论的话题。

Linux内核装载ELF过程

当我们在Linux系统的bash下输入一个命令执行某个ELF程序时,bash进程会调用fork系统调用创建一个新的进程,然后新的进程会调用exec系统调用执行指定的ELF文件。

C程序的开始和结束

内核通过exec运行一个进程,在C start-up routine中,系统会自动调用一些初始化函数,再执行main函数,然后通过调用exit,先执行那些通过atexit注册的函数,再进行一些收尾工作,最后使用_exit结束进程。


要想进一步了解,可以阅读以下资料:

  1. How statically linked programs run on Linux
  2. Linux x86 Program Start Up
  3. 《深入理解计算机系统》
  4. 《程序员的自我修养》
  5. 《UNIX环境高级编程》
上一篇 下一篇

猜你喜欢

热点阅读