11运行库

第十一章 运行库
静态 glibc
 
1     入口函数和程序初始化
入口函数 :在 main 函数之前和之后运行的函数称为入口函数或入口点( entry point )。
一个典型的程序运行如下:
(1)       进程创建,控制权交给入口点,入口点为运行库中的入口函数
(2)       入口函数对运行库和程序运行环境进行初始化,包括堆, I/O 、线程、全局变量构造等
(3)       初始化后,调用 main 函数
(4)       Main 函数完毕,调用入口函数,做清理工作,包括全局变量析构、堆销毁、关闭 I/O ,然后系统调用结束进程。
 
Glibc 入口函数
Glibc 的入口为 _start ,该入口为 ld 链接器默认的链接脚本指令的。 i386 的源码如下:
libc\sysdeps\i386\elf\Start.S
_start:
xorl %ebp,       %ebp
popl   %esi
movl  $esp                   %ecx
 
pushl          %esp                                     //sp
pushl          %edx                                     //rtld_fini
pushl          $__libc_csu_fini                 //fini
pushl          $__libc_csu_init                //init
pushl          %ecx                                     //ubp_av
pushl          %esi                                      //argc
pushl          main                                     //main
call              __libc_start_main
上面右边注释几位 __libc_start_main 的参数。 __libc_start_main 的工作如下:
__pthread_initialize_minimal();
_cax_atexit(rtld_fini, NULL, NULL);
__libc_init_first(argc, argv, __environ);
__cxa_atexit(fini, NULL, NULL);
(*init)(argc, argv, __environ);
加粗部分为注册函数, main 函数结束时调用。在 __libc_start_main 末尾有:
result = main(argc, argv, __environ);
exit ( result );
exit 函数中,依次调用注册过的函数,然后调用 _exit 系统调用。因为程序要么按 main 函数返回,要么 exit() 结束,都要进入 exit 函数,能保证注册函数顺利结束。
 
MSVC CRT 入口函数
 
运行库与I/O
用户打开一个文件,获得该文件的文件描述符( file description )或者句柄。文件句柄总是内核的文件对象相关联的。 fd 0 1 2 分别代表标准输入、标准输出和错误输出。那么 fd 是什么呢?
每个进程都有一个私有的“打开文件表”,该表由操作系统内核管理,打开文件表是一个指针数组,而 fd 则是数组的下表。
I/O 初始化的职责是:需要在用户空间中建立 stdio stdout stderr 及其他对应的 FILE 结构,使得程序进入 main 之后可以直接使用 printf scanf 等函数。
 
2     C/C++ 运行库
C 语言运行库
C 语言标准库
Glibc 的启动文件
Glibc 除了 C 标准库之外,还有几个辅助程序运行时的运行库。分别是 crt1.o crti.o crtn.o
Crt1.o 中包含 _start ,由它负责调用 __libc_start_main 初始化 libc 并且调用 main 函数。由于 C++ ELF 文件改进,出现了在 main 函数之前 \ 后执行的全局 \ 静态对象的构造和析构,在目标文件中引入了 .init .finit 。链接器在静态链接时会把输入目标文件总的 .init .finit 段收集起来,并且与 crti.o crtn.o 中的指令进行合并,形成一个 .init .finit 。其中 crti.o crtn.o 中的内容是整个初始化段的前部分和后部分。经过连接后,最终的形成 _init() _finit 两个函数,由 __libc_csu_init __libc_csu_fini 调用。
GCC 平台相关的文件
crtbeginT.o crtend.o 实现 C++ 全局对象的构造和析构。 .init .finit 段提供了一个在 main 之前和之后运行代码的机制,真正全局构造和析构则由 crtbeginT.o crtend.o 完成。
libgcc.a GCC 提供的一个仿真计算库,软件仿真各种硬件不提供的运算。
libgcc_eh.a 支持 C++ 的异常处理。
 
3     运行库与多线程
4     C++ 全局构造与析构
_start à__libc_start_main àinit\__libc_csu_init à_init
这里的 _init 正是 crti 中的 _init() 函数,经过反汇编,可以发现函数进入了
_start à__libc_start_main àinit\__libc_csu_init à_init à__do_global_crt_aux
__do_global_crt_aux 中有对 __CTOR_LIST__[i] 的循环调用。
GCC 在编译某个文件时,会遍历该文件中的所有全局对象,生成一个特殊的函数,对全局对象进行构造和析构:(以 helloworld 为例)
Static void GLOBAL__I_Hw(void)
{
           Hw::Hw();                  // 构造
Atexit(__tcf_1);        // 析构
}
GCC 会在该文件的目标文件中生成 .ctors ,存放指向改函数的指针。
链接器在链接的时候,所有的 .ctors 段被合并成一个 .ctors 段,因为合并后的 .ctors 成了一个指针数组,存放全局构造函数的地址列表 __CTOR_LIST__
在链接的时候, crtbegin.o crtend.o 也包含 .ctors 段, crtbegin.o 作为其实,存放的内容为 -1 ,会被链接器修改为全局构造函数的数量,并且将起始地址定义为 __CTOR_LIST__ crtend.o 段的内容为全 0 ,并定义符号 __CTOR_END__ 指令段尾。
析构刚好相反,命名跟构造函数对应。
5     fread 实现

你可能感兴趣的:(职场,休闲,程序员的自我修养,运行库,连接装载和库)