顾名思义启动代码就昰使进程启动的代码。它包含了进程运行的第一条指令
每个程序都有一段启动代码。启动代码初始化进程环境调用main函数,使程序正式開始运行
glibc为我们提供了进程的启动代码,本文将详细讲解glibc提供的启动代码(基于glibc2.7)
接下来,我们将详细讲解启动代码嘚实现
让我们来看一下glibc源代码中启动代码的实现。
glibc的启动代码包含在一个汇编文件和几个c语言文件中这些文件将在本文中详细讲解。
整个代码不长也就几十行代码。代码使用汇编语言编写接下来分段解析代码实现。
清理栈帧由于在c语言函数调用中需要大量使用ebp寄存器,将其作为栈帧此处将其设置为0,这样最外层的栈帧也就为0
在明白这两句汇编代码时,需要先了解进程运行前栈的分布情况
进程运行前栈的分布情况
栈顶存放了命令行参数的个数argc,所以popl %esi将命令行参数的个数放入了esi寄存器中
argc下是命令行参数字符指针数组(argv[0]……argv[n])。movl %esp, %ecx 将esp寄存器的值赋值给ecx寄存器此时ecx寄存器指向命令行参数指针数组(argv)。
调整esp寄存器的值使其是16的倍数。便于后面的入栈操作
将eax寄存器的值压入栈中。后面会压入28个字节的数据此处压入eax使压入的数据为32字节。
将esp寄存器的值压入栈中作为用户空间最高的栈地址。
压叺共享库终止函数的地址
压入命令行参数的个数。
压入命令行参数指针数组的地址
压入main函数的地址,为后面调用main函数做准备
停机指囹,一般不会执行到此处在__libc_start_main函数中会调用exit,结束进程