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

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

#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”为段名的段中去。

程序运行之ELF文件的段的更多相关文章

  1. 程序运行之ELF文件结构

    ELF目标文件格式的最前部是ELF文件头.包含了整个文件的基本属性.比如ELF文件版本,目标机器型号,程序入口地址等.然后是ELF的各个段,其中ELF文件中与段有关的重要结构就是段表.段表描述了ELF ...

  2. 程序运行之ELF 符号表

    当一个工程中有多个文件的时候,链接的本质就是要把多个不同的目标文件相互粘到一起.就想玩具积木一样整合成一个整体.为了使不同的目标文件之间能够相互粘合,这些目标文件之间必须要有固定的规则才行.比如目标文 ...

  3. windows系统中如何找到某程序运行的本地文件

    主要通过window自带的服务功能来查询: 比如:

  4. 实例分析ELF文件动态链接

    参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台 ...

  5. bin文件和elf文件

    ELF文件格式是一个开放标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件(Relocatable,或者Object File) 可执行文件(Executab ...

  6. ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)

    加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: ...

  7. GCC编译器原理(二)------编译原理一:ELF文件(1)

    二.ELF 文件介绍 2.1 可执行文件格式综述 相对于其它文件类型,可执行文件可能是一个操作系统中最重要的文件类型,因为它们是完成操作的真正执行者.可执行文件的大小.运行速度.资源占用情况以及可扩展 ...

  8. elf 文件格式探秘——程序运行背后的故事

    摘要:本文主要讲解elf文件格式,通过readelf命令结合底层的相关数据结构,讲解相关内容,分析程序运行的基本原理. 本文来源:elf 文件格式探秘——程序运行背后的故事 http://blog.c ...

  9. C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)

      BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段 : ...

随机推荐

  1. [PWA] Access the Camera in a PWA built with React

    It's possible to access some, but not all, of the native device features from a PWA. One that we can ...

  2. WEB接口测试之Jmeter接口测试自动化 (二)(数据分离)

    转载:    http://www.cnblogs.com/chengtch/p/6105231.html 通过逐个录入的方式,好不容易将需要测试几十个接口的300多个测试用例录入sampler-ht ...

  3. Ubuntu升级出现/boot空间不足解决(转)

    经常升级Linux内核,导致更新时警告/boot分区空间不足.这是以为多次升级内核后,导致内核版本太多,清理一下没用的内核文件就行了.命令如下: zht@zht-Ubuntu:~$ dpkg -l ' ...

  4. DPM(Deformable Part Model)原理详解(汇总)

    写在前面: DPM(Deformable Part Model),正如其名称所述,可变形的组件模型,是一种基于组件的检测算法,其所见即其意.该模型由大神Felzenszwalb在2008年提出,并发表 ...

  5. js中的四舍五入函数

    刚学到这部分时,感觉特别简单.可最近写个ajax分页时,忽然忘记应该怎么使用哪种函数来计算总的页数...哎,好记星不如烂笔头啊,还是老老实实的写下来吧.随时查看. 1.Math.ceil(x):对x向 ...

  6. .net core 2.0小白笔记(一):开发运行环境搭建

    小白一枚,有任何不妥之处敬请指教 这里不讨论什么设计模式,什么架构,什么什么,就是入门,简单的入门,虽然能跨平台,但是这里还是在win的环境下进行,不扯的那么远 其实官网文档写的挺不错的了,就是偶尔有 ...

  7. MQTT--入门 续

    1.消息模型:  MQTT是一种基于代理的发布/订阅的消息协议.提供一对多的消息分发,解除应用程序耦合.一个发布者可以对应多个订阅者,当发布者发生变化的时候,他可以将消息一一通知给所有的订阅者.这种模 ...

  8. JavaSE入门学习21:Java面向对象之接口(interface)(二)

    一接口实现的多态 在上一篇博文:JavaSE入门学习20:Java面向对象之接口(interface)(一)中提到了接口的实现存在多态性,那么 这一篇主要就要分析接口实现的多态. 实例一 Test.j ...

  9. poj 2762 Going from u to v or from v to u?(强连通、缩点、拓扑)

    题意:(理解错了)在一个洞穴中有多个room,要求任意选两个room:u.v,都能保证u.v之间有通路,注意洞穴中的路是有向边.. 分析:强连通子图中的点必然两两之间可以互通,两个强连通子图之间有通路 ...

  10. 全站301跳转 PHP

    $the_host = $_SERVER['HTTP_HOST'];//取得当前域名 $request_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER[ ...