《操作系统真象还原》——0.21 Section和Segment的区别

简介: C程序大体上分为预处理、编译、汇编和链接4个阶段。预处理阶段是预处理器将高级语言中的宏展开,去掉代码注释,为调试器添加行号等。编译阶段是将预处理后的高级语言进行词法分析、语法分析、语义分析、优化,最后生成汇编代码。汇编阶段是将汇编代码编译成目标文件,也就是转换成了目标机器平台上的机器指令。

本节书摘来自异步社区《操作系统真象还原》一书中的第0章,第0.21节,作者:郑钢著,更多章节内容可以访问云栖社区“异步社区”公众号查看

0.21 Section和Segment的区别

C程序大体上分为预处理、编译、汇编和链接4个阶段。预处理阶段是预处理器将高级语言中的宏展开,去掉代码注释,为调试器添加行号等。编译阶段是将预处理后的高级语言进行词法分析、语法分析、语义分析、优化,最后生成汇编代码。汇编阶段是将汇编代码编译成目标文件,也就是转换成了目标机器平台上的机器指令。链接阶段是将目标文件连接成可执行文件。这里我们只关注汇编和链接这两个阶段。

在汇编源码中,通常用语法关键字section或segment来表示一段区域,它们是编译器提供的伪指令,作用是相同的,都是在程序中“逻辑地”规划一段区域,此区域便是节。注意,此时所说的section或segment都是汇编语法中的关键字,它们在语法中都表示“节”,不是段,只是不同编译器的关键字不同而已,关键字segment在语法中也被认为与section意义相同。首先汇编器根据语法规则,会将汇编源码中表示“节”的语法关键字section或segment在目标文件中编译成“节”,此“节”便是我们要讨论的section。经过汇编生成目标文件之后,由这些section或segment修饰的程序区域便成为了“节”(section)。但操作系统加载程序时并不关心节的数量和大小,操作系统只关心节的属性,因为程序必然是要加载到内存中才能运行的,而内存的访问会涉及到全局描述符表中段描述符的访问权限等属性,保护模式下对任何内存的访问都要经过段描述符才行。比如程序代码所在的段描述符权限属性必须是只读,数据所在的段描述符的权限属性必然是可读写,程序中那些只读的节(比如代码区域)必然不能指向可读写的段描述符,同样,程序中的数据也不能用只读权限的段描述符去访问。如果此时您对段描述符不了解,以后咱们在介绍保护模式下全局描述表时就明白了。操作系统在加载程序时,不需要对逐个节进行加载,只要给出相同权限的节的集合就行了,例如把所有只读可执行的节(如代码节.text和初始化代码节.init)归并到一块,所有可读写的节(如数据节.data和未初始化节.bss)归并到一块,这样操作系统就能为它们分配不同的段选择子,从而指向不同段描述符,实现不同的访问权限了。为了程序能在操作系统上运行,操作系统和编译器需要相互配合,此时汇编器只生成了目标文件,尚未链接,因此这个将“节”合并的工作是由链接器来完成的,链接器将目标文件中属性相同的节合并成一个大的section集合,此集合便称为segment,也就是段,此段便是我们平时所说的可执行程序内存空间中的代码段和数据段。

现在总结一下。

section称为节,是指在汇编源码中经由关键字section或segment修饰、逻辑划分的指令或数据区域,汇编器会将这两个关键字修饰的区域在目标文件中编译成节,也就是说“节”最初诞生于目标文件中。

segment称为段,是链接器根据目标文件中属性相同的多个section合并后的section集合,这个集合称为segment,也就是段,链接器把目标文件链接成可执行文件,因此段最终诞生于可执行文件中。我们平时所说的可执行程序内存空间中的代码段和数据段就是指的segment。

在大多数情况下,这两者都被混为一谈,现在咱们做个实际测试,通过实验结果来展示出这两者的不同。其实用一个测试样例就能得出结果,不过为了消除大家的疑虑,测试得更彻底一点,在这里给大家准备了两个小汇编文件,将它们编译链接后,我们通过readelf命令查看其信息来得出结论。上菜了。

文件1.asm

screenshot

这个汇编文件是在本地中声明了字符串,并调用外部的打印函数print,大家可以参考注释,弄个大概明白就行。

文件2.asm

screenshot

在文件2.asm中声明了函数print。下面将这两个文件分别编译成elf格式,这样方便我们通过readelf来查看其编译结果。开始编译,链接成可执行文件12。

[work@localhost test]$nasm -f elf 1.asm -o 1.o
[work@localhost test]$nasm -f elf 2.asm -o 2.o
[work@localhost test]$ld 1.o 2.o -o 12

没问题,再执行一下。

[work@localhost test]$ ./12
Hello,world!

打印出了Hello,world!,结果正确。让我们用readelf查看下文件12的头信息,如图0-12所示。

screenshot

screenshot

结果好长,为了方便查看,我对关键部分加以注释,如图0-13和图0-14所示。

在上面重点部分我都用文字标出了,要注意section headers的部分,此部分显示可执行文件中所有的section,也包括我们在两个汇编文件中用关键字section定义的部分。从第2个section到第5个section,是1.asm中的自定义数据section: file1data,自定义代码section: file1text和2.asm中的自定义数据section: file2data和自定义代码section: file2text。

再往下看Program Headers部分,此处一共有两个段,第一个段是我们的代码段,通过其Flg值为RE便可推断,只读(Readonly)可执行(Execute),其MemSiz为0x000c3。此段对应Section to Segment mapping部分中的第00个Segment,此segment中包括section: .text file1data file1text file2data file2text。

screenshot

第二个段便是我们的数据段,但此数据段中只包含.bss节(section),它用于存储全局未初始化数据,故其Flg必然可读写,其属性为RW。此段MemSiz大小为0x40,即十进制的64,可见,这和1.asm中定义的bss大小一致,而在2.asm中未定义.bbs section,所以此bss指的就是1.asm中的定义。此段对应Section to Segment mapping部分中的第01 个Segment,而此segment只包括.bss节,独立成一个段了。

到此文件分析完毕,总结一下。

自定义的section名,会在elf的section header 中显示出来。下面是几个标准的section(节)名,不是segment(段)名,segment没有名称。

节名     说明
.data   用于存入数据,可读可写
.text   用于存入代码,只读可执行
.bss    全局未初始化区域

在汇编代码中,若以标准节名定义section,如我们定义的.bss便是标准节名。编译器会按照以上说明中的要求使用section内的数据。

不管定义了多少节名,最终要把属性相同的section,或者编译认为可以放到一块的,合并到一个大的segment中,也就是elf中说的 program header 中的项。由此可见,某个节(section)属于某个段(segment),段是由节组成的。另外多说一句,最终给加载器用的也是program header中显示的段,这才是进程的资源,这部分内容将在加载内核时展开。在第3章中介绍了section在地址分配上的内容,大家有兴趣可以提前了解下。

相关文章
|
4月前
|
安全 Android开发 数据安全/隐私保护
请说明鸿蒙操作系统与其他操作系统(如Android和iOS)的主要区别。
请说明鸿蒙操作系统与其他操作系统(如Android和iOS)的主要区别。
62 1
|
3月前
|
弹性计算 运维 安全
阿里云服务器Windows和Linux操作系统区别对比
阿里云服务器Windows和Linux操作系统区别对比,性能有差异吗?有,同配置下Linux性能要优于Windows,但这与阿里云无关,仅仅是linux和windows之间的区别。另外,阿里云提供的windows和linux操作系统均为正版授权,用户不需要额外支付许可费用,如何选择?看用户自己的应用程序情况。
|
3月前
|
运维 安全 Linux
使用阿里云搭建幻兽帕鲁服务器操作系统类型Windows和Linux有区别吗?
使用阿里云搭建幻兽帕鲁服务器操作系统类型Windows和Linux有区别吗?性能有差异?同配置的游戏服务器,如4核16G或8核32G配置等,选择Windows和Linux操作系统差异不太大,如果非要对比的话,Linux系统相对Windows更少占用计算资源,当然如果对Linux不熟悉的话,可以选择Windows。另外,即便是幻兽帕鲁服务器创建成功后,也是可以免费修改操作系统的
118 1
|
6月前
|
存储 算法 Java
深入理解操作系统中进程与线程的区别及切换机制(下)
本文首先介绍了进程的控制结构,即进程控制块(PCB),它是表示进程的数据结构,包含了进程的相关信息和资源。PCB之间通过链表连接,形成就绪队列和阻塞队列,用于进程调度和资源管理。接着,文章详细探讨了进程的切换过程。进程切换是为了保证公平分配CPU时间片,涉及保存和恢复进程的执行上下文、更新进程状态和调度算法选择等步骤。文中还提到了进程上下文切换的场景,如时间片用完、内存不足、高优先级进程需求等。最后,文章介绍了线程的概念和上下文切换过程。线程是进程中的独立执行流程,可以共享进程的资源。线程的上下文切换开销较小,只需要保存和恢复线程的寄存器和计数器等信息。
深入理解操作系统中进程与线程的区别及切换机制(下)
|
6月前
|
Java 调度
深入理解操作系统中进程与线程的区别及切换机制(上)
进程是正在运行的程序的实例,它可以包含一个或多个线程。我们了解了进程的执行方式,包括早期单核处理器上的顺序执行以及引入多任务概念实现的伪并行。我们还探讨了进程的状态模型。进程可以处于就绪、运行、阻塞和结束等不同的状态。就绪状态表示进程已经准备好运行,但还没有被调度执行。运行状态表示进程正在执行。阻塞状态表示进程被阻塞,需要等待某些事件的发生才能继续执行。结束状态表示进程已经完成执行。
深入理解操作系统中进程与线程的区别及切换机制(上)
|
6月前
|
Linux 开发者 Windows
Windows、Linux 和 Mac:操作系统之间的区别
Windows系统、Linux系统与Mac系统:操作系统的对比与选择 操作系统是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。操作系统是用户和计算机的接口,同时也是计算机硬件和其他软件的接口。以下是Windows 系统、Linux 系统、Mac 系统的对比:
|
7月前
|
资源调度 调度
操作系统中进程的就绪和等待两个状态的区别
操作系统中进程的就绪和等待两个状态的区别
106 0
|
8月前
|
存储 缓存 程序员
操作系统中逻辑地址和物理地址的区别
操作系统中逻辑地址和物理地址的区别
134 1
|
10月前
|
存储 Unix Linux
重学操作系统----13 Linux 内核和 Windows 内核有什么区别
重学操作系统----13 Linux 内核和 Windows 内核有什么区别
155 0
|
12月前
操作系统:分段与分页的区别
操作系统:分段与分页的区别
121 0