文章目录
- 能看懂基本的汇编程序而不要求会写汇编程序
- 一、最简单的汇编程序
- 1.代码:结果相当于在C程序的 main 函数中 return 4
- (1)如何运行汇编程序?
- (2)链接的作用:地址重定位,多文件合并成一个可执行文件
- (3)Shell中可以用特殊变量 $? 得到上一条命令的退出状态
- (4)分析汇编程序
- (h)int $0x80
- CPU处于用户模式是不能调用内核函数的
- 2.x86汇编的两种语法:intel语法和AT&T语法
- 3.习题
- 二、x86上重要的寄存器
- 1.x86通用寄存器:eab,ebx等
- 2.x86特殊寄存器:eip等
- 三、第二个汇编程序
- 1.求一组数的最大值的汇编程序
- (1)汇编程序的运行
- (2).section .data段
- (3)edi、ebx、eax寄存器的作用
- (4)movl指令
- (5)循环start_loop、比较cmpl、条件je指令
- (6)比较cmpl、条件jle指令
- 四、x86的常用寻址方式
- 1.内存寻址的通用格式
- 2.常用的寻址方式
- 五、ELF文件——以第二个汇编程序为基础
- 1.UNIX系统的可执行文件都采用ELF格式,类型有三种
- 2.汇编程序的汇编、链接、运行过程如下
- 3.图示ELF文件
- (1)从链接器的角度看ELF文件
- (2)从加载器的角度看ELF文件
- (3)目标文件、可执行文件、共享库与section header table,program header table的关系
- 4.目标文件的符号表(XXX.o文件)
- (1)读目标文件:readelf -a xxx.o
- (a).txt段的作用
- (2)打印目标文件的字节:hexdump -C xxx.o
- (a)C语言全局变量属于.bss段
- (b).bss段和.data段的区别
- (3)机器指令反汇编来分析.txt段:objdump -d xxx.o
- 5.可执行文件的符号表:XXX
- (1)读可执行文件:readelf -a xxx
- (d)文件和加载地址的对应关系
- (2)机器指令反汇编来分析.txt段:objdump -d xxx
能看懂基本的汇编程序而不要求会写汇编程序
一、最简单的汇编程序
1.代码:结果相当于在C程序的 main 函数中 return 4
(1)如何运行汇编程序?
(2)链接的作用:地址重定位,多文件合并成一个可执行文件
(3)Shell中可以用特殊变量 $? 得到上一条命令的退出状态
现在执行这个程序,它只做了一件事就是退出,退出状态是4
(4)分析汇编程序
(a)首先, # 号表示单行注释;
(b)伪操作
汇编程序中以 . 开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为汇编指示(Assembler Directive) 或伪操作(Pseudo-operation) ,由于它不是真正的指令所以加个“伪”字。
(c).section .data
.section 指示把代码划分成若干个段(Section) ,程序被操作系统加载执行时,每个段被加载到不同的地址, 操作系统对不同的页面设置不同的读、写、执行权限。
.data 段保存程序的数据,是可读可写的,相当于C程序的全局变量。
(d).section .text
.text 段保存代码,是只读和可执行的,后面那些指令都属于 .text 段。
(e).globl _start
(f)_start:
(g)movl $1, %eax
(h)int $0x80
CPU处于用户模式是不能调用内核函数的
2.x86汇编的两种语法:intel语法和AT&T语法
UNIX平台的书都采用AT&T语法
3.习题
二、x86上重要的寄存器
1.x86通用寄存器:eab,ebx等
2.x86特殊寄存器:eip等
三、第二个汇编程序
1.求一组数的最大值的汇编程序
(1)汇编程序的运行
(2).section .data段
补充说明:
(a)这组数在 .data 段给出;
(b).long 指示声明一组数,每个数占32位,相当于C语言中的数组;
(c)汇编器会把数组的首地址作为 data_items 符号所代表的地址, data_items 类似于C语言中的数组名; data_items 这个标号没有用 .globl 声明,因为它只在这个汇编程序内部使用,链接器不需要用到这个名字;
(d)除了 .long 之外,常用的数据声明还有:
(3)edi、ebx、eax寄存器的作用
(4)movl指令
(5)循环start_loop、比较cmpl、条件je指令
(6)比较cmpl、条件jle指令
四、x86的常用寻址方式
1.内存寻址的通用格式
2.常用的寻址方式
五、ELF文件——以第二个汇编程序为基础
1.UNIX系统的可执行文件都采用ELF格式,类型有三种
2.汇编程序的汇编、链接、运行过程如下
3.图示ELF文件
注:注意Section Header Table和Program Header Table并不是一定要位于文件的开头和结尾,其位置由ELF Header指出,上图这么画只是为了清晰。
(1)从链接器的角度看ELF文件
(2)从加载器的角度看ELF文件
(a)右边是从加载器的视角来看ELF文件,开头是ELF Header,Program Header Table中保存了所有Segment的描述信息,Section Header Table在加载过程中用不到, 所以是可有可无的。
(b)从上图可以看出,一个Segment由一个或多个Section组成。
(c)这些Section加载到内存时具有相同的访问权限。
(d)有些Section只对链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment。
(3)目标文件、可执行文件、共享库与section header table,program header table的关系
4.目标文件的符号表(XXX.o文件)
(1)读目标文件:readelf -a xxx.o
(a)用 readelf 工具读出目标文件 max.o 的ELF Header和Section Header Table。
(b)ELF Header中描述了操作系统是UNIX,体系结构是80386。
(c)文件地址的定义:文件开头第一个字节的地址是0,然后每个字节占一个地址。
补充:
(a)off和size的eg如下
readelf 输出的最后一部分
说明:
(a).txt段的作用
.rel.text 告诉链接器指令中的哪些地方需要做重定位
(b)
(2)打印目标文件的字节:hexdump -C xxx.o
说明:
(a)C语言全局变量属于.bss段
C语言的全局变量如果在代码中没有初始化,就会在程序加载时用0初始化。这种数据属于 .bss 段。
(b).bss段和.data段的区别
- 在加载时, .bss 段和 .data 段一样都是可读可写的数据。
- 但是在ELF文件中 .data 段需要占用一部分空间保存初始值,而 .bss 段则不需要。
-why?
.bss 段在文件中只占一个Section Header而没有对应的Section,程序加载时 .bss 段占多大内存空间在Section Header中描述。
(3)机器指令反汇编来分析.txt段:objdump -d xxx.o
目前所有指令中用到的符号地址都是相对地址, 下一步链接器要修改这些指令,把其中的地址都改成加载时的内存地址,这些指令才能正确执行。
5.可执行文件的符号表:XXX
(1)读可执行文件:readelf -a xxx
(a)相比较于readelf -a 目标文件.o,多了两个Program Header,少了两个Section Header。
(b)在Section Header Table中(就是Section Headerts),bss 段没有用到,所以被删掉了。 .rel.text 段就是用于链接过程的,做完链接就没用了,所以也删掉了。
(c)在Program Header Table中,Flg 列指出第一个Segment的访问权限是可读可执行,第二个Segment的访问权限是可读可写。
(d)文件和加载地址的对应关系
最后一列 Align 的值0x1000(4K) 是x86平台的内存页面大小。在加载时文件也要按内存页面大小分成若干页,文件中的一页对应内存中的一页, 对应关系如下图所示。
(2)机器指令反汇编来分析.txt段:objdump -d xxx
解释说明如下:
(a)指令中的相对地址都改成绝对地址了。
首先看跳转指令, 原来目标文件的指令是这样:
(b)再看内存访问指令,原来目标文件的指令是这样: