第六章源代码编译和调试连接概览_第1页
第六章源代码编译和调试连接概览_第2页
第六章源代码编译和调试连接概览_第3页
第六章源代码编译和调试连接概览_第4页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、编译连接四过程连接1、编译连接过程概览连接的目预处理或的目预处理或预编译汇编编译汇编编译符号解析 a、符号确定和调整 b、如果使用静态库话,需 要拷贝静态库重定位,给定链接符号解析 a、符号确定和调整 b、如果使用静态库话,需 要拷贝静态库重定位,给定链接地址目的:生成ELF格式可执行文件命令:gcc -o a a.c/a.i/a.s的目的目的目的目将a.s,生成为将a.s,生成为ELF格式的可重定位目标文件a.o,命令:gcc -c a.c -o a.o对#内容做处理,生成a.i的扩展性c文件命令:gcc -E a.c -o a.i cpp a.c -o a.i生成机器汇编a.s,机器汇编包

2、含了a.o需要的各种符号命令:gcc -S a.c -o a.s以上的4个步骤中的链接,是相对比较难理解。但是充分地理解链接,对于我们来说还是很有帮助的。有助于构造大型程序,因为构造大型程序往往需要很多模块和库的支持,但是在链接这些模块和库时,所提示的错误也往往让人很迷惑,但是如果你很好的理解了编译链接的过程的话,这将不是难题。有助于对函数和全局变量的链接域概念,进行深入地理解。有助于理解与系统相关的知识:如何加载可执行文件运行,什么是虚拟内存,什么分页和内存映射等。理解有关库(动态库和静态库)的概念。2、各个步骤详细描述2.1第1步,预编译所需工具软件:预处理器目的:处理所有#开头的指令,生

3、成xxx.i的扩展性c源文件处理内容:a)、宏展开,将宏用实际的宏常量替换b)、头文件包含(头文件可嵌套包含),将头文件中所有的类型定义和函数声明包含到c文件c)、处理条件编译,将条件编译允许的代码留在c文件中,不允许的排除在外a.c#include #include#include #include #define STR hellostatic int c = 100;char b = 1;char *p = STR;int h; struct kk int e; char f; ;struct kk yy = 100, a;int main(int kk, char *argv)/arg

4、v存放参数的 int i = 0; int a = 0; a = +i + +i + +i; printf(a = %d, i = %dn, a, i); return 0;加了这么多的全局变量,仅仅是为了加了这么多的全局变量,仅仅是为了全面的说明汇编文件的结构而已ls -al a.c 查看文件大小-rw-rw-r-. 1 linux linux 388 Mar 11 16:12 a.c /红色字体是文件的大小file a.c /查看文件的类型c: UTF-8 Unicode C program text /c程序文本文件,UTF-8 Unicode含中文编码的格式,目的主要/是为了能够对c代

5、码做各种的中文注释命令:gcc -E a.c -o a.i 或者 cc1 a.c -o a.i ,cc1是处理软件,a.c是被输入数据,a.i是加工后数据生成的a.i文件如下:。1841 static int c = 100;。1841 static int c = 100;1842 char b = 1;/STR宏展开,被”hello”替换1843 char *p = hello;1844 int h;1845 struct kk1846 1847 int e;1848 char f;1849 ;1850 struct kk yy = 100, a;1851 1852 int main(in

6、t kk, char *argv)1853 1854 int i = 0;1855 int a = 0;1856 a = +i + +i + +i;1857 printf(a = %d, i = %dn, a, i);1858 return 0;1859 包含了各种的函数声明和类型定义。 486 extern int fprintf (FILE *_restrict _stream, 487 _const char *_restrict _format, .);。/我们需要调用到的函数extern int printf (_const char *_restrict _format, .);。

7、 extern int vprintf (_const char *_restrict _format, _gnuc_va_list _arg ); 508 509 extern int vsprintf (char *_restrict _s, _const char *_restrict _forma t, 510 _gnuc_va_list _arg) _attribute_ (_nothrow_);。 919 typedef struct 920 921 int quot; 922 int rem; 923 div_t; 924 925 ls -al a.i 查看文件大小-rw-rw-

8、r-. 1 linux linux 39324 Mar 11 16:16 a.i /红色字体是文件的大小file a.i /查看文件的类型a.i: ASCII C program text /c程序文本文件,纯英文编码格式a.c 变为a.i后,变化如下:a)、文件大小从388变为了39324,因为导入了头文件b)、文件格式从UTF-8 Unicode变为了ASCII,也就是说从包含中文的编码格式,变为了纯英文的编码格式,但是如果printf(“你好n”);中,或其他的字符串中包含了中文的话,格式还会保持为UTF-8 Unicode格式,所以a.i到底是UTF-8 Unicode还是ASCII格

9、式,就看字符串中包不包含中文。2.2、第2步,编译所需软件工具:编译器(c语言的词法语法分析)目的:生成对硬件针对性很强的机器汇编文件, gcc生成x86的机器汇编指令,arm-linux-gcc生成arm 的机器汇编指令处理内容:词法语法分析,将跨平台的高级语言c语言编译为x86的机器汇编命令:gcc -S a.i(a.c) -o a.s 编译器是处理软件,a.i是被输入数据,a.s是加工后数据a.s .file a.c /文件名 .file a.c /文件名/* 到.size c, 4前都是对变量c的说明,没有globale修饰代表是本地变量,只有本.c文件才能访问到*/ .data /初

10、始化的数据节 .align 4 /4字节对齐存放 .type c, object /类型是变来那个 .size c, 4 /占4个字节的空间 c: /c标号 .long 100 /.long等价于.int或.word,100存放于一个字的空间 .globl b /globle代表其它的.c文件也能够访问到,说明了它的链接域 .type b, object /变量 .size b, 1 /占1字节 b: .byte 49 /1的ascii值 .globl p .section .rodata /常量数据节 .LC0: /标号 .string hello .data /指针p放在数据段,p中方“h

11、ello” /的在常量节的存放地址 .type p, object /p是变量(指针变量) .size p, 4 /4个字节,地址都是4个字节 p: .long .LC0 /将“hello”在常量节的存放首地址,赋给指针变量p .comm h,4,4 /是未初始化的全局变量,它是一个弱符号,链接时可能会与其它同名符号合并, /如果长度不一致,选择长度大那个,如果遇到了强符号,就选择强符号,/其实这里涉及到了声明和定义的问题,.comm代表h是可能会被合并的通用符号/这个对于链接时的符号解析是非常有用的,第一个4代表空间大小。第二个4代表/对齐方式(4字节对齐),他必须是2的幂次,它是未被初始化

12、的若符号,最后被合并后的还/是个若符号的话,它就会被存在.bss段(在没有运行前,.bss里只有占位符,没有空间) .globl yy /yy是结构体 .align 4 /4字节对齐存放 .type yy, object /变量 .size yy, 8 /共8字节(为适当对齐) yy: .long 100 /结构体第一个变量的值 .byte 97 /结构体第二个变量的值,.byte代表只有一个字节 .zero 3 /空字节有3个,因为结构适当对齐(适当对齐将c语言时讲解),只用了5个字节,利用/3字节空的空间占位用 .section .rodata /后面的格式化输出的,字符串当道常量节.LC

13、1: .string a = %d, i = %dn /printf的格式字符串机器汇编余下部分代码如下:机器汇编余下部分代码如下: .text/代表后面的main放在大妈段 .globl main /表明main是全局的符号 .type main, function /符号main是函数 main: /标号,给人看的,对机器来说无意义/*红色字体前的4句话是涉及到实参,调用函数返回地址,调用函数栈帧,局部变量新栈帧和栈顶的入栈和变化,不易理解,这里就不描述*/ pushl %ebp movl %esp, %ebp andl $-16, %esp subl $32, %esp/*一下红色部分对

14、应a.c的红色部分,我会写* 是a = +i + +i + +i;的汇编实现 */ movl $0, 24(%esp) /24(%esp) 代表内存位置,24代表%esp存放地址+24 movl $0, 28(%esp) addl $1, 24(%esp) addl $1, 24(%esp) movl 24(%esp), %eax addl %eax, %eax addl $1, 24(%esp) addl 24(%esp), %eax movl %eax, 28(%esp) /*下面是printf()实现,需要给a格式字符串,给它a和i的值,新开两个空间来存放,为什么新开 *两个空间来访a和

15、i,自己思考*/ movl $.LC1, %eax /.LC1:printf格式字符串首地址 movl 24(%esp), %edx movl %edx, 8(%esp) movl 28(%esp), %edx movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave /函数栈释放等事宜。ls -al a.s 查看文件大小-rw-rw-r-. 1 linux linux 971 Mar 11 18:25 a.s /红色字体是文件的大小file a.s /查看文件的类型a.s: ASCII assembler pro

16、gram text /纯英文编码的汇编文本文件a.s 变为a.i后,变化如下:a)、文件大小相对于a.i的39324,a.s变小为了971,因为.c文件中只用到了printf一个动态库函数函数,而预处理却将所有的标准io动态库函数的声明和类型定义全部放到了.i中,但是编译时,只需要用到printf一个函数符号即可,所以会小了非常多,但是记住printf库函数并没有被复制进入a.s中,函数声明也只是告诉编译器,如果找不到printf函数符号,不要报警告和错误了,这不是一个问题,该函数在其它地方有实现,链接时连接进来即可,那么其它地方,有可能是其它.c,也有可能是其它库函数,这里printf就是库

17、函数。但是相对.c文件388,a.s的971还是大了很多,原因是一条c代码会被翻译成很多条汇编指令,因此文件会大很多,也不足为奇。b)、我们知道a.i的文件格式是UTF-8 Unicode还是ASCII格式,就看使用到的字符串中有没有包含中文,如printf(“你好”);这个字符串就是中文,但是不管a.i是什么格式,生成的a.s 都是ASCII格式,因为即便含有中文,中文也会变为ascii的数字编码,如“你好”就会变为 344275240345245275,这些数字均是ascii码。备注:机器汇编中main函数前面的各种带点(.)的符号很重要,后面可重定位目标文件的符号 表的生成需要用到他们2

18、.3、第3步,汇编所需软件工具:汇编器目的:将x86机器汇编指令,汇编成为ELF格式的二进制可重定位目标文件处理内容:汇编的词法语法分析命令:gcc -c a.s(a.c) -o a.o 或 as a.s -o a.o ,as是汇编处理程序,a.s是输入数据,a.o是加工后数据a.o?ELFAAAACADA 4(L U D$XD$D$XA D$XAD$XAD$XACD$XD$FT$XT$HT$ T$DD$d1dahel lo a = %d, i = %d 2 GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3).symtab.strtab.shstrt men

19、t.note.GNU-stack _ AF4ZD 0DP 3 ADH)ACT D% DH 我们打开a.o发现,居然是乱码,其实我们认为是乱码,但是不是的,文本编辑器忠实地按照要求翻译了这些二进制代码的,只是不是人所能够识别的格式而已,但是红色字体的ELF格式头我们能看的很清楚,说明该文件是ELF格式的。ls -al a.o 查看文件大小-rw-rw-r-. 1 linux linux 1096 Mar 11 18:58 a.o /红色字体是文件的大小file a.o /查看文件的类型/ELF格式 32 linux standard base 可重定位文件,用于x86平台,版本1,未瘦身(包含各

20、类符号表)a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not strippeda.o 变为a.s后,变化如下:a)、a.o的 1096和a.s的971基本差不多,只是a.o中多了些符号表,文件稍大些b)、a.s的ASSCII格式转为了a.o的ELF二进制格式将a.o进行反汇编:我们知道a.o是二进制文件,不是我们人能够看懂的格式,那么我们就需要一种方法来看懂,那就是反汇编反汇编命令:objdump -D a.o u_a.su_a.s 2 a.o: file format elf32-i386 2 a.o: fi

21、le format elf32-i386。 5 Disassembly of section .text: 6 7 00000000 : 8 0: 55 push %ebp 9 1: 89 e5 mov %esp,%ebp。 34 Disassembly of section .data: 35 36 00000000 : 37 0: 64 00 00 add %al,%fs:(%eax) 。 53 Disassembly of section .rodata: 54 55 00000000 : 56 0: 68 65 6c 6c 6f push $0 x6f6c6c65 57 5: 00 2

22、0 add %ah,(%eax)。 65 Disassembly of section .comment: 66 67 00000000 : 68 0: 00 47 43 add %al,0 x43(%edi) 69 3: 43 inc %ebx 70 4: 3a 20 cmp (%eax),%ah。对于从a.o反汇编来的u_a.s反汇编文件,我们并不需要知道里面的指令的含义,我们需要关心的是文件的组成结构,黑体代表组成的各个节,红色为机器汇编指令,粉红为汇编对应的二进制机器码,蓝色代表的是各个指令在各自节中的定位地址由上我们知道如下几件事、a.o的定位地址从0开始、代码被划分回了这么几个段、

23、代码段:只有.text也称为代码节、数据段:.data:静态数据节,.rodata:常量数据节,.comment:若符号节关于*.o的可重定位目标文件文件,ELF(Executable and Linkable Format, ELF)格式说明目标文件种类、如.o的可重定位目标文件(包括.a):包含二进制的代码和数据,链接时可以和其它的可重定位 目标文件一起合并起来,形成一个可执行二进制文件、可执行目标文件:包含二进制的数据和指令,可直接被加载器加载到虚拟内存上运行、共享库目标文件:其实就是动态库文件,一种特殊的可重定位文件,可以在程序运行时,动态 的被加载到内存中运行,以便提供功能支持.o文

24、件的ELF格式文件.o为什么需要ELF格式,因为我们的程序的运行,是需要依赖于这个格式的,因此我们在生成a.o时就需要将其a.s中的符号数据以ELF重新组合生成a.o文件,为最终生成ELF格式的可执行文件a做好准备。那么ELF格式是什么格式呢?实际上.o文件的ELF格式与可执行文件的ELF格式略有些不同的,以下是.o文件的ELF格式说明段索引号段名11节头部表10.strtab9.line8.debug7.rel.data6.rel.text5.symtab4.bss3 .data2.rodata1.textELF头.o里面其实是.comm.o里面其实是.comm各节说明:ELF头:计算机字大

25、小(我们的是4字节),大小端序,和帮助连接器语法分析和解释目标文件 的信息.text: 代码节(已编译程序的机器指令代码存放处).rodata:常量数据节,比如char *p = “hello”;指针字符串,“hello”就是放在这里,但p不放在这 里,p具体放在那里根据是局部变量还是全局变量而定,printf(“a = %dn”, a);中的“a = %dn”,字符串也放在这里。.data: 初始化的静态变量放在这里,如全局的int a = 100;局部的静态局部变量static int b = 10; 也放在这里,如果没有static修饰的局部变量,在运行是放到栈里,这里是a.o文件, 这

26、里没有可执行文件,还谈不上运行,所以还没有栈。.bss(Block Storage Start):未初始化的静态变量,不过运行时,会帮忙全部清零,.o里面这 个段只有占位符,实际不占磁盘空间,我们为了好记记为better save space,.o文件里 的.bss准确来说应该是,comm,所有.o的.comm合并(同名符号统一后)后才是.bss.symtab:程序中定义和引用的(调用)函数和全局变量的信息(符号解析需要用到),注意没有 局部变量。我定义了全局变量int a = 100;这个符号a就包含很多信息,如符号类 型(变量),空间大小,链接类型等等,其实这些信息在机器汇编.s文件中也有

27、体现, 但是生成.o后,所有的符号信息集中放在这里。1、符号类型模块m中定义的全局符号,如不带static修饰的链接域是全局的函数和全局变量其它模块定义,但是有本m模块引用的全局符号,称为外部符号,如其它模块中如不带static修饰的链接域是全局的函数和全局变量只被本m模块使用的本地符号,如带static的全局变量和函数,自动局部变量符号在栈中管理,但是带static的局部变量却归类为本地符号,根据有无初始化分别在.data和.bss中管理,如果出现重名,重名的符号在解析时将会被唯一化。.data /数据段 .align 4 /4字节对齐存放.data /数据段 .align 4 /4字节对齐

28、存放 .type c, object /类型是变量 .size c, 4 /占4个字节的空间 c: .long 100 /变量值我们从上面了解到c的这几个信息:(1) 4字节对齐存放 (2)符号类型是变量(object表示) (3)占4字节空间 (4)变量值为100 (5)连接类型是局部的(没有globle修饰)生成a.o后,这些信息会收集到.symtab这个段中,我们运行readelf -s a.o打印出a.o的符号列表看看,有关c的描述是否正确? Num: Value Size Type Bind Vis Ndx Name Num: Value Size Type Bind Vis Ndx

29、 Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FILE LOCAL DEFAULT ABS a.c/ABS不可重定位符号 2: 00000000 0 SECTION LOCAL DEFAULT 1 3: 00000000 0 SECTION LOCAL DEFAULT 3 4: 00000000 0 SECTION LOCAL DEFAULT 5 5: 00000000 0 SECTION LOCAL DEFAULT 6 6: 00000000 0 SECTION LOCAL DEFAULT 8 7: 00000000 0

30、 SECTION LOCAL DEFAULT 7 8: 00000000 4 OBJECT LOCAL DEFAULT 3 c 9: 00000004 1 OBJECT GLOBAL DEFAULT 3 b 10: 00000008 4 OBJECT GLOBAL DEFAULT 3 p 11: 00000004 4 OBJECT GLOBAL DEFAULT COM h /COM通用符号,对应.s的.comm 12: 0000000c 8 OBJECT GLOBAL DEFAULT 3 yy 13: 00000000 90 FUNC GLOBAL DEFAULT 1 main 14: 000

31、00000 0 NOTYPE GLOBAL DEFAULT UND printf /UND未定义符号Num:符号编号 Value:符号所致内容在所在节中的偏移 Size:内容占空间大小 Type:符号类型,如文件,变量,函数无类型等等 Bind:链接域:涉及c中static标志 Ndx:所在节编号 Name:符号名称上面的红色信息就是对变量c符号的描述。信息基本符合,唯独值(value)不符合,因为它的实际值放在的3指向的节.data段里面,这里根本不用存入。这个无需-g选项就能得到.rel.text:所有的.o合成一个可执行文件时,所有的.o同名节会合并在一起,那么重定位时就会有 很多需要修

32、改的地方,这个节里面就记录了在合并时.text中需要修改的位置.rel.data:记录了.data在合并时需要修改的位置,任何全局变量的信息在重定位时需要被修改.bebug: 调试符号表,其条目是程序中定义的局部变量和它的类型定义,以及程序中定义和引用 的局部变量,-g选项才能得到,对于GDB调试来说很重要.line: 原始c程序中每行c代码的行号和现在生成的机器代码间的对应关系,这个关系对于调 试来说也是很重要的,没有行号,很难进行错误定位,-g选项得到.strtab:一个字符串表,包含了各个节的名字,这些名字字符串以null结尾备注:1、前面的红色部分重点掌握,最两个.debug和.lin

33、e节可以用strip命令进行瘦身。 2、a.o的ELF格式非常重要,它为后面连接生成ELF格式的可执行文件打下基础2.4、第4步,链接所需软件工具:连接器目的:将x86ELF格式的各个.o文件链接为二进制ELF格式的可执行目标文件处理内容:根据链接脚本的要求,链接各个.o和各个库命令:gcc a.o(a.c) -o a 或 ld + 链接脚本 + 库函数a.o -o a ,ld是汇编处理程序,a.o和其它.o和库 目标文件是输入数据,a是加工后数据,那么我们会有一个疑问,那就是.o文件其实也是ELF 格式的呀?那他为什么还要经过链接再次生成ELF格式的可执行文件呢?如下图解释:ELF格式头EL

34、F格式头.text.rodata.data.bss其它段a.oELF格式头.text.rodata.data.bss其它段xxx.oELF格式头.text.rodata.data.bss其它段xxx.oELF格式头.text.rodata.data.bss其它段x.sooELF格式头.text.rodata.data.bss其它段xxx.a新的ELF格式头.text.rodata.data.bss其它段a每一个.o、.a和.so文件都会有自己的.text、rodata.、data.、bss等段而这.o都不能自己独立的运行,它们之间需要相互的支持才能运行,所以需要做随后的一次链接重新生成一个新的

35、ELF格式的可执行文件。并且需要生成对内存映射支持的相应节,才能加载虚拟内存运行那么这些段的布局格式是由链接脚本文件指定的,像a这种的普通文件是系统链接时,由缺省链接脚本文件指定,我们无权指定,而普通文件链接的动态库是共享库,是别人的,需要的原因是这些库能够支持普通文件的运行,没有他们是普通文件是不能运行的。指明了各个段的起始位置和段大小,机器大小端,机器字长,连接语法等实际上我们只有一个由a.c生成的.o,但是我们为了很好的说明连接的过程,我们假定了很多的.o文件,实际上我们真的写工程代码的话肯定也不止只有一个.o文件,上面的每个.o是分别对各自的.c文件进行预处理,编译汇编得到的,.so是

36、动态库,.a是静态库,库可以简单说为是一堆.o文件的集合,库的好处如下:便于模块化功能的实现便于版本更新和维护不会导致大量无用的代码赋值到可执行文件中,浪费宝贵的内存空间静态库节省时间但是浪费空间,动态库节省空间但是浪费时间,侧重点不同链接所做事情:符号解析:a)、符号唯一化每个符号的引用刚好和一个符号的定义联系起来,这就涉及声明与定义的问题,最终相同的符号会被统一为一个,统一时涉及符号强弱问题,函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号,符号解析时,针对强弱符号处理规则如下:规则1:不允许多个强符号规则2:一个强符号和多个弱符号,选择强符号,如定义全局变量int a=100

37、; 声明int a;前者为强,后者为弱规则3:多个都是弱符号,任意选择其中一个,如果定义了两个int a;都为初始化呢 ,两个都是若符号,选择在程序中最靠前的一个会被合并唯一化的符号将会被组成一个集合(E集合),符号唯一化就是对E集合进行操作b)、从其它的模块或库中搜索未定义符号,如果到处都找不到,那么提示符号未定的错误。未定义的符号组成一个集合(U集合),搜索未定义符号就是对U集合进行操作重定位:a)、节和符号的地址重定位将所有的.o的相同节合并起来,形成可执行文件中同名的新的聚合节,每个被唯一定义的符号和指令都要被赋予了运行时地址(或也称为连接地址,从0 x08048000开始)。重定位的

38、地址是由gcc默认的链接脚本指定的,学到后面的uboot的时候链接脚本是自己给的,倘若给定了链接地址,但是又不从链接地址开始运行,那么我们就说链接地址和实际的运行地址(pc实际取址)不相符合,链接地址和实际运行地址不符合,这就要求运行代码为位置无关代码,这和生成动态库时,指定-fpic选项生成位置无关动态库是一个道理,如果虚拟内存运行起来了,pc取址的就是虚拟地址(0 x8048000就是),否者取址的就是实际物理地址,这个实际物理地址就可能会和链接指定的地址(一般给虚拟内存用)不相符合,这一块=在讲uboot时会有详细说明的。b)、修改代码节和数据节中对唯一定义的符号的引用,使得这些引用指向

39、正确的运行时地址重定位相对引用地址重定位绝对应用地址重定位依赖于重定位条目,指令重定位条目在.rel.text中,数据重定位条目在.rel.data中ls -al a 查看文件大小-rw-rw-r-. 1 linux linux 1096 Mar 11 18:58 a.o /红色字体是文件的大小-rwxrwxr-x. 1 linux linux 4848 Mar 11 20:20 afile a /查看文件的类型/ELF格式 32位linux standard base 可重定位文件,用于x86平台,版本1,动态链接库,centos 用到的linux版本号,未瘦身(包含各类符号表)a: ELF

40、 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not strippeda.o 变为a.s后,变化如下:a)、a的大小4848,a.o大小1096,那是因为加入了动态库的连接信息在里面和增加了其它的节b)、都是ELF格式,但是a是ELF格式的可执行目标文件,并且连接了库?ELFAAABCAPDH4?ELFAAABCAPDH4G A9r_$USd$DHtRDHCud$DUSDQlYCABhello a = %d,

41、i = %d 2 AC; C,TAzRA|HALDDA 。EANHBBMEALDD(ZANHBBMECEDCBPAAALDDP hDAPLDHMDHoDHEDHFDH a也是无法读懂的二进制文件,反汇编 objdump -D a u_a_a.s 2 a: file format elf32-i386 2 a: file format elf32-i386 5 Disassembly of section .interp: 6 7 08048134 : 8 8048134: 2f das 9 8048135: 6c insb (%dx),%es:(%edi) 10 8048136: 69 62

42、2f 6c 64 2d 6c imul $0 x6c2d646c,0 x2f(%edx),%esp。90 Disassembly of section .init:191 192 08048294 :193 8048294: 55 push %ebp194 8048295: 89 e5 mov %esp,%ebp。 Disassembly of section .plt:212 213 080482c4 :214 80482c4: ff 35 88 96 04 08 pushl 0 x8049688215 80482ca: ff 25 8c 96 04 08 jmp *0 x804968c21

43、6 80482d0: 00 00 add %al,(%eax)。 234 Disassembly of section .text:235 236 08048310 :237 8048310: 31 ed xor %ebp,%ebp238 8048312: 5e pop %esi239 8048313: 89 e1 mov %esp,%ecx。Disassembly of section .rodata:426 427 080484d8 :428 80484d8: 03 00 add (%eax),%eax433 80484de: 02 00 add (%eax),%al。与.o的反汇编文件基

44、本类似,但是却有了如下的不同:被重定位后的地址不再是00000000开始,而是从08044000开始,但是有些同学可能会说是从08048134开始的,那是因为08044000与08048134还有部分启动代码没看见,所有的程序都是从这一地址卡是运行的2、多了.init等的其它节,后面会说这个很重要,因为它决定了是否能够被加载器加载到我们的虚拟内存中运行可执行文件的ELF格式我们知道了a.o的ELF格式,当a.o被连接后会生成新的一个ELF格式的可执行文件,其格式没有太大变化,段名节头部表.strtab.line.debug.symtab.bss.data.rodata.text.init段头部表ELF头这些信息不回加到虚拟内存(进程空间运行)这些信息不回加到虚拟内存(进程空间运行)数据段数据段能够使程序被加载到内存中运行能够使程序被加载到内存中运行代码段代码段决定了到虚拟内存的映射关系,这样我们就能够根据它访问到各段和节决定了到虚拟内存的映射关系,这样我们就能够根据它访问到各段和节上面多了蓝色部分,另外少两个节,主要目的是为了将这个可执行文件

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论