程序运行之ELF文件的段

更多精彩内容在公众号。

我们将之前的代码增加下变量来具体看下

在代码中增加了全局变量以及静态变量,还有一个简单的函数。

#include <stdio.h>

int global_var=1;

int global_init_var;

void func1(int i){

printf("%d\n",i);

}

int main(void){

static int static_var=8;

static int static_var2;

int a=1;

int b;

func1(static_var+a);

return 0;

}

使用gcc -c来编译这个文件:gcc -c main.c。 -c表示只编译不链接

然后通过objdump -h来查看生成的.o文件。从下面结果看到除了代码段,数据段和BSS段以外,还有.rodata(只读数据段), .comment(注释信息段),.note.GNU-stack(堆栈提示段)。 在File off中标识了每个段的偏移位置。比如.text段的偏移位置是0x40. 代表ELF的header占据的空间为0x00-0x40。.text的起始位置为0x40

main.o:     文件格式 elf64-x86-64

节:

Idx Name          Size      VMA               LMA               File off  Algn

  0 .text         0000004c  0000000000000000  0000000000000000  00000040  2**0

                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE

  1 .data         00000004  0000000000000000  0000000000000000  0000008c  2**2

                  CONTENTS, ALLOC, LOAD, DATA

  2 .bss          00000008  0000000000000000  0000000000000000  00000090  2**2

                  ALLOC

  3 .rodata       00000004  0000000000000000  0000000000000000  00000090  2**0

                  CONTENTS, ALLOC, LOAD, READONLY, DATA

  4 .comment      00000024  0000000000000000  0000000000000000  00000094  2**0

                  CONTENTS, READONLY

  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000b8  2**0

                  CONTENTS, READONLY

  6 .eh_frame     00000058  0000000000000000  0000000000000000  000000b8  2**3

                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

另外有一个专门的命令size可以查看ELF文件的代码段,数据段和BSS段的长度。hex代表的是三个段的总长度。

root@zhf-maple:/home/zhf/c_prj# size main.o

   text    data     bss     dec     hex filename

168       8       8     180      b4 main.o

在.data段中保存是已经初始化了的全局静态变量和局部静态变量。上面的代码中global_var和static_var就是这样的数据,两个变量都是int类型,各占4个字节。一共刚好8个字节。所以.data这个段的大小为8个字节。

要想查看各个数据段中的具体内容可以通过objdump -s main.o的方式来查看

可以看到.data段中的数据为 01000000 和 08000000 各自占据4个字节,分别对应int global_var=1以及static int static_var=8;

那么为什么不是0x00000001和0x00000008呢,原因在于字节存放的顺序是大端序还是小端序的

大端序:数据的高位字节存放在地址的低端 低位字节存放在地址高端

小端序:数据的高位字节存放在地址的高端 低位字节存放在地址低端

具体的实现参考下面的这个帖子

https://www.cnblogs.com/flysnail/archive/2011/10/25/2223721.html

从上面的数据可以看出这个是小端序的

main.o:     文件格式 elf64-x86-64

Contents of section .text:

 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...

 0010 488d3d00 000000b8 00000000 e8000000  H.=.............

 0020 0090c9c3 554889e5 4883ec10 c745fc01  ....UH..H....E..

 0030 000000be 04000000 488d3d00 000000b8  ........H.=.....

 0040 00000000 e8000000 008b1500 0000008b  ................

 0050 45fc01d0 89c7e800 000000b8 00000000  E...............

 0060 c9c3                                 ..              

Contents of section .data:

 0000 01000000 08000000                    ........        

Contents of section .rodata:

  0000 25640a00                             %d..        

Contents of section .comment:

 0000 00474343 3a202855 62756e74 7520372e  .GCC: (Ubuntu 7.

 0010 322e302d 38756275 6e747533 2920372e  2.0-8ubuntu3) 7.

 0020 322e3000                             2.0.            

Contents of section .eh_frame:

 0000 14000000 00000000 017a5200 01781001  .........zR..x..

 0010 1b0c0708 90010000 1c000000 1c000000  ................

 0020 00000000 24000000 00410e10 8602430d  ....$....A....C.

 0030 065f0c07 08000000 1c000000 3c000000  ._..........<...

 0040 00000000 3e000000 00410e10 8602430d  ....>....A....C.

 0050 06790c07 08000000                    .y...... 

另外我们看到在.rodata中也有数据。.rodata中是存储只读数据的。比如const修改的变量。在这里看到.rodata中的数据为%d。 这个是因为我们调用了printf的时候用到了字符串常量%d. 它是一种只读数据。所以被放到了.rodata中。

0000 25640a00                             %d.. 

.bss段存放的是未初始化的全局变量以及局部静态变量。也就是global_init_var和static_var2变量,但是.bss段只有4个字节大小,2个int的变量应该是8个字节才对。我们通过objdump -x main.o来查看符号表。可以看到.bss段中只有static_var2变量,global_init_var并没有在里面。这和编译器有关,global_init_var是一个未定义的COMMON符号,有些编译器会将其放入.bss段中

SYMBOL TABLE:

0000000000000000 l    df *ABS* 0000000000000000 main.c

0000000000000000 l    d  .text 0000000000000000 .text

0000000000000000 l    d  .data 0000000000000000 .data

0000000000000000 l    d  .bss 0000000000000000 .bss

0000000000000000 l    d  .rodata 0000000000000000 .rodata

0000000000000004 l     O .data 0000000000000004 static_var.2256

0000000000000000 l     O .bss 0000000000000004 static_var2.2257

0000000000000000 l    d  .note.GNU-stack 0000000000000000 .note.GNU-stack

0000000000000000 l    d  .eh_frame 0000000000000000 .eh_frame

0000000000000000 l    d  .comment 0000000000000000 .comment

0000000000000000 g     O .data 0000000000000004 global_var

0000000000000004       O *COM* 0000000000000004 global_init_var

0000000000000000 g     F .text 0000000000000024 func1

0000000000000000         *UND* 0000000000000000 _GLOBAL_OFFSET_TABLE_

0000000000000000         *UND* 0000000000000000 printf

0000000000000024 g     F .text 0000000000000028 main

除了之前介绍的这些段,ELF文件还有如下的段

.strtab : String Table 字符串表,用于存储 ELF 文件中用到的各种字符串。

.symtab : Symbol Table 符号表,从这里可以所以文件中的各个符号。

.shstrtab : 是各个段的名称表,实际上是由各个段的名字组成的一个字符串数组。

.hash : 符号哈希表。

.line : 调试时的行号表,即源代码行号与编译后指令的对应表。

.dynamic : 动态链接信息。

.debug : 调试信息。

.comment : 存放编译器版本信息,比如 "GCC:(GNU)4.2.0"。

.plt 和 .got : 动态链接的跳转表和全局入口表。

.init 和 .fini : 程序初始化和终结代码段

另外GCC还提供了自定义段,比如你可能希望变量或者某些部分代码能够放到你指定的段中去实现特定的功能,比如满足硬件内存和I/O的地址布局。

我们在全局变量和函数之前加上”__attribute__((section(“name”)))”属性就可以把相应的变量或者函数放到以”name”为段名的段中去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/570998.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

合辑下载 | MatrixOne 与 MySQL 全面对比

前言 MatrixOne是一款高度兼容MySQL语法的HTAP数据库&#xff0c;采用云原生化和存储、计算、事务分离的架构打造了HSTAP超融合数据引擎&#xff0c;实现单一数据库系统同时支持OLTP、OLAP、流计算等多种业务负载。基于MatrixOne高度兼容MySQL的定位&#xff0c;社区的小伙伴在…

【Linux】生产者消费者模型{基于BlockingQueue的PC模型/RAII风格的加锁方式/串行,并行,并发}

文章目录 1.认识PC模型2.基于BlockingQueue的PC模型2.1串行&#xff0c;并行&#xff0c;并发2.2理解linux下的并发2.2RAII风格的加锁方式2.3阻塞队列2.4深入理解pthread_cond_wait2.5整体代码1.Task.hpp2.lockGuard.hpp3.BlockQueue.hpp4.pcModel.cc 3.总结PC模型 1.认识PC模型…

机器学习笔记(2)—单变量线性回归

单变量线性回归 单变量线性回归(Linear Regression with One Variable)1.1 模型表示1.2 代价函数1.3 代价函数的直观理解1.4 梯度下降1.5 梯度下降的直观理解1.6 梯度下降的线性回归 单变量线性回归(Linear Regression with One Variable) ps:...今天很倒霉 一名小女孩悄悄地碎…

以Pycharm为例的生成requirements.txt

一、什么是requirements.txt 通常用于Python项目&#xff0c;其中列出了项目依赖的软件包及其版本号。通过在requirements.txt中列出这些依赖项&#xff0c;可以确保其他用户或开发人员能够轻松地安装项目所需的所有软件包及其特定版本&#xff0c;以便项目能够正常运行。一般…

【Java核心能力】RocketMQ 针对消息有序和消息积压的处理

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

linux 网卡配置 vlan/bond/bridge/macvlan/ipvlan 模式

linux 网卡模式 linux网卡支持非vlan模式、vlan模式、bond模式、bridge模式&#xff0c;macvlan模式、ipvlan模式等&#xff0c;下面介绍交换机端及服务器端配置示例。 前置要求&#xff1a; 准备一台物理交换机&#xff0c;以 H3C S5130 三层交换机为例准备一台物理服务器&…

5个免费的3D钣金CAD软件

如果你正在设计简单的折叠钣金零件&#xff0c;则只需设计一些具有圆角半径的法兰&#xff1a;一个简单的钣金模块。 首先&#xff0c;你可以采用老式方式绘图并以 2D 方式完成所有操作。 许多传统制造商仍在使用 2D DWG 和 DXF 图纸。 因此&#xff0c;你很有可能只需快速起草…

工具推荐-eNSP(Enterprise Network Simulation Platform)

一.简介 1.1 一款由华为提供的免费的、可扩展的、图形化操作的网络仿真工具平台。 1.2 主要对企业网络路由器、交换机进行软件仿真&#xff0c;完美呈现真实设备实景&#xff0c;支持大型网络模拟。 1.3 让广大用户有机会在没有真实设备的情况下能够模拟,进行模拟网络架构和建…

HTTP 请求走私实现以及攻击案例

HTTP 请求走私实现以及攻击案例。 HTTP请求走私(HTTP Request Smuggling)是一种Web安全漏洞,它涉及到HTTP协议的不安全实现,特别是在处理多个HTTP请求时。这种漏洞可以被利用在多种场景中,导致不同的安全问题。以下是一些主要的漏洞和应用场景: 1. 缓存投毒(Cache Pois…

鸿蒙操作系统-初识

HarmonyOS-初识 简述安装配置hello world1.创建项目2.目录解释3.构建页面4.真机运行 应用程序包共享包HARHSP 快速修复包 官方文档请参考&#xff1a;HarmonyOS 简述 1.定义&#xff1a;HarmonyOS是分布式操作系统&#xff0c;它旨在为不同类型的智能设备提供统一的操作系统&a…

Python 全栈体系【四阶】(二十)

第五章 深度学习 二、推荐系统 1. 推荐算法介绍 1.1 个性化推荐算法 人口属性 地理属性 资产属性 兴趣属性 1.2 推荐算法分支 协同过滤推荐算法基于内容的推荐算法混合推荐算法流行度推荐算法 1.3 推荐算法 为推荐系统选择正确的推荐算法是非常重要的决定。目前为止…

【Python】搭建 Python 环境

目 录 一.安装 Python二.安装 PyCharm 要想能够进行 Python 开发&#xff0c;就需要搭建好 Python 的环境 需要安装的环境主要是两个部分&#xff1a; 运行环境: Python开发环境: PyCharm 一.安装 Python (1) 找到官方网站 (2) 找到下载页面 选择 “Download for Windows”…