吾读 - 《深入理解计算机系统》第三章 程序的机器级表示 (二) 跳转和循环

上一篇我们初步认识了寄存器,学会了几个简单的汇编指令,例如mov,以及几种寻址模式。寻址模式不仅在mov指令中有用,各种指令都是通过这种方式来读取或写入内存中的值。

一个程序有各种函数,一个函数中也可能有复杂的结构,判断、循环等等,这些东西在汇编中又是什么样的呢?if-else, for, while, switch这些常见的结构会被翻译成怎样的汇编代码呢?

3.5 算术和逻辑操作

本节要接触多更多汇编操作指令,主要以算术及逻辑操作为主,分为四类,参见下图:

在这里插入图片描述

加减乘,没有除,这是为什么呢?因为除法比较特殊,需要同时操作两个寄存器,属于特殊操作指令

3.5.1 加载有效地址 lea

lea即 Load Effective Address,独成一类。该指令实际是mov的变形,指令形式是从存储器读数据到寄存器,但实际上并不会访问存储器,而只是将地址存储到目标寄存器。如同C语言中的&S结果。

3.5.2 一元和二元操作

第二类为一元操作,一元操作即只有一个操作数,即使源也是目标。如图3.7中的 Inc dec neg not指令。

第三类为二元操作,有两个操作数,且第二个操作数既作为源也作为目标。 如同C中的 x += y 中的x既作为源,又作为目标。与mov同样的,两个操作数不可以同时为存储器位置。

3.5.3 移位操作

第四类移位操作。操作数k取值范围为0到31,可以是立即数,或者存放在单字节寄存器中(即前四个寄存器的地位中)。两个左移是一样的,都是右边填充0 。右移则区分算术右移和逻辑右移。

所以左移也有两个指令是强迫症保持对称吗?

常数的乘法常常会优化为加法和移位的组合,当然对于无法拆分的则只能直接使用imul指令。例如x*48 可以拆解为两条指令 x*=3;x<<4x*3又可以使用 lea (%eax, %eax, 2), %edx 来实现

利用寻址方式来实现一些固定的乘法。由于寻址模式里面的s只能取值1 2 4 8,所以该方式就只能实现一些特定的乘法, 例如3x, 5x, 9x等。

3.5.5 特殊的算术操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k0ziunaP-1599574682773)(C3_特殊算术操作.png)]

上图的imull和mull常规来说是需要两个操作符的,但是这里是但操作符。当他们为单操作符的时候,就是计算64位的乘法。此法要求另一个操作数要提前存储在%eax中。乘法的结果高位存在%edx中,地位存储在%eax中组合成一个64位的数字。

目前为止%eax有三个特殊用法了:

  • 整数型返回值,需要放入到%eax中
  • imull和mull的单操作数模式,使用%eax中数据作为乘数,结果的低位也存储到%eax中
  • idivl和divl被除数的低位在%eax中。

3.6 控制

程序执行的一个很重要的部分就是控制执行的顺序,像条件分支,循环,switch等等。汇编代码中基本上就只有个跳转,相当于C中的goto。所以后面将可以看到一些实例C代码的汇编,同其goto实现版本基本是一致的。

学C++的时候都说goto不好,建议不要用,是因为程序员容易用的不好?主要是容易滥用导致控制流混乱。结构良好的goto,可以很好的统一在函数结尾释放资源、处理失败情况等。

3.6.1 条件码

CPU的四个条件码寄存器:

  • CF:进位标志。最近的操作使最高位产生了进位。用于无符号数溢出
  • ZF:零标志。最近的操作结果是0 。
  • SF:符号标志。 是否为负数。
  • OF:溢出标志。最近的操作导致二进制补码溢出

例如C代码 t = a + b, 该指令操作完成后就会设置以上的四个标志位。其中:

  • CF:(unsigned t) < (unsigned a)
  • ZF:t == 0
  • SF:t < 0 负数
  • OF:(a < 0 == b < 0) && (t < 0 != a < 0)

leal指令不会改变条件码,因为它只操作地址。对于逻辑操作,xorl (异或)进位标志和溢出标志都设置成0,移位操作则进位标志设置为最后一个被移除的位,溢出标志则为0 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rzYvQ2Ju-1599574682774)(C3_比较.png)]

cmp和test只修改条件码,不修改其他寄存器。cmp和test的区别为:cmp是比较两个参数的差,test是两个参数的与

比如cmp a,b 如果a和b相等,则有a-b == 0,所以ZF为0。所以ZF可以用来确定两个数是否相等。

通过几个条件码的组合,就能对两个数的各种情况作出明确的判断了。条件码又怎么写入到通用寄存器中呢?

3.6.2 访问条件码

条件码只有一个字节,所以它只能写入到8个单字节的寄存器中。而前面提过的movzbl,movsbl则可以将低位扩展

cmp1 %eax,%edx     
setl %al           读取条件码写入到al中
movzb1 %al,%eax    扩展到整个寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HD4QHS5o-1599574682775)(C3_set指令.png)]

注意小于是setl, l 是 less的缩写,不是large的缩写。g则是greate的缩写。e是equls,n当然是not啦。a估计是above,b则就是below。

这么些逻辑算术看的人头大,直接死背或者用到的时候在查表还好点。

C语言的判断表达式中 && 与 & 有区别吗?例如 if ( expa && expb) 和 if (expa & expb)?
区别是 &&有短路属性,即表达式expa如果为真,则不会计算expb,而&没有这个属性,需要完整计算。

3.6.3 跳转指令编码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOhFl4hx-1599574682776)(C3_jump.png)]

跟前面set的后缀完全一致,就是set换成j 。jmp完整指令则是不判断条件。其他指令则是在满足条件的情况下跳转。这里的Label也如同C语言中Goto的标签一样。

jmp *Operand指令则是跳转到寄存器或者内存中的某个地址去。 例如 jmp *%eax, jmp *(eax) 寻址方式则是与mov等指令一致。

跳转指令的常见做法是:目标地址相对PC(指令计数器)的。也就是是比如当前的PC是 0x123, 则想要调到0x126地址去,编码会是jmp 0x3

一般来说PC的值是当前指令的下一条指令的地址,而不是当前指令的地址,这是因为处理器会先将PC更新,然后才开始执行指令。

汇编代码中可能会有.p2align 4,,7类似的指令,这是条汇编器的命令,它会使后面的指令地址从16的倍数开始,而最多浪费7个字节。这有什么好处呢?它能够让处理器更优化地使用指令高速缓存存储器

3.6.4 翻译条件转移
   if (test-expr)
        then-statement
    else
        else-statement
以上语句翻译成goto版本为:
    t = test-expr
    if (t)
        goto True;
    else-statement;
    goto Dne;
True:
	then-statement
Done:
	...

汇编语言正是以goto版本来翻译if语句的。

为什么用goto,我想是因为汇编及底层只有顺序和跳转两个方式。就是说只有goto这种方式,高级语言的控制结构必须转成想应的goto结构。

3.6.5 循环

for、while和do-while循环,一般在编译成汇编的过程中,都会转换成do-while的循环结构。do-while 循环结构有下面的形式:

do
	body-statement
	while(test-exp)
这很容易翻译成汇编代码的结构如下:

loop:
	body-statement
	t = test-exp
	if (t)
		goto loop

while循环如何翻译成上面的形式?

while (test-exp)
	body-statement
可以翻译成:
    t = test-exp;
    if (!t)
        goto done;
loop:
	body-statement
	t = test-exp
	if (t)
		goto loop;
done:

这里提到一个小技巧:例如上面的

t = test-exp
if (t)
	goto loop;

看起来有三句,实际上汇编指令可能就2句,比如

decl %eax     
jre loop

第一句对t操作之后,立刻进行对t进行判断,不需要额外操作,因为此时条件码恰好是t这个操作相关的。所以可以节省一条判断t的指令。

for循环的格式翻译如下

for (init-expr;test-expr;update-expr)
	body-statement;
翻译成goto方式如下:
    init-expr;
    t = test-expr;
    if (!t)
        goto done;
loop:
	body-statement;
	update-expr;
	t = test-expr;
	if (t)
		goto loop;
done:
相比前面的while 只是多了init-expr和update-expr。

各种循环最终都是转变成了goto模式。这并不是实际开发中值得借鉴的方式,使用goto很显然让代码更难阅读了。

3.6.6 switch语句

早就听说switch比一堆if要快,为什么快,怎么个快法?是不是任何情况都快?这下要揭晓了。

GCC根据开关情况的数量和开关情况值的稀少程度来翻译开关语句。当开关情况数量比较多,并且值的范围跨度比较小时,就会使用跳转表跳转表可以使得跳转时间与开关数量无关。

这么说跳转表来类似一个map,直接索引到目标,多个if-else则像是vector在遍历。

这里也说到了使用跳转表是有条件的,并不是switch必然会使用。在不使用调整表的情况下,两者的汇编代码其实是一致的。所以以后不能无脑说switch比if快了,得有理有据。

CC根据开关情况的数量和开关情况值的稀少程度来翻译开关语句。当开关情况数量比较多,并且值的范围跨度比较小时,就会使用跳转表跳转表可以使得跳转时间与开关数量无关。

这么说跳转表来类似一个map,直接索引到目标,多个if-else则像是vector在遍历。

这里也说到了使用跳转表是有条件的,并不是switch必然会使用。在不使用调整表的情况下,两者的汇编代码其实是一致的。所以以后不能无脑说switch比if快了,得有理有据。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机应用基础 1 计算机应用基础第02章--Windows7应用全文共37页,当前为第1页。 第2章 Windows 7应用 2023/5/31 2 计算机应用基础第02章--Windows7应用全文共37页,当前为第2页。 任务描述 小明以前都是进网吧玩电脑,多是与同学及朋友进行QQ聊天、打网络游戏、看网络视频,也下载喜欢的歌曲。现在进入大学,父母奖励了他一台新的电脑,高兴之余,发现对电脑了解很少,希望能对计算机操作系统有一个简单的全面了解,能够充分利用计算机上的各种功能,管理好自己的电脑。 3 计算机应用基础第02章--Windows7应用全文共37页,当前为第3页。 任务分解 熟悉Windows 7工作界面。 掌握窗口与对话框的相关操作。 掌握文件和文件夹的管理方法。 学习控制面板的相关知识,对计算机进行个性化的设置。 学习系统自带的小程序,以便解决学习、生活中的常见问题。 4 计算机应用基础第02章--Windows7应用全文共37页,当前为第4页。 完成任务 1 Windows 7的启动与退出 2 Windows 7的桌面 3 Windows 7的窗口与对话框 4 Windows 7的文件与文件夹管理 5 控制面板与系统设置 6 附件 7 知识拓展 5 计算机应用基础第02章--Windows7应用全文共37页,当前为第5页。 1 Windows 7的启动与退出 启动 退出 进入睡眠与重新启动 睡眠和休眠 6 "开始"按钮 死机时如何处理? 计算机应用基础第02章--Windows7应用全文共37页,当前为第6页。 2 Windows 7的桌面 桌面图标 7 系统图标 快捷图标 计算机应用基础第02章--Windows7应用全文共37页,当前为第7页。 2 Windows 7的桌面 桌面图标 常用系统图标: "计算机" "回收站":还原、清空 8 图2.3 "回收站"窗口 计算机应用基础第02章--Windows7应用全文共37页,当前为第8页。 2 Windows 7的桌面 桌面图标 快捷图标:应用程序或窗口的快捷启动方式。 创建快捷图标 9 图2.4 为"作业"文件夹创建桌面快捷方式 计算机应用基础第02章--Windows7应用全文共37页,当前为第9页。 2 Windows 7的桌面 桌面背景 任务栏 将程序锁定到任务栏 程序未运行 程序已运行 将程序从任务栏解锁 10 通知区域 语言栏 "显示桌面"按钮 "开始"按钮 图2.5 任务栏 计算机应用基础第02章--Windows7应用全文共37页,当前为第10页。 2 Windows 7的桌面 "开始"菜单 跳转列表:指最近使用的项目的列表,如文件、文件夹或网站等,该列表按程序分组显示。 11 图2.10从任务栏查看跳转列表 图2.11从"开始"菜单查看跳转列表 计算机应用基础第02章--Windows7应用全文共37页,当前为第11页。 3 Windows 7的窗口与对话框 打开窗口 窗口的组成 移动窗口 12 标题栏 地址栏 搜索栏 菜单栏 导航窗格 窗口工作区 工具栏 状态栏 图2.12"计算机"窗口 计算机应用基础第02章--Windows7应用全文共37页,当前为第12页。 3 Windows 7的窗口与对话框 排列窗口 自动排列窗口 使用"对齐"排列窗口 并排 垂直 最大化窗口 13 层叠 堆叠 并排 计算机应用基础第02章--Windows7应用全文共37页,当前为第13页。 3 Windows 7的窗口与对话框 循环切换窗口 Alt+Tab 三维堆栈排列窗口:Windows 徽标键+Tab 关闭窗口 14 计算机应用基础第02章--Windows7应用全文共37页,当前为第14页。 3 Windows 7的窗口与对话 对话框:对话框是特殊类型的窗口,可以提出问题,允许选择选项来执行任务,或者提供信息。 多数对话框只可以移动,而无法最大化、最小化或调整大 15 计算机应用基础第02章--Windows7应用全文共37页,当前为第15页。 4 Windows 7的文件与文件夹管理 文件与文件夹 文件:保存在计算机中的各种信息和数据都被统称为文件,如一张图片、一份办公文档、一个应用、一首歌曲、一部电影等。 文件名 文件图标 文件描述信息 文件夹:可以看作是存储文件的容器。文件夹还可以存储其他文件夹。文件夹中包含的文件夹通常称为"子文件夹"。 16 计算机应用基础第02章--Windows7应用全文共37页,当前为第16页。 4 Windows 7的文件与文件夹管理 文件与文件夹的操作 文件与文件夹显示方式 新建文件与文件夹 使用"文件"菜单 使用快捷菜单 选择文件与文件夹 17 选定对象 操作 单个对象 单击所要选定的对象 多个连续的对象 鼠标操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值