实例说明代码段(.text)、数据段(.data)、bss段、只读数据段(.rodata)、堆栈的划分依据 您所在的位置:网站首页 单片机字段码 实例说明代码段(.text)、数据段(.data)、bss段、只读数据段(.rodata)、堆栈的划分依据

实例说明代码段(.text)、数据段(.data)、bss段、只读数据段(.rodata)、堆栈的划分依据

2024-06-19 09:17| 来源: 网络整理| 查看: 265

目录 程序实例介绍各个段内容、分析段(segment)分布分析代码段(.text)、数据段(.data)、bss段、只读数据段(.rodata)划分依据

程序实例介绍各个段内容、分析段(segment)分布

先举个小例子说明,让大家有个表面的印象。

下面的程序定义了一些不同类型的变量,主要包括初始化的全局变量(globle_var1 )和静态全局变量(globle_static_var1 )、未初始化的全局变量(globle_var2)和静态全局变量(globle_static_var2)、常量(globle_const_var 、const_var )和局部变量(var1 、var2)。并通过函数func进行打印输出求和结果,非常简单的一个程序。

//hello.c #include int globle_var1 = 10; int globle_var2; static int globle_static_var1 = 20; static int globle_static_var2; const int globle_const_var = 30; void func(int i) { printf("%d\n",i); } int main() { static int static_var1 = 70; static int static_var2; const int const_var = 40; int var1 = 30; int var2; var2 = globle_var1+globle_static_var1+globle_const_var+static_var1+const_var+var1; func(var2); return 0; }

在 目标文件中的内容至少包括编译后的机器指令代码、数据,还包括了链接时所需要的的一些信息,比如符号表、调试信息、字符串等。目标文件将这些信息按不同的属性以“ 段 ”(segment)的形式存储。以下就是一些常见的段。

并且还根据一个简单程序说明编译后的目标文件的结构。主要分析表格中常见的段信息,其实还有其他段例如注释信息段( .comment ),但这不是我们关注的重点。 段 下面的图是一个目标文件的结构分析,主要分析代码和数据存放在那些段中,图中没有给出堆栈段信息,因为堆栈需要在程序被装载准备运行才会分配,因此在目标文件这个阶段还没有分配栈段的内存。并且堆栈相信大家非常熟悉,栈就是存放函数局部变量,malloc()内存分配就是从堆分配的。 段信息

分析代码段(.text)、数据段(.data)、bss段、只读数据段(.rodata)划分依据

以前学习的时候我也只背住各个段分别存放什么内容,根本不知道为什么需要进行不同段的划分。下面分析一下划分的依据,以及这样划分有什么好处。

首先,可以先区分代码段和数据段。程序源代码编译后的机器指令就会放在代码段里;然后这里的数据段包括" .data “、” .bss “、” .rodata ",将程序中定义的全局变量和局部变量都称先称为数据段。

为什么把程序的“ 代码段 ”和“ 数据段 ”分开存放?

当程序被装载后,数据和指令分别被映射到两个虚拟内存区域。数据段对进程来讲是可读写的,而代码段对进程来说是只读的,所以这两个虚拟内存区域的权限可以被分别设置为可读写和只读,防止程序的指令被有意和无意地改写。现代CPU的缓存一般被设计成数据缓存和指令缓存分离,程序的指令和数据被分开存放对CPU的缓存命中率提高有好处。当系统中运行着多个该程序的副本时,例如多个线程同时都运行同一个程序,它们的代码段指令都是一样的,所以内存中只需要保存一份该程序的代码段,然后将每个副本进程的数据段区域分来,这样可以节省大量空间。

为什么数据段还需要分" .data “、” .bss “、” .rodata "这么麻烦?有什么区别? 主要根据两个维度进行区分,是否占内存空间、读写权限。

以初始化的全局变量和局部静态变量都保存在" .data “段。未初始化的全局变量和局部静态变量一般都放在” .bss "段,因为未初始化的变量默认值为0,本来它们也可以放在.data段,但是因为它们都是0,所以为它们在.data段分配空间并且存放数据0是没有必要的。

" .data"段和" .bss “段都是可读写的数据段,而” .rodata “存放的是只读数据,主要是一些const变量和字符串常量。单独设立” .radata “段的好处是,在程序加载的时候可以将” .rodata “段的属性映射成只读,这样对这个段的任何修改操作都作为非法操作处理。另外在某些平台还可以将” .rodata "段存放在只读存储器,例如ROM,通过硬件保证只读。

所以如果通过命令objdump查看各个段的大小发现,.data段大小为12字节,正好是变量globle_var1、globle_static_var1、static_var1的大小。但是.bss段的大小为8个字节,并不是变量globle_var2、globle_static_var2、static_var2变量的大小,可以看出.bss并没有为变量分配内存。

zhouyuanlin@zhouyuanlin-virtual-machine:/mnt/hgfs/share$ ls a.out hello.c hello.o zhouyuanlin@zhouyuanlin-virtual-machine:/mnt/hgfs/share$ objdump -x -s -d hello.o hello.o: 文件格式 elf64-x86-64 hello.o 体系结构:i386:x86-64, 标志 0x00000011: HAS_RELOC, HAS_SYMS 起始地址 0x0000000000000000 节: Idx Name Size VMA LMA File off Algn 0 .text 00000073 0000000000000000 0000000000000000 00000040 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 0000000c 0000000000000000 0000000000000000 000000b4 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000008 0000000000000000 0000000000000000 000000c0 2**2 ALLOC 3 .rodata 00000008 0000000000000000 0000000000000000 000000c0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .comment 00000036 0000000000000000 0000000000000000 000000c8 2**0 CONTENTS, READONLY 5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000fe 2**0 CONTENTS, READONLY 6 .eh_frame 00000058 0000000000000000 0000000000000000 00000100 2**3 ......

参考文献 [1] 俞甲子,石凡,潘爱民.程序员的自我修养——链接、装载与库[M].北京:电子工业出版社,2009.4



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有