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

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

#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. Windows局域网如何进行远程桌面连接

    我们以虚拟机为例: 1 确保被控制的计算机允许远程连接   2 确保被控制的计算机有密码(一般人方便,只有一个administrator账号,而且不设密码,开机直接进入的,如果没有密码,将无法进行远程 ...

  2. 使用file_get_contents下载图片

        <?php /* 当你在搭建网站时,从远程服务器下载某张图片并且将其保存在自己的服务器上,这一操作会经常用到.代码如下: */ $image = file_get_contents('h ...

  3. c语言用rand() 函数,实现random(int m)

    函数rand()是真正的随机数生成器.而srand()会设置供rand()使用的随机数种子. 假设你在第一次调用rand()之前没有调用srand(),那么系统会为你自己主动调用srand(). 注意 ...

  4. 谈谈PHP网站的防SQL注入

    SQL(Structured Query Language)即结构化查询语言.SQL 注入,就是把 SQL 命令插入到 Web 表单的输入域或页面请求参数的查询字符串中,在 Web表单向 Web 服务 ...

  5. MySQL 字符编码总结

    今天操作服务器数据库时遇到了Mysql中文字符乱码的问题,主要原因是因为安装的时候没有设置好字符集. 很是郁闷,因为库里有很多重要数据,所以重装是不可能了,于是决定找找在不重装且不改代码的前提下,能搞 ...

  6. 无法连接到服务器,用户xxx登陆失败"

    无法连接到服务器,用户xxx登陆失败" 该错误产生的原因是由于SQL Server使用了"仅 Windows"的身份验证方式, 因此用户无法使用SQL Server的登录 ...

  7. apktool反编译时各种问题汇总

    问题1:apktool d -d 时出现错误Error occured while disassembling class办法:这不是你的错误,这是apktool本身的错误,目前正式release的1 ...

  8. C++类型转换运算符 static_cast,dynamic_cast,reinterpret_cast,const_cast

    类型转换是一种让程序猿可以临时或永久性改变编译器对对象的解释机制.可改变对象解释方式的运算符称为类型转换运算符. 为何须要进行类型转换 通常为了实现使用不同环境的个人和厂商编写的模块可以相互调用和协作 ...

  9. GDBus

    1. https://en.wikipedia.org/wiki/D-Bus In computing, D-Bus (for "Desktop Bus"[4]), a softw ...

  10. layer 不居中的坑爹问题

    使用了该代码弹出一个图片.但居然不居中 var layer_index = layer.open({ type: 1, title: false, closeBtn: 0, area: '516px' ...