首先我们先看两段代码:

a.c

  1. extern int shared;
  2.  
  3. int main(){
  4. int a=100;
  5. swap(&a,&shared);
  6. }

b.c

  1. int shared=1;
  2.  
  3. void swap(int* a,int* b){
  4. *a^=*b^=*a^=*b;
  5. }

gcc  -c a.c b.c 得到a.o 与b.o

1、查看a.o:

  1. [root@tlinux misc]# objdump -h a.o
  2.  
  3. a.o: file format elf64-x86-64
  4.  
  5. Sections:
  6. Idx Name Size VMA LMA File off Algn
  7. 0 .text 00000027 0000000000000000 0000000000000000 00000040 2**0
  8. CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  9. 1 .data 00000000 0000000000000000 0000000000000000 00000067 2**0
  10. CONTENTS, ALLOC, LOAD, DATA
  11. 2 .bss 00000000 0000000000000000 0000000000000000 00000067 2**0
  12. ALLOC
  13. 3 .comment 0000002e 0000000000000000 0000000000000000 00000067 2**0
  14. CONTENTS, READONLY
  15. 4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00000095 2**0
  16. CONTENTS, READONLY
  17. 5 .eh_frame 00000038 0000000000000000 0000000000000000 00000098 2**3
  18. CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

2、查看b.o:

  1. [root@tlinux misc]# objdump -h b.o
  2.  
  3. b.o: file format elf64-x86-64
  4.  
  5. Sections:
  6. Idx Name Size VMA LMA File off Algn
  7. 0 .text 0000004a 0000000000000000 0000000000000000 00000040 2**0
  8. CONTENTS, ALLOC, LOAD, READONLY, CODE
  9. 1 .data 00000004 0000000000000000 0000000000000000 0000008c 2**2
  10. CONTENTS, ALLOC, LOAD, DATA
  11. 2 .bss 00000000 0000000000000000 0000000000000000 00000090 2**0
  12. ALLOC
  13. 3 .comment 0000002e 0000000000000000 0000000000000000 00000090 2**0
  14. CONTENTS, READONLY
  15. 4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000be 2**0
  16. CONTENTS, READONLY
  17. 5 .eh_frame 00000038 0000000000000000 0000000000000000 000000c0 2**3
  18. CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

3、链接之前,VMA与LMA都是0,即目标文件的虚拟空间地址与装载地址都无效。经过链接ld过程,才会给链接文件分配虚拟地址空间。

ld a.o b.o -e main -o ab

链接过程,合并了a.o与b.o的代码段、数据段,具体的位置与大小如下所示:

具体信息如下所示

  1. [root@tlinux misc]# objdump -h ab
  2.  
  3. ab: file format elf64-x86-64
  4.  
  5. Sections:
  6. Idx Name Size VMA LMA File off Algn
  7. 0 .text 00000071 00000000004000e8 00000000004000e8 000000e8 2**0
  8. CONTENTS, ALLOC, LOAD, READONLY, CODE
  9. 1 .eh_frame 00000058 0000000000400160 0000000000400160 00000160 2**3
  10. CONTENTS, ALLOC, LOAD, READONLY, DATA
  11. 2 .data 00000004 0000000000601000 0000000000601000 00001000 2**2
  12. CONTENTS, ALLOC, LOAD, DATA
  13. 3 .comment 0000002d 0000000000000000 0000000000000000 00001004 2**0
  14. CONTENTS, READONLY

 同时,我们可以看一下,链接后,各个源文件的符号表也合成一张全局符号表,且符号表中表明各个符号的虚拟空间位置:

readelf -s ab

  1. Symbol table '.symtab' contains 13 entries:
  2. Num: Value Size Type Bind Vis Ndx Name
  3. 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  4. 1: 00000000004000e8 0 SECTION LOCAL DEFAULT 1
  5. 2: 0000000000400160 0 SECTION LOCAL DEFAULT 2
  6. 3: 0000000000601000 0 SECTION LOCAL DEFAULT 3
  7. 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
  8. 5: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.c
  9. 6: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.c
  10. 7: 000000000040010f 74 FUNC GLOBAL DEFAULT 1 swap
  11. 8: 0000000000601000 4 OBJECT GLOBAL DEFAULT 3 shared
  12. 9: 0000000000601004 0 NOTYPE GLOBAL DEFAULT 3 __bss_start
  13. 10: 00000000004000e8 39 FUNC GLOBAL DEFAULT 1 main
  14. 11: 0000000000601004 0 NOTYPE GLOBAL DEFAULT 3 _edata
  15. 12: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 3 _end

4、接下来介绍一下符号的解析与重定位:

首先查看一下未重定位之前,a.o中是怎么处理shared变量与swap函数的:

利用 objdump -d a.o查看一下,a.o的反汇编代码

  1. [root@tlinux misc]# objdump -d a.o
  2.  
  3. a.o: file format elf64-x86-64
  4.  
  5. Disassembly of section .text:
  6.  
  7. 0000000000000000 <main>:
  8. 0: 55 push %rbp
  9. 1: 48 89 e5 mov %rsp,%rbp
  10. 4: 48 83 ec 10 sub $0x10,%rsp
  11. 8: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
  12. f: 48 8d 45 fc lea -0x4(%rbp),%rax
  13. 13: be 00 00 00 00 mov $0x0,%esi //00 00 00 00 shared 未给地址
  14. 18: 48 89 c7 mov %rax,%rdi
  15. 1b: b8 00 00 00 00 mov $0x0,%eax
  16. 20: e8 00 00 00 00 callq 25 <main+0x25> //swap函数也未给地址
  17. 25: c9 leaveq
  18. 26: c3 retq

5、经过ld链接之后,在最后文件ab中,shared 与 swap都知道了地址。因为链接过程会分配虚拟地址,那么根据前面第三点链接过后的信息,可以知道各个段的虚拟地址,那么

其中各个符号的地址也会知道。那么,经过连接之后,ab中的代码反汇编结果如何,如下所示:

  1. [root@tlinux misc]# objdump -d ab
  2.  
  3. ab: file format elf64-x86-64
  4.  
  5. Disassembly of section .text:
  6.  
  7. 00000000004000e8 <main>:
  8. 4000e8: 55 push %rbp
  9. 4000e9: 48 89 e5 mov %rsp,%rbp
  10. 4000ec: 48 83 ec 10 sub $0x10,%rsp
  11. 4000f0: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
  12. 4000f7: 48 8d 45 fc lea -0x4(%rbp),%rax
  13. 4000fb: be 00 10 60 00 mov $0x601000,%esi //00 60 10 00 详见ab文件的数据段
  14. 400100: 48 89 c7 mov %rax,%rdi
  15. 400103: b8 00 00 00 00 mov $0x0,%eax
  16. 400108: e8 02 00 00 00(相对下一行命令偏移 02 callq 40010f <swap> // 由下面swap在 40010f处可知,a.o b.o链接到一起后,swap的函数虚拟地址可知 call 命令: 40010d+00000002
  17. 40010d: c9 leaveq
  18. 40010e: c3 retq
  19.  
  20. 000000000040010f <swap>:
  21. 40010f: 55 push %rbp
  22. 400110: 48 89 e5 mov %rsp,%rbp
  23. 400113: 48 89 7d f8 mov %rdi,-0x8(%rbp)
  24. 400117: 48 89 75 f0 mov %rsi,-0x10(%rbp)
  25. 40011b: 48 8b 45 f8 mov -0x8(%rbp),%rax
  26. 40011f: 8b 10 mov (%rax),%edx
  27. 400121: 48 8b 45 f0 mov -0x10(%rbp),%rax
  28. 400125: 8b 08 mov (%rax),%ecx
  29. 400127: 48 8b 45 f8 mov -0x8(%rbp),%rax
  30. 40012b: 8b 30 mov (%rax),%esi
  31. 40012d: 48 8b 45 f0 mov -0x10(%rbp),%rax
  32. 400131: 8b 00 mov (%rax),%eax
  33. 400133: 31 c6 xor %eax,%esi
  34. 400135: 48 8b 45 f8 mov -0x8(%rbp),%rax
  35. 400139: 89 30 mov %esi,(%rax)
  36. 40013b: 48 8b 45 f8 mov -0x8(%rbp),%rax
  37. 40013f: 8b 00 mov (%rax),%eax
  38. 400141: 31 c1 xor %eax,%ecx
  39. 400143: 48 8b 45 f0 mov -0x10(%rbp),%rax
  40. 400147: 89 08 mov %ecx,(%rax)
  41. 400149: 48 8b 45 f0 mov -0x10(%rbp),%rax
  42. 40014d: 8b 00 mov (%rax),%eax
  43. 40014f: 31 c2 xor %eax,%edx
  44. 400151: 48 8b 45 f8 mov -0x8(%rbp),%rax
  45. 400155: 89 10 mov %edx,(%rax)
  46. 400157: 5d pop %rbp
  47. 400158: c3 retq

6、重定位表信息:

对于可重定位文件,必须包含重定位表,用来描述如何修改相应的段。可以利用objdump  -r  a.o查看重定位表

  1. [root@tlinux misc]# objdump -r a.o
  2.  
  3. a.o: file format elf64-x86-64
  4.  
  5. RELOCATION RECORDS FOR [.text]:
  6. OFFSET TYPE VALUE
  7. 0000000000000014 R_X86_64_32 shared
  8. 0000000000000021 R_X86_64_PC32 swap-0x0000000000000004
  1. OFFSET指的是需要被重定位的内容在可重定位文件中的位置,看第4点的反汇编内容可知,0x14位置和0x21位置分别为shared swap.需要被重定位

binary hacks读数笔记(ld 链接讲解 一)的更多相关文章

  1. binary hacks读数笔记(ld 链接讲解 二)

    这块将介绍一下ld链接命令的具体使用.ld的作用:ld是GNU binutils工具集中的一个,是众多Linkers(链接器)的一种.完成的功能自然也就是链接器的基本功能:把各种目标文件和库文件链接起 ...

  2. binary hacks读数笔记(堆、栈 VMA的分布)

    一.首先看一个简单的程序: #include<stdlib.h> int main() { while(1) { sleep(1000); } return 0; } gcc -stati ...

  3. binary hacks读数笔记(共享库)

    共享库从文件结构上来讲,与共享对象没什么区别.Linux下,共享库就是普通的ELF共享对象. 1.共享库命名: libname.so.x.y.z :其中最前面使用前缀lib,中间是库的名字和后缀&qu ...

  4. binary hacks读数笔记(readelf基本命令)

    一.首先对readelf常用的参数进行简单说明: readelf命令是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用,下面以ELF格式可执行文件test为例详细介绍: 1. ...

  5. binary hacks读数笔记(装载)

    1.地址空间 在linux系统中,每个进程拥有自己独立的虚拟地址空间,这个虚拟地址空间的大小是由计算机硬件决定的,具体地说,是由CPU的位数决定的.比如,32位硬件平台决定的虚拟地址空间大小:0--2 ...

  6. binary hacks读数笔记(nm命令)

    nm命令(names):输出包含三个部分:1 符号值.默认显示十六进制,也可以指定: 2 符号类型.小写表示是本地符号,大写表示全局符号(external); 3 符号名称. 例如:nm Simple ...

  7. binary hacks读数笔记(file命令与magic file)

    file命令的作用是用于检验文件的类型,并打印至终端.file命令检验文件类型按以下顺序来完成: 检验文件系统(Filesystem)中支持的文件类型. 检验magic file规则. 检验文件内容的 ...

  8. binary hacks读数笔记(dlopen、dlsym、dlerror、dlclose)

    1.dlopen是一个强大的库函数.该函数将打开一个动态库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.比如 Apache Web 服务器利用这个函数在运行过程中加载 ...

  9. binary hacks读数笔记(readelf命令)

    可以用readelf命令来查看elf文件内容,跟objdump相比,这个命令更详细. 1. readelf -h SimpleSection.o ELF Header: Magic: 7f 45 4c ...

随机推荐

  1. 多测师讲解自动化测试 _接口面试题(001)_高级讲师肖sir

    1.为什么要做接口测试(必要性)1.可以发现很多在页面上操作发现不了的bug2.检查系统的异常处理能力3.检查系统的安全性.稳定性4.前端随便变,接口测好了,后端不用变5.可以测试并发情况,一个账号, ...

  2. Linux发行版教你如何选 给入门者的选择通法

    Linux的发行版何止琳琅满目,简直是乱入你眼. 本篇将介绍选择发行版的经验和通用法则,主要会从PC角度去谈. 更新于2020年,初次发布于2017年 选择发行版需考虑哪些因素 选择发行版时需要考虑的 ...

  3. linux磁盘空间满的处理

    Java中运行SQL插入数据时报错: linux磁盘空间满处理: 1.df -h  查看磁盘空间占用,实际上是查看磁盘块占用的文件(block) 2.分别查看输入以下命令 (面对磁盘满了,通过下列命令 ...

  4. 面经手册 · 第14篇《volatile 怎么实现的内存可见?没有 volatile 一定不可见吗?》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.码场心得 你是个能吃苦的人吗? 从前的能吃苦大多指的体力劳动的苦,但现在的能吃苦已经包括太 ...

  5. poj1011 Sticks (搜索经典好题)

    poj1011 Sticks 题目连接: poj1011 Description George took sticks of the same length and cut them randomly ...

  6. Android测试工具 UIAutomator介绍

    UI Automator 测试工具定义以及用途 UI Automator 测试框架提供了一组 API,用于构建在用户应用和系统应用上执行交互的界面测试.通过 UI Automator API,您可以执 ...

  7. # ThreeJS学习7_裁剪平面(clipping)

    ThreeJS学习7_裁剪平面(clipping) 目录 ThreeJS学习7_裁剪平面(clipping) 1. 裁剪平面简介 2. 全局裁剪和局部裁剪 3. 被多个裁剪平面裁剪后 4. 被多个裁剪 ...

  8. 多线程之Callable

    多线程实现Callable的好处有三点 1.Callable支持泛型 2.Callable支持返回值 3.Callable可以抛出异常 class MyThread2 implements Calla ...

  9. git每次提交代码都要设置账号密码的问题

    git config --global credential.helper store 待下一次提交代码的时候,输入了正确的用户名和密码,之后 就不需要输入用户名密码

  10. 02 HTML 常见标记 选择器 样式

    no.02今天主要学习了在web中的HTML CSS,并在其中制作了明信片,在制作明信片途中有几个知识点需要总结:1.HTML 全称hyper text markup language 超文本标记语言 ...