Linux应用程序的启动流程
目录
代码
用strace查看调用流程
分析
总结
看到一篇好文:摘抄记录--Linux应用程序 启动流程-BugMan-ChinaUnix博客
代码
#include <stdio.h>int main (int argc, char *argv[])
{printf ("Hello World\n");return 0;
}
用strace查看调用流程
pc123@ubuntu:~/Public$ strace ./main execve("./main", ["./main"], 0x7fff3906f3d0 /* 56 vars */) = 0 brk(NULL) = 0x55d0fc755000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=81045, ...}) = 0 mmap(NULL, 81045, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe65b878000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\35\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe65b876000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe65b272000 mprotect(0x7fe65b459000, 2097152, PROT_NONE) = 0 mmap(0x7fe65b659000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fe65b659000 mmap(0x7fe65b65f000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe65b65f000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7fe65b8774c0) = 0 mprotect(0x7fe65b659000, 16384, PROT_READ) = 0 mprotect(0x55d0fa83f000, 4096, PROT_READ) = 0 mprotect(0x7fe65b88c000, 4096, PROT_READ) = 0 munmap(0x7fe65b878000, 81045) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0 brk(NULL) = 0x55d0fc755000 brk(0x55d0fc776000) = 0x55d0fc776000 write(1, "hello world", 11hello world) = 11 exit_group(0) = ? +++ exited with 0 +++ pc123@ubuntu:~/Public$
分析
- 毫无疑问,在shell内执行一个程序main,本质上是shell去调用execve函数执行main程序
- execve是一个系统调用,Linux内核会在这个系统调用里面为main程序映射必要的内存
- 动态解释器【动态解释器】:当execve将控制权给/lib64/ld-linux-x86-64.so.2的时候,这个文件进行动态库代码重定向等功能
$ readelf -l hello | grep interpreter[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
- 通过读取elf头部信息中的entry部分,即可得到程序入口地址为0x540
pc123@ubuntu:~/Public$ readelf -h main ELF Header:Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64Data: 2's complement, little endianVersion: 1 (current)OS/ABI: UNIX - System VABI Version: 0Type: DYN (Shared object file)Machine: Advanced Micro Devices X86-64Version: 0x1Entry point address: 0x540Start of program headers: 64 (bytes into file)Start of section headers: 6448 (bytes into file)Flags: 0x0Size of this header: 64 (bytes)Size of program headers: 56 (bytes)Number of program headers: 9Size of section headers: 64 (bytes)Number of section headers: 29Section header string table index: 28 pc123@ubuntu:~/Public$
- 通过objdump找到程序的入口地址:
pc123@ubuntu:~/Public$ objdump -axd main > main.s
在main.s文件找到地址为0x540的代码
Disassembly of section .text: 段名:.text,表示代码段0000000000000540 <_start>: 函数名_start,存放地址0x540540: 31 ed xor %ebp,%ebp542: 49 89 d1 mov %rdx,%r9545: 5e pop %rsi546: 48 89 e2 mov %rsp,%rdx549: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp54d: 50 push %rax54e: 54 push %rsp54f: 4c 8d 05 8a 01 00 00 lea 0x18a(%rip),%r8 # 6e0 <__libc_csu_fini>556: 48 8d 0d 13 01 00 00 lea 0x113(%rip),%rcx # 670 <__libc_csu_init>55d: 48 8d 3d e6 00 00 00 lea 0xe6(%rip),%rdi # 64a <main>564: ff 15 76 0a 20 00 callq *0x200a76(%rip) # 200fe0 <__libc_start_main@GLIBC_2.2.5>56a: f4 hlt 56b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
可见在shell执行main程序,程序的入口是_start函数,这个_start函数实际上是由C库实现的,
_start函数最后调用了__libc_start_main函数【汇编的callq *0x200a76这一行】,而调用__libc_start_main函数传入了0x54f, 0x556, 0x55d对应的这三个参数,其中对应的就是__libc_csu_fini, __libc_csu_initial, main函数【也就是我们写的代码】
【__libc_start_main@plt表示这是一个延迟加载函数,什么是延迟加载函数呢?延迟加载函数就是指在动态解释阶段不进行代码重定位,只有在真正使用该函数的时候,才去定位该函数的地址, 这样做的目的是加快程序启动】
__libc_start_main函数的运行的顺序为:__libc_csu_init->main->__libc_csu_fini,__libc_csu_init叫构造函数,__libc_csu_fini叫析构函数,在代码中可通过__attribute__ ((constructor))标记构造函数,__attribute__ ((destructor))来标记析构函数 有这样的例子
#include <stdio.h>static void hello_after() __attribute__ ((destructor)); static void hello_before() __attribute__ ((constructor));static void hello_before(void) {printf("Before main\n"); }static void hello_after(void) {printf("After main\n"); }int main (int argc, char *argv[]) {printf ("Hello World\n");return 0; }
pc123@ubuntu:~/Public$ ./main Before main Hello World After main pc123@ubuntu:~/Public$
总结
shell通过execve启动main程序------->main函数被C 库作为一个函数----------->整个程序的入口地址是_start【通过objdump对应的0x540确定】----->start函数调用了__libc_start_main,传入了构造,main, 析构函数。
Linux应用程序的启动流程相关推荐
- Android应用程序进程启动流程
在学习应用程序进程启动流程前,先要弄清楚系统启动流程,如果有不清楚的同学,建议先看下以前博主的文章: Android系统启动(上篇)_AD钙奶-lalala的博客-CSDN博客 Android系统启动 ...
- linux系统下开机启动流程
在了解开机启动流程之前,还是得先了解一些磁盘的基本知识.磁盘主要由盘片,机械手臂,磁头,主轴马达构成.盘片就是存储数据的物理单位了.然后盘片上我们可以分成扇区(sector)和柱面(cylinder) ...
- Note For Linux By Jes(14)-启动流程、模块管理与 Loader
Linux的启动流程分析: 启动流程一览 加载BIOS 的硬件资讯与进行自我测试,并依据配置取得第一个可启动的装置: 读取并运行第一个启动装置内MBR 的boot Loader (亦即是grub, s ...
- iOS 应用程序的启动流程及其代理
应用程序的启动步骤 main函数调用UIApplicationMain. UIApplicationMain创建了一个UIApplication UIApplicationMain创建了一个AppDe ...
- Linux下程序开机启动
2019独角兽企业重金招聘Python工程师标准>>> 这个不是指apache这样的service程序. 指进入桌面后,自动启动那些程序,是在~/.config/autostart/ ...
- 微信小程序的启动流程
小程序运行的三种环境 1.ios端,Mac微信端 2.Android端.PC微信端 3.微信开发者模拟器端 第一步环境准备 1.小程序运行进程以及运行环境的准备 2.代码包下载.校验以及初始化 3.视 ...
- Linux设置程序开机启动-tomcat开机启动
假设我有一个tomcat应用需要开机启动. 前提你的JAVA环境变量已经配置好没有问题,检测方法如图 然后找到tomcat的目录,我的目录是 /home/yuqing_4.0/tomcat_share ...
- golang程序启动流程详解
golang程序启动流程详解 环境 go1.16.5 linux/amd64 用例 package mainimport "fmt"func main() {fmt.Println ...
- (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 原文:(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 版权声明:本作品采用知识共享署名-非商 ...
最新文章
- poj 3411(DFS多点访问)
- c 语言输出指针的值,C 语言指针
- python调用oracle过程 权限不足_Python连接Oracle的一些坑以及出现原因和解决方法...
- android 服务是什么问题,Android Studio 中的Service问题
- iOS内存管理系列之一:对象所有权与引用计数
- RabbitMQ的简单示例
- Linux 下 Shell 命令的分类及用法
- 对象存储 OSS > 产品简介 > 什么是对象存储OSS
- 从零开始刷Leetcode——数组(581.605.628)
- linux deepin 15.9双系统,windows10安装双系统Deepin15.9遇到的坑
- procedure mysql_所有子节点、Procedure、MySQL
- 如何让sublime编译c语言,如何在Sublime Text 3中编译C程序?
- 机器学习基石 作业0
- docker-compose 部署shipyard
- QT HTTP接收多个数据包生成图片
- 赵俊峰内蒙古大学计算机学院,内蒙古大学计算机学院研究生导师:赵俊峰
- 程序员代码中的希腊字母表示
- PJzhang:搜索引擎高级语法与渗透测试
- urlrewrite使用介绍
- MES系统的实施准备,将MES系统导入到企业的运作体系之中
热门文章
- OTA升级包的解释和升级方法
- 10 个解放双手超实用在线工具,有些代码真的不用手写
- 通达OA 工作流流转过程中使用系统自带的提醒功能设置(图文)
- zz 邮件列表的文化与礼节
- 【前端基础 四】HTML DOM
- 生成器 推导式 练习
- 内网渗透(八十一)之搭建Exchange服务器
- QT5.50+opencv3.0+VS2013安装教程
- 架构设计——接口设计
- 学python人工智能电脑要什么配置_本人是大一人工智能专业,不打游戏,我们需要学习C++和Python。用什么配置的笔记本电脑比较好?...