什么是进程?
这篇文章主要还是引入一些思想的一些导论,主要讲的是进程是什么样的,我该怎么加载一个进程,为了跟进时代的变化这里还用了 chatgpt
来做了一些名词的解释之类的(相当好用!)
什么是进程
很多人可能一上来就是概念,阿吧阿巴,进程是: 进程 (英语:process),是指电脑中已执行的 程式 ,曾经是 分时系统 的基本运作单位。在面向进程设计的系统(如早期的 UNIX , Linux 2.4 及更早的版本)中,是程式的基本执行实体;在面向线程设计的系统(如当代多数操作系统、 Linux 2.6 及更新的版本)中,行程本身不是基本执行单位,而是 执行绪 的容器。(来源于 wiki)
tl;dr 在冯诺依曼架构下面 进程就是一块内存其中填充了一堆当前 CPU 认识的指令
并且操作系统给他做了特殊标识 并把对应的资源附着在这上面
但是,有没有什么能让我们感觉到真实的进程是什么样的呢?
有,甚至很确切
#include <stdio.h>
int main () {
printf("hello world\n");
return 0;
}
这是一个简单的 hello world 代码,我们把它编译成 可执行文件 a.out
后 gdb
调试他,在源代码里面随便打一个断点,之后使用 pmap
命令来获取进程号,具体过程如下面图所示
在 Linux 操作系统中,pmap 命令用于查看指定进程或进程中指定线程的内存映射情况。pmap 命令会输出指定进程或线程使用的内存地址、使用的内存大小、内存权限等相关信息。pmap 命令是一个非常有用的诊断工具,可以帮助用户检测内存泄漏、内存碎片等问题。通常情况下,pmap 命令需要 root 权限才能运行。以下是 pmap 命令的常见用法:
pmap PID # 查看指定进程的内存映射情况 pmap -x PID # 查看指定进程的详细内存映射情况 pmap -d PID # 显示指定进程或线程的内存映射中的数据段 pmap -s PID # 显示指定进程或线程的内存映射中的栈段
来源于
chatgpt
,有兴趣的可以自己man 1 pmap
查看
在这里同样你也可以通过
!cat /proc/83220/maps
来查看,pmap
其实对前者封装了一下而已,让他更human friendly
上面的内存信息就是我们的进程真实的样子啦,很多人可能会很懵,你这进程长这逼样谁看得懂啊,别急,慢慢来。
这里简单介绍一下
linux
的内存都是 4k 为一个块,所以这里内存都是 4k 对齐的a.out
就是我们的可执行文件libc.so.6
和ld-linux-x86-64.so.2
就是我们进程动态链接过来的内存页,比如hello world
用到的printf
就是从libc.so.6
动态链接过来的- anno 其实就是匿名页,比如说
mmap
映射的在这里就是匿名页 - stack 就不用多说了
- 其实细心同学用别的代码尝试的话还可能发现有
vdso
和vvar
等,由于篇幅原因可以自行man
手册和chatgpt
具体细节可以去看 jyy 老师的课: 进程的地址空间
elf 文件
那操作系统是怎么知道我们要创建这样的进程的呢?
没错, elf 文件 ,也就是我们的 xxx.o
文件(当然我们的 a.out
其实也是,毕竟是从 xxx.o
链接过来的),我们可以通过 file xxx.o
来查看文件类型
ELF(Executable and Linkable Format)文件是一种常见的二进制文件格式,在 Linux 及其他类 UNIX 系统中被广泛使用。ELF 文件可以包含可执行程序、共享库、目标文件等类型的程序代码。ELF 格式的设计目标是提供一种通用、可移植、灵活的二进制格式,能够适应各种 CPU 架构和操作系统。
ELF 文件具有丰富的头部、节区、符号表和重定位等元信息,这些元信息描述了程序的各种属性和结构,如 代码段、数据段、链接信息、调试信息 等等。这些元信息使得在运行时对程序进行加载、链接和执行变得简单和高效。ELF 文件中包含的重定位信息,也可以帮助程序进行动态链接和库加载并在运行时进行代码共享。
ELF 文件的结构十分清晰、灵活,使得他们能够满足不同类型的程序的需要。它被广泛应用于 Linux 系统的各种应用场景,无论是编译器、链接器、动态链接器、调试器,还是其他形式的二进制文件,都使用了 ELF 文件格式。(来源于 chatgpt)
其实 elf 文件
就是我们学到的一种数据结构而已,包括他的程序头,各种 section
,都在 elf.h
中定义,在你的 /usr/include/elf.h
就可以看到,这里随便列举点片段,这边建议搞懂 elf 具体长什么样再看后面的例子,可以看看 csapp
的第七章
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr; //64 位 elf 文件头
typedef struct
{
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;//64 位 section 头
typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;//64 位程序头
具体 elf 长啥样?
我们可以通过 readelf
命令来读取 elf 文件
readelf 是一个用于查看 ELF 文件的命令行工具。它支持读取并显示 ELF 文件的所有表头信息、段头信息、符号表信息、重定位信息、动态节信息、动态符号表信息等。
常用的 readelf 命令选项包括:
- -a/--all:显示 ELF 文件的所有内容;
- -h/--file-header:显示 ELF 文件的文件头信息;
- -S/--section-header:显示 ELF 文件的节表信息;
- -s/--symbols:显示 ELF 文件的符号表信息;
- -r/--relocs:显示 ELF 文件的重定位表信息;
- -d/--dynamic:显示 ELF 文件的动态节信息;
- -V/--version-info:显示 ELF 文件使用的动态库版本信息。
示例:
读取 ELF 文件的文件头信息:
readelf -h test.out
读取 ELF 文件的节表信息:
readelf -S test.out
读取 ELF 文件的程序头信息:
readelf -l test.out
(来源于 chatgpt)感兴趣可以自行man 1 readelf
以下是一些 helloworld
的例子
elf 文件头
elf 文件的各种 section
可执行文件的程序头
注意这里是 a.out
这种已经链接过的可执行文件才有的程序头,用于告诉操作系统该怎么加载这个进程,那些东西得放哪里......
来点实际的
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Mybatis 配置杂谈
下一篇: 通过注册表为文件(夹)添加右键菜单
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论