程序入口

程序的入口

加载

linux可执行文件都是通过调用execve函数来调用加载器的.

加载器将可执行文件的代码和数据从磁盘拷贝到内存中, 然后通过第一条指令来查找程序运行的入口, 从而执行整个程序. 而将数据从磁盘复制到内存的过程就叫做加载.

程序的入口

通过从内核设置的第一条指令找到程序的入口, 一般gcc默认编译程序的入口是_libc_start_main这一个默认函数, 而默认函数的入口又是存放在段<_start>里面. _start函数调用系统启动函数, 它初始化环境, 调用用户层的main函数, 处理main函数的返回值, 最后将返回值返回给内核处理.

一个简单的代码

int main()
{ }

执行

gcc main.c

在执行

objdump a.out -d 
# 如果适合看intel的汇编, 可加上 -M intel 即可

程序入口_第1张图片

可以看到, call __libc_start_main调用此函数, 而它是在<_start> 段中 . 在<_start>断之前还有3个段.

<_init>段程序会初始化调用ELF.init函数. 有兴趣可以去查一下ELF.

如果想要自己来设置程序的入口的, 可以在gcc中添加禁用mian入口的命令

gcc -nostartfiles -e 入口 filename.c

-nostartfiles : 关掉gcc默认的main函数作为入口

-e : 设置程序开始的入口

// 简单的尝试
#include 
#include 
void print()
{
    printf("print\n");
    exit(0);
}

如果在程序的结尾处没有加上exit函数, 调用return也会出错, 报出断错误. 这里主要是exit函数会直接告诉系统该程序退出, 而return只是将程序返回, 我们并没有将程序地址压栈, 所以return返回的地址就会产生越界, 连个如果都没有, 那么程序也就不知道它自己执行结束.

程序入口_第2张图片

同样我们objdump看一下, 此时程序的入库设置成了print函数, 结束的时候在调用exit, 杀死该进程.

程序入口_第3张图片

没有调用exit的函数, 则显示的便是这样.

对exit和return不太区分的, 也可以看看这一篇博客.exit和return的区别

如果是自己写的OS程序启动, 可在boot.s中修改入口, call 入口函数名就行了

你可能感兴趣的:(c/c++,C++基础学习)