3 目标文件里面有什么

第3章 目标文件里有啥

目标文件格式

ELF文件类型 说明 实例
可重定位文件(Relocatable File) 待链接的目标文件,包括静态链接库 .o, .obj
可执行文件 可以直接执行的程序 /bin/bash文件,.exe
共享目标文件 共享库 .so, DLL
核心转储文件 当进程意外终止时,系统可以把该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件 core dump

目标文件内部是怎样的

wecom-temp-224047-7c7edf6a72e305c07e1537f1a8e4837e.jpg

代码编译后生成的机器指令通常被放在代码段

全局变量和局部静态变量等常量数据放在数据段

ELF文件头: 描述了文件属性,是否可执行,静态还是动态,入口地址,段表(描述各个段的数组,记录段的属性)

bss段: 某些未初始化的数据放在这个段里,而不是放在data段,因为没初始化默认是0,还要给他们分配内存没必要,只需要标记一下,为他们预留位置

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

分段的好处

  1. 代码是只读,数据可读可写,分区映射到不同的内存区,避免相互篡改

  2. CPU缓存命中率提高

  3. 存在多个程序副本时,大家可以共用一块指令区,只保证数据区不一样,节省内存

对于代码文件SimpleSection.c

/*
SimpleSection.c
Linux:
gcc -c SimpleSection.c
*/
int printf(const char *fmt, ...);

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 -c SimpleSection.c

-c 表示只编译不链接

得到一个.o文件

继续

$ objdump -h SimpleSection.o

-h 查看段的基本信息

SimpleSection.o:  file format mach-o arm64

Sections:
Idx Name             Size     VMA              Type
 0 __text           00000088 0000000000000000 TEXT
 1 __data           00000008 0000000000000088 DATA
 2 __cstring        00000004 0000000000000090 DATA
 3 __bss            00000004 00000000000000d8 BSS
 4 __compact_unwind 00000040 0000000000000098 DATA
wecom-temp-364378-cebc0e6bcf8fb511ed8230b57adba69f.jpg

图文无关,仅供参考,如果对应上面运行在macOS上的代码,请使用MachOView查看,点击左上角RVA选项,查看地址

image-20230201160037052.png

代码段

objdump -s -d SimpleSection.o

-s 把段内容以16进制打印

-d 将包含指令的段反汇编

SimpleSection.o:  file format mach-o arm64

Contents of section __text:
 0000 ff8300d1 fd7b01a9 fd430091 a0c31fb8  .....{...C......
 0010 a8c35fb8 e10308aa 00000090 00000091  .._.............
 0020 e9030091 210100f9 00000094 fd7b41a9  ....!........{A.
 0030 ff830091 c0035fd6 ff8300d1 fd7b01a9  ......_......{..
 0040 fd430091 bfc31fb8 28008052 e80b00b9  .C......(..R....
 0050 09000090 280140b9 09000090 2a0140b9  ....(.@.....*.@.
 0060 08010a0b ea0b40b9 08010a0b ea0740b9  ......@.......@.
 0070 00010a0b 00000094 e00b40b9 fd7b41a9  ..........@..{A.
 0080 ff830091 c0035fd6                    ......_.
Contents of section __data:
 0088 54000000 55000000                    T...U...
Contents of section __cstring:
 0090 25640a00                             %d..
Contents of section __bss:
<skipping contents of bss section at [00d8, 00dc)>
Contents of section __compact_unwind:
 0098 00000000 00000000 38000000 00000004  ........8.......
 00a8 00000000 00000000 00000000 00000000  ................
 00b8 38000000 00000000 50000000 00000004  8.......P.......
 00c8 00000000 00000000 00000000 00000000  ................

Disassembly of section __TEXT,__text:

0000000000000000 <ltmp0>:
 0: ff 83 00 d1   sub  sp, sp, #32
 4: fd 7b 01 a9   stp  x29, x30, [sp, #16]
 8: fd 43 00 91   add  x29, sp, #16
 c: a0 c3 1f b8   stur  w0, [x29, #-4]
 10: a8 c3 5f b8   ldur  w8, [x29, #-4]
 14: e1 03 08 aa   mov  x1, x8
 18: 00 00 00 90   adrp  x0, #0
 1c: 00 00 00 91   add  x0, x0, #0
 20: e9 03 00 91   mov  x9, sp
 24: 21 01 00 f9   str  x1, [x9]
 28: 00 00 00 94   bl  0x28 <ltmp0+0x28>
 2c: fd 7b 41 a9   ldp  x29, x30, [sp, #16]
 30: ff 83 00 91   add  sp, sp, #32
 34: c0 03 5f d6   ret

0000000000000038 <_main>:
 38: ff 83 00 d1   sub  sp, sp, #32
 3c: fd 7b 01 a9   stp  x29, x30, [sp, #16]
 40: fd 43 00 91   add  x29, sp, #16
 44: bf c3 1f b8   stur  wzr, [x29, #-4]
 48: 28 00 80 52   mov  w8, #1
 4c: e8 0b 00 b9   str  w8, [sp, #8]
 50: 09 00 00 90   adrp  x9, #0
 54: 28 01 40 b9   ldr  w8, [x9]
 58: 09 00 00 90   adrp  x9, #0
 5c: 2a 01 40 b9   ldr  w10, [x9]
 60: 08 01 0a 0b   add  w8, w8, w10
 64: ea 0b 40 b9   ldr  w10, [sp, #8]
 68: 08 01 0a 0b   add  w8, w8, w10
 6c: ea 07 40 b9   ldr  w10, [sp, #4]
 70: 00 01 0a 0b   add  w0, w8, w10
 74: 00 00 00 94   bl  0x74 <_main+0x3c>
 78: e0 0b 40 b9   ldr  w0, [sp, #8]
 7c: fd 7b 41 a9   ldp  x29, x30, [sp, #16]
 80: ff 83 00 91   add  sp, sp, #32
 84: c0 03 5f d6   ret

可以看到ltmp0的第一个ff 83 00对应代码段开头是一样的,结尾的ret对应的5f d6也可以对应到上面代码段的结尾。

数据段和只读数据段

Contents of section __data:
 0088 54000000 55000000                    T...U...

这里可以看到data段就是8个字节,一个global_init_var和一个static_var各占4个字节,分别对应的值0x54和0x55换成10进制就是84和85,采用小端存储

BSS段

存放未初始化的全局变量和局部变量,有些变量并没有放在.bss段。编译器只预留了一个未定义的全局符号,等到链接时再在.bss段分配空间。

其他段

wecom-temp-260462-fcec74b55b964f10bc93ad4424c09c4e.jpg

ELF文件结构描述

wecom-temp-170762-f022ccb43969ab50fe15340c3d3d0866.jpg

ELF文件头中定义了ELF魔数、文件机器字节长度、数据存储方式等等信息

  • ELF魔数 包含ELF字长(32/64为)、字节序(大小端)、ELF文件版本(一般是1)

  • 文件类型 .o文件,可执行文件,共享文件比如.so

  • 机器类型 运行在什么平台下,比如EM_386表示运行Intel x86

段表 (Section Header Table)

描述了name,type,flags,addr,offset等段的相关信息

  • 段的类型 表示是程序段(代码段、数据段)还是符号表等等

  • 段的标志位 表示该断在进程虚拟地址空间的属性,比如是否可写,可执行。

  • 段的链接信息 如果是段的类型跟链接相关,比如重定位表、符号表

重定位表

链接器在处理目标文件时,需要对目标文件进行重定位,即代码段和数据段中那些对绝对地址的引用,这些都记录在重定位表里面.

字符串表

通过字符串表和偏移来查找对应的字符串

wecom-temp-151694-4d7f11b48db67b667bf43622d9bbef18.jpg

链接的接口-符号

在链接中,我们把函数和变量统称为符号(Symbol),函数名或变量名就是符号名(Symbol Name)

每一个目标文件都会有一个相应的符号表(Symbol Table)

每个定义的符号有一个对应的值,叫做符号值(Symbol Value),对应变量和函数来说,符号值就是它们的地址。

符号表类型

  • 定义在本目标文件的全局符号
  • 在本目标文件中引用的全局符号,却没有定义在本目标文件,一般叫做外部符号(External Symbol)
  • 段名称,如.text,.data等
  • 局部符号
  • 行号信息

符号表结构,通常是一个结构体数组,每个结构体存储一个符号,里面包含名称,对应的值,类型(数据,函数,段,文件名),所属的段,符号绑定信息(局部,全局,弱引用)

特殊符号:链接器脚本中定义的一些符号,可以再代码中声明并且使用

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

名称修饰:编译器在将源码编译成目标文件时,会将函数和变量的名字进行修饰,形成符号名。

extern "C"

C++为了与C兼容,在符号的管理上,添加了一个声明或定义一个C的符号的关键字用法。C++编译器会将在extern "C"的大括号内部的代码当做C语言代码处理,因为C语言的符号修饰规则和C++不一样,所以最终生成的符号是C的风格而非C++风格。

弱符号和强符号

对于C/C++语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。

  • 不允许强符号被多次定义
  • 一个符号在某个目标文件中是强符号,在其他文件都是弱符号,那么选择强符号
  • 如果一个符号在所有目标文件中都是弱符号,那么选择占用空间最大的一个

强引用: 如果符号引用在目标文件被最终链接时,没有找到该符号的定义,没有被正确决议,链接器就会报符号未定义错误,这种被称为强引用(Strong Reference)

弱引用(Weak Reference) 如果该符号有定义,则链接器将该符号的引用决议;如果该符号未被定义,则链接器对于该引用不报错。一般对于未定义的弱引用,链接器默认其为0

弱符号和弱引用对于库来说十分有用,可以用来裁剪和组合某些功能,比如如下代码,用来决定是否有多线程,在链接时是否连接Glib库(是否在编译时有-lpthread选项)

#include <stdio.h>
#include <pthread.h>

int pthread_create(pthread_t *, const pthread_attr_t *, void* (*)(void*), void*) __attribute__((weak));

int main()
{
    if (pthread_create) {
        printf("This is multi-thread version!\n");
    } else {
        printf("This is single-thread version!\n");
    }
}

编译运行

$ gcc pthread.c -o pt
$ ./pt
This is single-thread version!
$ gcc pthread.c -lpthread -o pt
$ ./pt
This is multi-thread version!

调试信息

现在编译器几乎都支持源代码级别的调试,这会在目标文件中添加很多debug相关的段,保存了目标代码地址和源代码中的哪一行、函数和变量的类型、结构体定义等相关的信息。

现在的ELF文件采用一个叫DWARF(Debug With Arbitrary Record Format)的标准的调试信息格式,一般发布的时候需要裁剪掉它

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

推荐阅读更多精彩内容