入口函数和程序初始化

0x01 入口函数的作用

  • 操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库中的某个入口函数。
  • 入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造,等等。
  • 入口函数在完成初始化之后,调用main函数,正式开始执行程序主体部分。
  • main 函数执行完毕以后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用结束进程。

    0x02 运行库与I/O

    什么是文件描述符

  • 在操作系统层面上,文件操作也有类似于ELF的一个概念,在Linux里,这叫做文件描述符(File Descriptor),而在Windows里,叫做句柄(Handle)
  • 内核可以通过句柄来计算出内核里文件对象的地址,但此能力并不对用户开放
  • 在程序中打开文件得到的fd从3开始增长。fd具体指什么呢?在内核中,每一个进程都有一个私有的“打开文件表”,这个表是一个指针数组,每一个元素都指向一个内核打开的文件对象,而fd,就是这个表的下标。当用户打开一个文件时,内核会在内部生成一个打开文件对象,并在这个表里找到一个空项,让这一向指向生成的打开文件对象,并返回这一项的下表做fd。由于这个表处于内核,并且用户无法访问到,因此用户即使拥有fd,也无法得到打开文件对象的地址,指能够通过系统提供的函数来操作。

    I/O初始化的职责

    在用户空间建立stdin,stdout,stderr以及其对应的FILE结构,使得程序进入main之后可以直接使用 printf、scanf 等函数。

C语言运行库

GLIBC 入口函数

glibc 的程序入口为_start

1
2
3
4
5
6
7
8
void _start()
{
%ebp = 0;
int argc = pop from stack
cgar ** argv = top of stack
__libc_start_main(main, argc, argv, __libc_csu_init, __libc_csu_fini, edx, top of stack);
}
其中argv除了指向参数表外,还隐含紧接着环境变量表。这个环境变量表要在__libc_start_main 里从argv 内提取出来。

glibc

运行库是平台相关的,因为它与操作系统结合的非常紧密。C语言的运行库从某种程度上来讲是C语言的程序和不同操作系统平台之间的抽象层,它将不同的操作系统API抽象成相同的库函数

glibc 的发布版本主要由两部分组成,一部分是头文件,比如stdio.h、stdlib.h等,它们往往位于/usr/include;另外一部分则是库的二进制文件部分

glibc 启动文件

  • “.init”和“.finit”.运行库会保证位于这两个段中的代码会先于/后于 main()函数执行。
-------------本文结束感谢您的阅读-------------
+ +