计算机工作原理(二)目标文件

一、简介

编译器编译源代码后生成的文件叫目标文件(Linux下.o或Windows下.obj),从结构上讲,它是已经编译后的可执行文件格式,只是还没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。其实它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。

二、目标文件是什么样的

目标文件中的内容至少有编译后的机器指令代码、数据,除了这些数据以外,还包括了链接时所需要的一些信息,比如符号表、调试信息、字符串等。

一般目标文件将这些信息按不同的属性,以“节”的形式存储,有时候也叫“段”,在一般情况下,他们都表示一个一定长度的区域。

程序源代码被编译后的机器指令经常被放在代码段(Code Section)里,代码段常见的名字有.code.text

全局变量和局部静态变量数据经常放在数据段(Data Section),数据段的名字一般都叫.data

File Header
.text section
.data section
.bss section

对照上面的表格来看,一般C语言的编译后执行语句都编译成机器代码,保存在.text段。

已初始化的全局变量和局部静态变量都保存在.data段。

未初始化的全局变量和局部静态变量都保存在.bss段。

我们知道未初始化的全局变量和局部静态变量默认值都为0,本来他们也可以被在.data段的,但是因为它们都是0,示意图为它们在.data段分配空间并且存放数据0是没有必要的。程序运行的时候它们的确是要占内存空间的,并且可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小综合,记为.bss段,所以.bss段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容,所以它在文件中也不占据空间。

总体来说,程序源代码被编译以后主要分成两种段:程序指令和程序数据,代码段属于程序指令,而数据段和.bss段属于程序数据。

为什么要将数据和指令的存放分开?

1.当程序被装载后,数据和指令分别被映射到两个虚存区域,由于数据区对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读,这样可以防止程序的指令被有意或无意的改写。

2.另外一方面对于现代CPU来说,他们有着极为强大的缓存(Cache)体系,由于缓存在现代的计算机中地位非常重要,所以程序必须尽量提高缓存的命中率。指令区和数据区的分离有利于提高程序的局部性。

3.第3个原因是最重要的原因,就是当系统中运行着多个该程序的副本时,它们的指令都是一样的,所以内存中只须要保存一份改程序的指令部分,对于指令这种只读的区域是这样,对于其他的只读数据也一样,比如很多程序里面带有的图标、图片、文本等资源也是属于可以共享的,这样就可以节省大量内存。

3、深入目标文件的具体细节

下面列举一个简单的C语言demo(SimpleSection.c)作为分析对象:


int printf(const char *format);
int global_init_var = 84;
int global_uninit_var;

void func1(int i){
    printf("%d\n", i);
}

int main(void){
    static int static_var = 85;
    static int static_var2;
    int a = 1;
    int b;
    
    func1(static_var + static_var2 + a + b);
    
    return a;
}

使用GCC来编译这个文件:

$ gcc -c SimpleSection.c

使用binutilsodjdump工具查看object内部的结构:

$ objdump -h SimpleSection.o

会得到如下几个段的信息:

0 .text
1 .data
2 .bss
3 .rodata
4 .comment
5 .note.GNU-stack

逐个来看着几个段,看看他们包含了什么内容。

(1)代码段

包含的是func1()main()的指令。

(2)数据段和只读数据段

.data段保存的是那些已经初始化了的全局静态变量和局部静态变量,分别是global_init_varstatic_var

.rodata存放的是只读数据,不光在语义上支持C++const关键字,而且操作系统在加载的时候可以将.rodata段的属性映射成只读,这样对于这个段的任何修改操作都会作为非法操作处理。保证了程序的安全性。

(3)BSS段

.bss段存放的是未初始化的全局变量和局部静态变量,上述代码中只有static_var2被存放在了.bss段,而global_uninit_var却没有被存放在任何段,只是一个未定义的COMMON符号。这其实跟不同的语言与不同的编译器实现有关,有些编译器会将全局的未初始化变量存放在目标文件的.bss段,有些则不存放,只是预留一个未定义的全局变量符号,等到最终链接成可执行文件的时候再在.bss段分配空间。

(4)其他段

常用的段名 说明
.rodata1 存放只读数据,比如字符串常量、全局const变量
.comment 存放的是编译器版本信息
.debug 调试信息
.dynamic 动态链接信息
.hash 符号哈希表
.line 调试时的行号表
.note 额外的编译器信息
.strtab 字符串表,用于存储ELF文件中用到的各种字符串
自定义段

正常情况下,GCC编译出来的目标文件中,代码会被放到.text段中,全局变量和静态变量会被放到.data.bss段,有时候我们希望变量或某些代码能够放到你所指定的段中去,GCC提供了一个扩展机制,使得程序员可以指定变量所处的段:

__attribute__((section("Foo"))) int glbal = 42;
__attribute__((section("BAR"))) void foo()
{
    ...
}

链接的接口—符号

链接过程的本质就是要把多个不同的目标文件之间相互“粘”在一起,在链接中,我们将函数和变量统称为符号,函数名或变量名就是符号名,我们可以将符号看做是链接中的粘合剂,整个链接过程正是基于符号才能正确完成,链接过程中很关键的一部分就是符号的管理,每一个目标文件都会有一个相应的符号表,这个表里面记录了目标文件中所用到的所有符号,每个定义的符号有一个对应的值,叫做符号值,对于变量和函数来说,符号值就是他们的地址。

函数签名

函数签名包含了一个函数的信息,包括函数名,它的参数类型,它所在的类和名称空间及其他信息。函数签名用于识别不同的函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容