binary hacks读数笔记(ld 链接讲解 一)
首先我们先看两段代码:
a.c
extern int shared;
int main(){
int a=100;
swap(&a,&shared);
}
b.c
int shared=1;
void swap(int* a,int* b){
*a^=*b^=*a^=*b;
}
gcc -c a.c b.c 得到a.o 与b.o
1、查看a.o:
[root@tlinux misc]# objdump -h a.o a.o: file format elf64-x86-64 Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000027 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 0000000000000000 0000000000000000 00000067 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 0000000000000000 0000000000000000 00000067 2**0
ALLOC
3 .comment 0000002e 0000000000000000 0000000000000000 00000067 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00000095 2**0
CONTENTS, READONLY
5 .eh_frame 00000038 0000000000000000 0000000000000000 00000098 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
2、查看b.o:
[root@tlinux misc]# objdump -h b.o b.o: file format elf64-x86-64 Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000004a 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 0000000000000000 0000000000000000 0000008c 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 0000000000000000 0000000000000000 00000090 2**0
ALLOC
3 .comment 0000002e 0000000000000000 0000000000000000 00000090 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000be 2**0
CONTENTS, READONLY
5 .eh_frame 00000038 0000000000000000 0000000000000000 000000c0 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
3、链接之前,VMA与LMA都是0,即目标文件的虚拟空间地址与装载地址都无效。经过链接ld过程,才会给链接文件分配虚拟地址空间。
ld a.o b.o -e main -o ab
链接过程,合并了a.o与b.o的代码段、数据段,具体的位置与大小如下所示:
具体信息如下所示
[root@tlinux misc]# objdump -h ab ab: file format elf64-x86-64 Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000071 00000000004000e8 00000000004000e8 000000e8 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .eh_frame 00000058 0000000000400160 0000000000400160 00000160 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data 00000004 0000000000601000 0000000000601000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .comment 0000002d 0000000000000000 0000000000000000 00001004 2**0
CONTENTS, READONLY
同时,我们可以看一下,链接后,各个源文件的符号表也合成一张全局符号表,且符号表中表明各个符号的虚拟空间位置:
readelf -s ab
Symbol table '.symtab' contains 13 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000004000e8 0 SECTION LOCAL DEFAULT 1
2: 0000000000400160 0 SECTION LOCAL DEFAULT 2
3: 0000000000601000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.c
6: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.c
7: 000000000040010f 74 FUNC GLOBAL DEFAULT 1 swap
8: 0000000000601000 4 OBJECT GLOBAL DEFAULT 3 shared
9: 0000000000601004 0 NOTYPE GLOBAL DEFAULT 3 __bss_start
10: 00000000004000e8 39 FUNC GLOBAL DEFAULT 1 main
11: 0000000000601004 0 NOTYPE GLOBAL DEFAULT 3 _edata
12: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 3 _end
4、接下来介绍一下符号的解析与重定位:
首先查看一下未重定位之前,a.o中是怎么处理shared变量与swap函数的:
利用 objdump -d a.o查看一下,a.o的反汇编代码
[root@tlinux misc]# objdump -d a.o a.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
f: 48 8d 45 fc lea -0x4(%rbp),%rax
13: be 00 00 00 00 mov $0x0,%esi //00 00 00 00 shared 未给地址
18: 48 89 c7 mov %rax,%rdi
1b: b8 00 00 00 00 mov $0x0,%eax
20: e8 00 00 00 00 callq 25 <main+0x25> //swap函数也未给地址
25: c9 leaveq
26: c3 retq
5、经过ld链接之后,在最后文件ab中,shared 与 swap都知道了地址。因为链接过程会分配虚拟地址,那么根据前面第三点链接过后的信息,可以知道各个段的虚拟地址,那么
其中各个符号的地址也会知道。那么,经过连接之后,ab中的代码反汇编结果如何,如下所示:
[root@tlinux misc]# objdump -d ab ab: file format elf64-x86-64 Disassembly of section .text: 00000000004000e8 <main>:
4000e8: 55 push %rbp
4000e9: 48 89 e5 mov %rsp,%rbp
4000ec: 48 83 ec 10 sub $0x10,%rsp
4000f0: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
4000f7: 48 8d 45 fc lea -0x4(%rbp),%rax
4000fb: be 00 10 60 00 mov $0x601000,%esi //00 60 10 00 详见ab文件的数据段
400100: 48 89 c7 mov %rax,%rdi
400103: b8 00 00 00 00 mov $0x0,%eax
400108: e8 02 00 00 00(相对下一行命令偏移 02) callq 40010f <swap> // 由下面swap在 40010f处可知,a.o b.o链接到一起后,swap的函数虚拟地址可知 call 命令: 40010d+00000002
40010d: c9 leaveq
40010e: c3 retq 000000000040010f <swap>:
40010f: 55 push %rbp
400110: 48 89 e5 mov %rsp,%rbp
400113: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400117: 48 89 75 f0 mov %rsi,-0x10(%rbp)
40011b: 48 8b 45 f8 mov -0x8(%rbp),%rax
40011f: 8b 10 mov (%rax),%edx
400121: 48 8b 45 f0 mov -0x10(%rbp),%rax
400125: 8b 08 mov (%rax),%ecx
400127: 48 8b 45 f8 mov -0x8(%rbp),%rax
40012b: 8b 30 mov (%rax),%esi
40012d: 48 8b 45 f0 mov -0x10(%rbp),%rax
400131: 8b 00 mov (%rax),%eax
400133: 31 c6 xor %eax,%esi
400135: 48 8b 45 f8 mov -0x8(%rbp),%rax
400139: 89 30 mov %esi,(%rax)
40013b: 48 8b 45 f8 mov -0x8(%rbp),%rax
40013f: 8b 00 mov (%rax),%eax
400141: 31 c1 xor %eax,%ecx
400143: 48 8b 45 f0 mov -0x10(%rbp),%rax
400147: 89 08 mov %ecx,(%rax)
400149: 48 8b 45 f0 mov -0x10(%rbp),%rax
40014d: 8b 00 mov (%rax),%eax
40014f: 31 c2 xor %eax,%edx
400151: 48 8b 45 f8 mov -0x8(%rbp),%rax
400155: 89 10 mov %edx,(%rax)
400157: 5d pop %rbp
400158: c3 retq
6、重定位表信息:
对于可重定位文件,必须包含重定位表,用来描述如何修改相应的段。可以利用objdump -r a.o查看重定位表
[root@tlinux misc]# objdump -r a.o a.o: file format elf64-x86-64 RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000014 R_X86_64_32 shared
0000000000000021 R_X86_64_PC32 swap-0x0000000000000004
OFFSET指的是需要被重定位的内容在可重定位文件中的位置,看第4点的反汇编内容可知,0x14位置和0x21位置分别为shared 与 swap.需要被重定位
binary hacks读数笔记(ld 链接讲解 一)的更多相关文章
- binary hacks读数笔记(ld 链接讲解 二)
这块将介绍一下ld链接命令的具体使用.ld的作用:ld是GNU binutils工具集中的一个,是众多Linkers(链接器)的一种.完成的功能自然也就是链接器的基本功能:把各种目标文件和库文件链接起 ...
- binary hacks读数笔记(堆、栈 VMA的分布)
一.首先看一个简单的程序: #include<stdlib.h> int main() { while(1) { sleep(1000); } return 0; } gcc -stati ...
- binary hacks读数笔记(共享库)
共享库从文件结构上来讲,与共享对象没什么区别.Linux下,共享库就是普通的ELF共享对象. 1.共享库命名: libname.so.x.y.z :其中最前面使用前缀lib,中间是库的名字和后缀&qu ...
- binary hacks读数笔记(readelf基本命令)
一.首先对readelf常用的参数进行简单说明: readelf命令是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用,下面以ELF格式可执行文件test为例详细介绍: 1. ...
- binary hacks读数笔记(装载)
1.地址空间 在linux系统中,每个进程拥有自己独立的虚拟地址空间,这个虚拟地址空间的大小是由计算机硬件决定的,具体地说,是由CPU的位数决定的.比如,32位硬件平台决定的虚拟地址空间大小:0--2 ...
- binary hacks读数笔记(nm命令)
nm命令(names):输出包含三个部分:1 符号值.默认显示十六进制,也可以指定: 2 符号类型.小写表示是本地符号,大写表示全局符号(external); 3 符号名称. 例如:nm Simple ...
- binary hacks读数笔记(file命令与magic file)
file命令的作用是用于检验文件的类型,并打印至终端.file命令检验文件类型按以下顺序来完成: 检验文件系统(Filesystem)中支持的文件类型. 检验magic file规则. 检验文件内容的 ...
- binary hacks读数笔记(dlopen、dlsym、dlerror、dlclose)
1.dlopen是一个强大的库函数.该函数将打开一个动态库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.比如 Apache Web 服务器利用这个函数在运行过程中加载 ...
- binary hacks读数笔记(readelf命令)
可以用readelf命令来查看elf文件内容,跟objdump相比,这个命令更详细. 1. readelf -h SimpleSection.o ELF Header: Magic: 7f 45 4c ...
随机推荐
- ORM查询相关的操作
必知必会13条 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.setti ...
- snappy压缩/解压库
snappy snappy是由google开发的压缩/解压C++库,注重压缩速度,压缩后文件大小比其它算法大一些 snappy在64位x86并且是小端的cpu上性能最佳 在Intel(R) Core( ...
- pytest文档43-元数据使用(pytest-metadata)
前言 什么是元数据?元数据是关于数据的描述,存储着关于数据的信息,为人们更方便地检索信息提供了帮助. pytest 框架里面的元数据可以使用 pytest-metadata 插件实现.文档地址http ...
- 【C语言学习笔记】C语言函数执行成功时,返回1和返回0,究竟哪个好?
基本上,没有人会将大段的C语言代码全部塞入 main() 函数,更好的做法是按照复用率高,耦合性低的原则,尽可能的将代码拆分不同的功能模块,并封装成函数.C语言代码的组合千变万化,因此函数的功能可能会 ...
- Spark如何进行动态资源分配
一.操作场景 对于Spark应用来说,资源是影响Spark应用执行效率的一个重要因素.当一个长期运行的服务,若分配给它多个Executor,可是却没有任何任务分配给它,而此时有其他的应用却资源紧张,这 ...
- 第二十五章 ansible基础
一.Ansible概述 1.什么是Ansible Ansible是一个自动化统一配置管理工具,自动化主要体现在Ansible集成了丰富模块以及功能组件,可以通过一个命令完成一系列的操作,进而能减少重复 ...
- Android面试题收录及解答10月刊
前言 嗨,大家好,好久不见.这里跟大家侃侃这中间发生了什么. 一个月前呢,想准备面试,就网上随便找找面试题什么的,发现要么就是卖课的,要么就是不给详细回答的或者回答不够深的(也许是我没找到).反正稍微 ...
- better-scroll插件 api
Vue中的better-scroll插件 在需要的文件中添加 import BScorll from 'better-scroll'; 引用的示例代码: let scroll = new BScrol ...
- java 文件和byte 互转
/** * 获得指定文件的byte数组 */ private byte[] getBytes(String filePath){ byte[] buffer = null; try { File fi ...
- 测试可变字符序列stringBuilder
测试可变字符序列 stringBuilder(线程不安全,效率高,一般用),stringBuffer(线程安全,效率低)stringBuilder,stringBuffer和string的区别前者可变 ...