深入理解计算机系统03——程序的机器级表示

目录

系列文章目录

一、程序编码

1.机器级别代码

2.不同级别的优化

3.数据格式

4.访问信息

4.1 操作数指示符

4.2 操作数示例 

4.3 代码中的操作数

4.4 数据传输指令 

4.5 数据传输扩展示例

4.6 数据传输扩展重要示例

4.7 数据传输在C与汇编间的转换

4.8 压入弹出栈数据

5.算数与逻辑操作

5.1 加载有效地址

5.2 一元操作与二元操作

5.3 移位操作

5.4 算数运算函数转换示例

5.5 特殊算数操作

5.6 特殊算数操作转换示例

6.控制

6.1 条件码

6.2 访问条件码

6.3 跳转指令

6.4 跳转指令的编码 

6.5 跳转指令反汇编示例 

6.6 用条件控制来实现条件分支 

6.7 条件控制示例

6.8  用条件传送来实现条件分支

6.9 条件传送示例

6.10 循环

6.11 switch

7.过程

7.1 运行时栈

7.2 数据传送

7.3 栈上的局部管理

7.4 局部管理重要案例

7.5 寄存器中的局部存储空间

7.6 递归过程

8.数组

8.1 数组示例

8.2 嵌套数组(多维数组)

8.3 多级数组(指针数组)

8.4 变长数组

8.5 嵌套数组示例

9.异质的数据结构

9.1 结构(体)

9.2 结构体示例

9.3 联合(体) 

9.4 数据对齐

10.结合控制和数据

10.1 理解指针

10.2 内存越界引用与缓冲区溢出

10.3 缓冲区溢出示例

10.4 对抗缓冲区攻击

总结


系列文章目录

本系列博客重点在深圳大学计算机系统(2)课程的核心内容梳理,参考书目《深入理解计算机系统》(有问题欢迎在评论区讨论指出,或直接私信联系我)。

第一章 深入理解计算机系统01——计算机系统漫游_@李忆如的博客-CSDN博客

第二章 深入理解计算机系统02——信息的表示与处理_@李忆如的博客-CSDN博客

第三章 深入理解计算机系统03——程序的机器级表示


梗概

本篇博客主要介绍深入计算机系统书目第三章程序的机器级表示的相关知识。


一、程序编码

1.机器级别代码

深入理解计算机系统03——程序的机器级表示_第1张图片

2.不同级别的优化

深入理解计算机系统03——程序的机器级表示_第2张图片

3.数据格式

Tips:注意后缀(b、w、l、q对应8、16、32、64位)!!! 

深入理解计算机系统03——程序的机器级表示_第3张图片

4.访问信息

从左至右分别为64(r开头)、32(e开头)、16、8位(l结尾)大的包括小的 非所有

ra(b)x    ea(b)x   a(b)x    a(b)l 有规律寄存器须记住。

深入理解计算机系统03——程序的机器级表示_第4张图片

寄存器中,1、2字节赋值,剩余字节不变。4字节赋值,高位4字节清零。

Tips:1、2字节赋值为低字节赋值,r8~r15为64位系统新增。 

4.1 操作数指示符

大多数指令有一或多个操作数,指出源数据值与目标地址。

寻址方式:1.立即数($开头(找自己) 无$表示绝对地址(找对应地址值)) 2.寄存器(%开头) 3.内存引用(括号括起来)

Tips:比例因子必须是2的幂。

4.2 操作数示例 

深入理解计算机系统03——程序的机器级表示_第5张图片

4.3 代码中的操作数

一维数组寻址:基址 + 比例寻址(a【n】= a【0】+ i(数据类型所占字节) x n)

二维数组寻址(假设按行存储):基址 + 比例寻址(b【i】【j】 = b【0】【0】+ i * n * m(一行多少个元素) + j * n(数据类型所占字节))

汇编代码示例(注意后缀!!):

4.4 数据传输指令 

深入理解计算机系统03——程序的机器级表示_第6张图片

4.5 数据传输扩展示例

深入理解计算机系统03——程序的机器级表示_第7张图片

深入理解计算机系统03——程序的机器级表示_第8张图片

ebx是专用寄存器,不能直接传值。 

Tips:内存之间不能对拷 即不能movq (%rdi),(%rsi),应该使用中介寄存器,例如:

4.6 数据传输扩展重要示例

深入理解计算机系统03——程序的机器级表示_第9张图片 Tips:选择有符号扩展和无符号扩展取决于原数据的有无符号。

4.7 数据传输在C与汇编间的转换

深入理解计算机系统03——程序的机器级表示_第10张图片

Tips:一般默认函数的第一参数存入rdi寄存器(与位有关 edi、di、dil),第二个参数存入rsi寄存器(esi、si、sil) ,第三个放入rdx寄存器(edx、dx、dl)

深入理解计算机系统03——程序的机器级表示_第11张图片

Tips:注意是取寄存器(数与变量)还是寄存器对应的内存(指针值)。

4.8 压入弹出栈数据

核心原则:先进后出(地址是从栈顶指针递减)

深入理解计算机系统03——程序的机器级表示_第12张图片

压入弹出栈数据知识总结:

1.栈顶指针为%rsp,与mov的位无关,与系统有关。

2.sub(减)为从栈顶指针向下开辟空间并将栈顶指针下移方便mov数据(push操作),add为从栈顶指针向上寻址取出所需栈中元素(pop操作)。

3.push与pop操作均可用bwlq实现不同类型数据的进出。

5.算数与逻辑操作

常见操作如下:

5.1 加载有效地址

深入理解计算机系统03——程序的机器级表示_第13张图片

lea(l和q与计算机系统位数有关)不访问内存,直接将寻址作为值赋给目标地址。

5.2 一元操作与二元操作

一元操作:只有一个操作数,既是源操作数,又是目的操作数。

二元操作:有两个操作数,第一个为源,第二个为目标。

深入理解计算机系统03——程序的机器级表示_第14张图片

Tips:lmulq 为 乘,lncq、decq为+1、-1 

5.3 移位操作

C语言符号:<< 与 >> 加数字表示移动的位数

左移:按位左移并在右端补0

右移

① 逻辑右移(shl/shr):按位右移在往左端补0(对无符号整数使用)

② 算术右移(sal/sar):按位右移在往左端补最高位有效值(对有符号整数使用)

Tips:移位量只能是立即数或%rcx的%cl中!!

移位规则:

深入理解计算机系统03——程序的机器级表示_第15张图片

深入理解计算机系统03——程序的机器级表示_第16张图片

5.4 算数运算函数转换示例

深入理解计算机系统03——程序的机器级表示_第17张图片

深入理解计算机系统03——程序的机器级表示_第18张图片

5.5 特殊算数操作

深入理解计算机系统03——程序的机器级表示_第19张图片

TIps:imull有单操作数和双操作数两种(双操作数的只取低32位),我们可以根据后面的操作数个数作出区别。

5.6 特殊算数操作转换示例

深入理解计算机系统03——程序的机器级表示_第20张图片

深入理解计算机系统03——程序的机器级表示_第21张图片

深入理解计算机系统03——程序的机器级表示_第22张图片

6.控制

除了顺序执行外,还存在着其他方式改变控制与数据流。

6.1 条件码

条件码(condition code)寄存器,其值描述最近的算术或逻辑操作的属性

CF (Carry Flag): 进位标志(无符号数的溢出)
ZF(Zero Flag): 结果为零标志
SF(Sign Flag): 符号标志,结果为负时 SF=1
OF(Overflow Flag): 溢出标志,正溢出或负溢出

深入理解计算机系统03——程序的机器级表示_第23张图片

leaq不会改变条件码,5中常见指令均会设置条件码。

影响标志位的指令总结

1leal/leaq指令是计算地址,不影响标志位

2INC(+1)/DEC(-1)设置OFZF,不设置CF

3、算术和逻辑指令会设置标志位

     逻辑操作,CF=0OF=0

4、移位操作 CF=最后一个移出的位,OF=0

而如下两类指令只设置条件码,不改变其他寄存器:

深入理解计算机系统03——程序的机器级表示_第24张图片 cmp常用于比较两数是否相等,test常用于判断某数的正负或是否非零。

6.2 访问条件码

条件码一般不会直接读取,常用方法如下:

1.利用条件码状态设置某个字节(低位单字节寄存器、一个字节的内存地址)

深入理解计算机系统03——程序的机器级表示_第25张图片Tips:不同的后缀指明了相关条件码的组合

2.有条件地完成跳转

3.有条件地完成数据传送

6.3 跳转指令

标号:  跳转目的地址的标识(label

1.无条件跳转:jmp + 标号直接跳转或jmp + 寄存器或内存目标中读出的的跳转目标(* + 操作数指示符)

深入理解计算机系统03——程序的机器级表示_第26张图片

2.条件跳转:je/jne/js/jns/jg/jge/jl/jle/ja/jae/jb/jbe

跳转目的地址:PC相对跳转、绝对跳转

跳转列表指令如下:

深入理解计算机系统03——程序的机器级表示_第27张图片

Tips:条件跳转只能是直接跳转,后缀与set一一对应。

6.4 跳转指令的编码 

理解跳转指令的目标如何编码,对第七章链接的的研究非常重要。

以下为汇编及反汇编示例:

深入理解计算机系统03——程序的机器级表示_第28张图片

链接后的反汇编版本如下:

深入理解计算机系统03——程序的机器级表示_第29张图片

6.5 跳转指令反汇编示例 

深入理解计算机系统03——程序的机器级表示_第30张图片

6.6 用条件控制来实现条件分支 

GCC编译模板如下:

深入理解计算机系统03——程序的机器级表示_第31张图片

goto版本C语言代码与对应汇编如下:深入理解计算机系统03——程序的机器级表示_第32张图片

6.7 条件控制示例

深入理解计算机系统03——程序的机器级表示_第33张图片

6.8  用条件传送来实现条件分支

条件控制来实现条件分支简单但也低效,数据的条件转移在一些受限的情况下可行,更符合现代处理器特点。

简单例子及其汇编如下:

深入理解计算机系统03——程序的机器级表示_第34张图片

条件跳转指令如下:

深入理解计算机系统03——程序的机器级表示_第35张图片

6.9 条件传送示例

深入理解计算机系统03——程序的机器级表示_第36张图片

6.10 循环

汇编用条件测试与跳转组合实现。

1.do-while循环

模板如下:

深入理解计算机系统03——程序的机器级表示_第37张图片

do-while示例

深入理解计算机系统03——程序的机器级表示_第38张图片

2.while循环

模板如下:

深入理解计算机系统03——程序的机器级表示_第39张图片

while示例(编译方法1)

深入理解计算机系统03——程序的机器级表示_第40张图片

while示例(编译方法2)

深入理解计算机系统03——程序的机器级表示_第41张图片

3.for循环

核心:for转while转goto 

模板如下:

深入理解计算机系统03——程序的机器级表示_第42张图片

for示例代码

深入理解计算机系统03——程序的机器级表示_第43张图片

6.11 switch

switch根据整数索引值实现多重分支。

GCC编译器翻译开关语句(什么时候使用switch)

深入理解计算机系统03——程序的机器级表示_第44张图片

Tips:稀疏程度过大,建表大量存入&&loc_def,浪费空间。 

深入理解计算机系统03——程序的机器级表示_第45张图片

C语言switch程序示例分析

深入理解计算机系统03——程序的机器级表示_第46张图片

switch转换示例

深入理解计算机系统03——程序的机器级表示_第47张图片

Tips:第五行为间接跳转到索引表对饮内存位置(寄存器与变量寄存器一致)。

7.过程

过程调用机制如下:

深入理解计算机系统03——程序的机器级表示_第48张图片

7.1 运行时栈

深入理解计算机系统03——程序的机器级表示_第49张图片

Tips:使用callq进行转移控制,原函数下一步地址压栈,返回原函数后出栈。

深入理解计算机系统03——程序的机器级表示_第50张图片

7.2 数据传送

深入理解计算机系统03——程序的机器级表示_第51张图片

Tips:当函数所需函数大于6个时才需要从栈申请空间,地址随参数增加增大,参数大小向8对齐(每个参数首地址是8的倍数)。

示例如下:

深入理解计算机系统03——程序的机器级表示_第52张图片

Tips:%rsp为栈顶指针,保存了返回地址。

7.3 栈上的局部管理

深入理解计算机系统03——程序的机器级表示_第53张图片

深入理解计算机系统03——程序的机器级表示_第54张图片

Tips:call后会自动向下开空间存返回地址,sub(开空间)一定要add(删除)回来。

7.4 局部管理重要案例

深入理解计算机系统03——程序的机器级表示_第55张图片

Tips:局部变量起始地址和类型对齐。 

7.5 寄存器中的局部存储空间

为了保证程序的正确性(防止值的覆盖),对于某些值需要在过程中保存(也需要开空间)。

深入理解计算机系统03——程序的机器级表示_第56张图片

Tips:函数返回值一般保存在%rax。

7.6 递归过程

深入理解计算机系统03——程序的机器级表示_第57张图片

Tips:同样注意值的保存,防止覆盖。

8.数组

数组占用L(数据类型对应字节)*N(个数)的连续内存(虚拟内存)。

深入理解计算机系统03——程序的机器级表示_第58张图片

数组的基本原则如下:

深入理解计算机系统03——程序的机器级表示_第59张图片

Tips:注意是算地址还是算值。

8.1 数组示例

深入理解计算机系统03——程序的机器级表示_第60张图片

Tips:注意最后一题为求第几个元素,而不是地址差。

8.2 嵌套数组(多维数组)

深入理解计算机系统03——程序的机器级表示_第61张图片

Tips:数组内存为连续的。

8.3 多级数组(指针数组)

深入理解计算机系统03——程序的机器级表示_第62张图片

Tips:指针的地址连续(每个指针占8字节),值为数组首地址。

8.4 变长数组

深入理解计算机系统03——程序的机器级表示_第63张图片

8.5 嵌套数组示例

深入理解计算机系统03——程序的机器级表示_第64张图片

9.异质的数据结构

9.1 结构(体)

深入理解计算机系统03——程序的机器级表示_第65张图片

9.2 结构体示例

深入理解计算机系统03——程序的机器级表示_第66张图片

深入理解计算机系统03——程序的机器级表示_第67张图片

Tips:分配空间时一定要注意对齐,局部变量对齐数据类型所占字节,如上图。

9.3 联合(体) 

深入理解计算机系统03——程序的机器级表示_第68张图片

Tips:注意大小端对数据对齐的影响。

深入理解计算机系统03——程序的机器级表示_第69张图片

9.4 数据对齐

深入理解计算机系统03——程序的机器级表示_第70张图片

Tips:可以设置不对齐,但是需要以时间换取空间。

深入理解计算机系统03——程序的机器级表示_第71张图片

Tips:结构体定义中空间与数据类型顺序有关(大数据类型先定义,节省空间)

10.结合控制和数据

10.1 理解指针

深入理解计算机系统03——程序的机器级表示_第72张图片

Tips:指针定义都会自动分配8个字节存本身。上图A2未初始化,所以读取A2【0】会出错。

深入理解计算机系统03——程序的机器级表示_第73张图片

10.2 内存越界引用与缓冲区溢出

x86-64 linux内存布局如下:

深入理解计算机系统03——程序的机器级表示_第74张图片

缓冲区溢出(越界访问了原本已使用的空间)示例如下:

深入理解计算机系统03——程序的机器级表示_第75张图片

深入理解计算机系统03——程序的机器级表示_第76张图片

缓冲区溢出定义如下:

深入理解计算机系统03——程序的机器级表示_第77张图片

Tips:部分库函数也存在缓冲区溢出可能(gets、scanf、strcpy、strcat等等)。

10.3 缓冲区溢出示例

深入理解计算机系统03——程序的机器级表示_第78张图片

反汇编观察汇编代码可以调查错误原因(字符串默认加‘\0’)

深入理解计算机系统03——程序的机器级表示_第79张图片

Tips:缓冲区溢出是否报错与数组位并无直接关系,与开辟栈空间(subq)的大小有关(覆盖返回地址才有可能报错)!!! 

Tips:由于缓冲区溢出可能改变返回地址,故可以在栈空间内注入攻击代码完成黑客攻击。

攻击示例如下:

深入理解计算机系统03——程序的机器级表示_第80张图片

代码解读:要完成简单的缓冲区攻击,需要将buf的首地址覆盖原返回地址,并在buf有效位数中填入攻击内容(填充区可放入除‘EOF’与‘\n’外其他字符,gets会结束)

如本程序中将buf定义为全0,将buf地址覆盖原gets返回地址,使gets每次返回都是0。

10.4 对抗缓冲区攻击

对抗缓冲区攻击有三大方面

1.避免溢出漏洞(eg.避免使用有漏洞的(库)函数)

2.采用系统级保护

2.1 随机叠加偏移

深入理解计算机系统03——程序的机器级表示_第81张图片

2.2 划分权限

深入理解计算机系统03——程序的机器级表示_第82张图片

缺点:失去部分程序灵活性。

3.编译器使用“栈金丝雀”(哨兵)

核心:在栈空间中分配一个特定值(哨兵),在回调前检查哨兵值是否改变,若改变则报错。

GCC实施:-fstack-protector

金丝雀使用实例

深入理解计算机系统03——程序的机器级表示_第83张图片

Tips:金丝雀能报的错有限,只溢出部分缓冲区(未涉及金丝雀位置)不会报错。 

总结

以上便是《深入理解计算机系统》第三章——程序的机器级表示的核心知识。在第三章为计算机系统(2)中的重要内容,主要介绍了程序的各种数据格式、C与汇编的各种转换、各种不同结构的汇编表示,以及程序运行的过程、控制与风险。

你可能感兴趣的