程序运行之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”为段名的段中去。
程序运行之ELF文件的段的更多相关文章
- 程序运行之ELF文件结构
ELF目标文件格式的最前部是ELF文件头.包含了整个文件的基本属性.比如ELF文件版本,目标机器型号,程序入口地址等.然后是ELF的各个段,其中ELF文件中与段有关的重要结构就是段表.段表描述了ELF ...
- 程序运行之ELF 符号表
当一个工程中有多个文件的时候,链接的本质就是要把多个不同的目标文件相互粘到一起.就想玩具积木一样整合成一个整体.为了使不同的目标文件之间能够相互粘合,这些目标文件之间必须要有固定的规则才行.比如目标文 ...
- windows系统中如何找到某程序运行的本地文件
主要通过window自带的服务功能来查询: 比如:
- 实例分析ELF文件动态链接
参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台 ...
- bin文件和elf文件
ELF文件格式是一个开放标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件(Relocatable,或者Object File) 可执行文件(Executab ...
- ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)
加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: ...
- GCC编译器原理(二)------编译原理一:ELF文件(1)
二.ELF 文件介绍 2.1 可执行文件格式综述 相对于其它文件类型,可执行文件可能是一个操作系统中最重要的文件类型,因为它们是完成操作的真正执行者.可执行文件的大小.运行速度.资源占用情况以及可扩展 ...
- elf 文件格式探秘——程序运行背后的故事
摘要:本文主要讲解elf文件格式,通过readelf命令结合底层的相关数据结构,讲解相关内容,分析程序运行的基本原理. 本文来源:elf 文件格式探秘——程序运行背后的故事 http://blog.c ...
- C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段 : ...
随机推荐
- [Angular] ngClass conditional
Using ngClass for conditional styling, here is the usage from the docs: /** * @ngModule CommonModule ...
- ReadWriteLock 读写锁(读书笔记)
读写分离锁可以有效的帮助减少锁的竞争,提升系统的效率, 读-读不互斥 读读之间不阻塞 读-写互斥 读阻塞写,写也会阻塞读 写-写互斥 写写阻塞 在系统中,读操作次数远远大于写操作,则读写锁就可以发挥 ...
- Python学习笔记(二)网络编程的简单示例
Python中的网络编程比C语言中要简洁很多,毕竟封装了大量的细节. 所以这里不再介绍网络编程的基本知识.而且我认为,从Python学习网络编程不是一个明智的选择. 简单的TCP连接 服务器代码如 ...
- linux配置jdk失败
在linux下配置jdk时,/etc/profile下的配置内容是对的,可是输入java -version却发现配置没有成功,这一般都是jdk的安装文件夹权限没有提升的原因,仅仅需用chmod -R ...
- C#操作消息列队
首先安装消息队列MSMQ,在“计算机管理-服务和应用程序-消息队列-专用队列”中新建列队名称Demo: static void SendAndReceiveMsg() { MessageQueue m ...
- linux路由服务
本文介绍怎样使用linux创建一台简单的路由server. 主要包含几个參数的设置:ip_forward和rp_filter. 1.开启IP forwarding # 重新启动后失效 $ echo & ...
- MATLAB 2014a 在Mac os x yosemite 10.10 Retina显示模糊的解决的方法
恐怕非常多童鞋在升级了yosemite之后都遇到了Matlab的问题. 之前转载的一篇文章写了安装的方法,本文说一下解决Retina屏显示模糊的办法. 那么因为Matlab 2014a使用自带的jav ...
- Android——点击对话框上button不关闭对话框
有时候我没可能须要在点击button进行一些检測.可是并不想关闭次对话框(系统默认点击不论什么一个button则关闭对话框),处理方法例如以下:在点击事件下加入例如以下代码: try { Field ...
- shell统计一个文件里某行出现的次数并排序
话说有个aaa.txt文件,文件内容如下: aaaabbbbccccddddeeeeffffmmmmooooaaaaccccaaaabbbbddddaaaammmmbbbbaaaaoooo 然后面试题 ...
- Mac下安装LNMP(Nginx+PHP5.6)环境(转)
安装Homebrew 最近工作环境切换到Mac,所以以OS X Yosemite(10.10.1)为例,记录一下从零开始安装Mac下LNMP环境的过程 确保系统已经安装xcode,然后使用一行命令安装 ...