深入理解计算机系统学习笔记

本文详细探讨了计算机编程中的算术和逻辑操作,包括leaq指令的特性和用法,以及一元、二元操作和移位操作。文章还介绍了控制结构,如条件码、跳转指令及其在C语言和机器代码中的应用,以及条件分支的不同实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.算术和逻辑操作

下图是一些整数和逻辑操作

这些操作被分为四组:加载有效地址、一元操作、二元操作和移位。二元操作有两个操作数,而一元操作有一个操作数。

1.1加载有效地址

加载有效地址(load effective address)指令 leaq 实际上是 movq 指令的变形。它的指令形式是从内存读数据到寄存器,但实际上它根本就没有引用内存。它的第一个操作数看 上去是一个内存引用,但该指令并不是从指定的位置读人数据,而是将有效地址写人到目的操作数。

为了说明leaq在编译出的代码中的使用,使用下面示例说明

long scale(long x, long y, long z){

long t = x + 4 * y + 12 *z;

return t; }

编译时,该函数的算术运算以三条leaq指令实现,

long scale(long x, long y, long z)

x in %rdi, y in %rsi, z in %rdx

scale:

leaq (%rdi,%rsi,4), %rax 

leaq  (%rdx,%rdx,2), %rdx

leaq (%rd%rax,x,4), %rax

ret

这三条指令代表的含义是:

x+4y

z+ 2z

x+4y +12z

leaq指令能执行加法和有限形式的乘法,在编译如上简单的算术表达式时,是很有用处的。

1.2 —元和二元操作

第二组中的操作是一元操作,只有一个操作数,既是源又是目的。

这个操作数可以是一个寄存器,也可以是一个内存位置。如果操作数是寄存器,那么指令会直接操作这个寄存器中的值。如果操作数是内存位置,那么指令会从内存中加载数据到寄存器中,然后执行操作,并将结果写回到同一个内存位置中。

比如说,指令incq(%rsp)会使栈顶的8字节元素加1。这种语法让人想起C语言中的加1运算符(++)和减1运算符(--)。

第三组是二元操作,其中,第二个操作数既是源又是目的。这种语法让人想起C语言中的赋值运算符,例如x-=y。

源操作数是第一个,目的操作数是第二个。例如,指令subq %rax,%rdx 使寄存器%rdx的值减去%rax中的值。

第一个操作数可以是立即数、寄存器或是内存位置。

第二个操作数可以是寄存器或是内存位置。

注意, 当第二个操作数为内存地址时,处理器必须从内存读出值,执行操作,再把结果写回内存。

1.3 移位操作

最后一组是移位操作,先给出移位量,然后第二项给出的是要移位的数。可以进行算术和逻辑右移。

移位量可以是一个立即数,或者放在单字节寄存器%c1中。

示例:salq $4, %rax

将 %rax 中的值左移 4 位

1.4特殊的算术操作

下图描述的是支持产生两个64位数字的全128位乘积以及整数除法的指令。

2.1控制

到目前为止,我们只考虑了直线代码的行为,也就是指令一条接着一条顺序地执行。

c语言中的某些结构,比如条件语句、循环语句和分支语句,要求有条件的执行,根据数据测k的结果来决定操作执行的顺序。机器代码提供两种基本的低级机制来实现有条件的行为:测试数据值,然后根据测试的结果来改变控制流或者数据流。

通过使用jump指令可以改变一组机器代码指令的执行顺序,jump指令指定控制应该被传递到程序的某个其他部分,可能是依赖于某个测试的结果。编译器必须产生构建在这种低级机制基础之上的指令序列,来实现C语言的控制结构。

3.6.1 条件码

除了整数寄存器,CPU还维护着一组单个位的条件码(condition code)寄存器,它们描述了最近的算术或逻辑操作的属性。可以检测这些寄存器来执行条件分支指令。

最常用 的条件码有:

CF:进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。

ZF:零标志。最近的操作得出的结果为0。

SF:符号标志。最近的操作得到的结果为负数。

OF:溢出标志。最近的操作导致一个补码溢出一正溢出或负溢出。

leaq 指令不改变任何条件码,因为它是用来进行地址计算的。。对于逻辑操作,例如XOR,进位标志和溢出标志会设 置成0。对于移位操作,进位标志将设置为最后一个被移出的位,而溢出标志设置为0。

2.2 访问条件码

条件码通常不会直接读取,常用的使用方法有三种:

1)可以根据条件码的某种组合, 将一个字节设置为0或者1,2)可以条件跳转到程序的某个其他的部分,3)可以有条件地 传送数据。

set指令

一条SET指令的目的操作数是低位单字节寄存器元素(图3-2)之一,或是一个字节的内存位置,指令会将这个字节设置成0或者1。

2..3 跳转指令

正常执行的情况下,指令按照它们出现的顺序一条一条地执行。跳转(jump)指令会导 致执行切换到程序中一个全新的位置。

示例:

jmp .LI

movq (%rax) ,%rdx

.LI:

指令jmp .LI会导致程序跳过movq指令,而从.LI:指令后面开始执行。

jmp指令是无条件跳转。它可以是直接跳转,即跳转目标是作为指令的一部分编码的;也可以是间接跳转,即跳转目标是从寄存器或内存位置中读出的。

2.4 跳转指令的编码

跳转指令有几种不同的编码,但是最常用都是PC相对的(PC-relative)。也就是,它们会将目标指令 的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。这些地址偏移量可以编 码为1、2或4个字节。

第二种编码方法是给出 “绝对” 地址,用4个字节直接指定目标。 汇编器和链接器会选择适当的跳转目的编码

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

将条件表达式和语句从C语言翻译成机器代码,最常用的方式是结合有条件和无条件跳转。

汇编代码层面的条件控制类似于 c 语言的 goto 语句。汇编语言使用条件码和条件跳转来起到和 c 语言中 if 相似的作用。

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

实现条件操作的传统方法是通过使用控制的条件转移。这种机制简单而通用,但是在现代 处理器上,它可能会非常低效。一种替代的策略是使用数据的条件转移。这种方法计算一个条件操作的两种结果,然后再根据条件是否满足从中选取一个。只有在一些受限制的情况中,这种策略才可行,但是如果可行,就可以用一条简单的条件传送指令来实现它,条件传送指令更符合现代处理器的性能特性。

### 关于《深入理解计算机系统》的学习笔记 #### 书籍概述 《深入理解计算机系统》是一本全面介绍计算机硬件和软件如何协同工作的教材。通过阅读此书并完成配套实验,读者能够获得对底层计算系统的深刻认识[^1]。 #### 学习进度规划 建议按照每周一章的速度推进学习进程,在假期之前尽可能多地掌握书中内容。这样的节奏既不会过于紧张也能保证足够的消化时间。 #### 实验环节的重要性 除了理论部分,《深入理解计算机系统》还配有九个实验室项目(Lab)。这些实践练习对于巩固所学概念至关重要,因为动手操作可以帮助更好地理解和记忆抽象的知识点。 #### 编译过程解析 当涉及到具体技术细节时,比如编译流程,《深入理解计算机系统》会讲解到像GCC这样的C语言编译器是如何工作以及其生成汇编代码的过程。汇编代码作为机器码的文字表述形式起到了连接高级编程语言与实际执行指令之间的桥梁作用[^2]。 #### 汇编语言的作用 在编译过程中有一个重要步骤是由编译器将预处理后的源文件转换成汇编语言文件。这个阶段产生的`.s`文件包含了对应于原始程序的一系列精确描述低级别机器命令的语句。由于多种不同的高级语言编译器都可以产出相同的汇编语法格式,因此这一步骤具有重要的意义[^3]。 ```c // 示例:简单的 C 函数及其对应的汇编代码片段 int add(int a, int b){ return a + b; } ``` ```assembly _add: leal (%rdi,%rsi), %eax ret ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值