- 浏览: 142391 次
文章分类
最新评论
下表是 x86-64 中的一些整数和逻辑操作指令,其中除 leaq 指令外,其他指令类都有各种不同大小操作数的变种(类似于 MOV 类指令,见汇编指令之数据传送指令)。例如,指令类 ADD 由四条加法指令组成:addb、addw、addl 和 addq,分别是字节加法、字加法、双字加法和四字加法。这些操作被分为四组:加载有效地址、一元操作、二元操作和移位。
加载有效地址(load effective address)指令 leaq 实际上是 movq 指令的变形。虽然它的指令形式是从内存读取数据到寄存器,但实际上它根本没有引用内存。它的第一个操作数看上去是一个内存引用,但该指令并不是从指定的位置读入数据,而是将有效地址写入到目的操作数(必须是一个寄存器)。这条指令可以为后面的内存引用产生指针,而且它还可以简洁地描述普通的算术操作。例如,如果寄存器 %rdx 的值为 x,那么指令“leaq 7(%rdx, %rdx, 4), %rax”将把寄存器 %rax 的值设置为 5x+7。
第二组中的操作数是一元操作,只有一个操作数,既是源又是目的。这个操作数可以是一个寄存器,也可以是一个内存位置。比如,指令“incq(%rsp)”会使栈顶的 8 字节元素加 1,类似于 C 语言中的自增运算符。
第三组是二元操作,其中,第二个操作数既是源又是目的。类似于 C 语言中的赋值运算符,如 x-=y。第一个操作数可以是立即数、寄存器或是内存位置,第二个操作数可以是寄存器或是内存位置。当第二个操作数是内存地址时,处理器必须从内存读出值,执行操作,再把结果写回内存。
最后一组是移位操作:先给出移位量,然后第二项给出的是要移位的数。移位量可以是一个立即数,或者放在特定的单字节寄存器 %cl 中。x86-64 中,移位操作对 w 位长的数据值进行操作,移位量是由 %cl 寄存器的低 m 位决定的,这里 2^m=w,高位则会被忽略。例如,当 %cl 寄存器的值为 0xFF 时,指令 salb 会移 7 位,salw 会移 15 位,sall 会移 31 位,而 salq 会移 63 位。移位操作的目的操作数可以是一个寄存器或是一个内存位置。
上面这些都属于常规的算术指令,其实还有一类特殊的算术操作。通常,两个 64 位有符号或无符号整数相乘得到的乘积需要 128 位(16字节,称为八字)来表示,x86-64 指令集对此提供了有限的支持,如下表所示。
注意,这里又出现了一个 imulq 指令,不过它是单操作数的,汇编器能够通过计算操作数的数目来分辨出想用哪条指令。单操作数的 imulq 指令和 mulq 指令分别是计算两个 64 位值的全 128 位乘积,前者计算补码乘法,后者计算无符号数乘法。它们都要求一个参数必须在寄存器 %rax 中,而另一个作为指令的源操作数给出,然后乘积存放在寄存器 %rdx(高 64 位)和 %rax(低 64 位)中。下面这段 C 代码说明了如何从两个无符号 64 位数字 x 和 y 生成 128 位的乘积。
这里的 unsigned __int128 类型是 GCC 提供的 128 位整数支持,改为 uint128_t 类型别名是为了沿用 inttypes.h 中其他数据类型的命名规律。最终的乘积存放在指针 dest 指向的 16 字节处。这段代码对应的汇编代码大致如下(对应的是小端法机器)。
除了 64 位乘法指令,这里还提供了之前的算术表里没有的除法和取模操作。它们也是单操作数的。其中,有符号除法指令 idivq 将寄存器 %rdx(高 64 位)和 %rax(低 64 位)中的 128 位数作为被除数,而将操作数作为除数,最终得出的商存储在寄存器 %rax 中,余数则存储在寄存器 %rdx 中。对于 64 位的被除数,其值应该存放在寄存器 %rax 中,而把 %rdx 的位设置为全 0(无符号运算)或者 %rax 的符号位(有符号运算)。后面这个操作可以用图中的指令 cqto 来完成,该指令不需要操作数,它会隐含读出 %rax 的符号位,并将它复制到 %rdx 的所有位。
下面这个 C 函数说明了 x86-64 是如何实现除法的,它计算了两个 64 位有符号数的商和余数。
该函数对应的汇编代码大致如下。
加载有效地址(load effective address)指令 leaq 实际上是 movq 指令的变形。虽然它的指令形式是从内存读取数据到寄存器,但实际上它根本没有引用内存。它的第一个操作数看上去是一个内存引用,但该指令并不是从指定的位置读入数据,而是将有效地址写入到目的操作数(必须是一个寄存器)。这条指令可以为后面的内存引用产生指针,而且它还可以简洁地描述普通的算术操作。例如,如果寄存器 %rdx 的值为 x,那么指令“leaq 7(%rdx, %rdx, 4), %rax”将把寄存器 %rax 的值设置为 5x+7。
第二组中的操作数是一元操作,只有一个操作数,既是源又是目的。这个操作数可以是一个寄存器,也可以是一个内存位置。比如,指令“incq(%rsp)”会使栈顶的 8 字节元素加 1,类似于 C 语言中的自增运算符。
第三组是二元操作,其中,第二个操作数既是源又是目的。类似于 C 语言中的赋值运算符,如 x-=y。第一个操作数可以是立即数、寄存器或是内存位置,第二个操作数可以是寄存器或是内存位置。当第二个操作数是内存地址时,处理器必须从内存读出值,执行操作,再把结果写回内存。
最后一组是移位操作:先给出移位量,然后第二项给出的是要移位的数。移位量可以是一个立即数,或者放在特定的单字节寄存器 %cl 中。x86-64 中,移位操作对 w 位长的数据值进行操作,移位量是由 %cl 寄存器的低 m 位决定的,这里 2^m=w,高位则会被忽略。例如,当 %cl 寄存器的值为 0xFF 时,指令 salb 会移 7 位,salw 会移 15 位,sall 会移 31 位,而 salq 会移 63 位。移位操作的目的操作数可以是一个寄存器或是一个内存位置。
上面这些都属于常规的算术指令,其实还有一类特殊的算术操作。通常,两个 64 位有符号或无符号整数相乘得到的乘积需要 128 位(16字节,称为八字)来表示,x86-64 指令集对此提供了有限的支持,如下表所示。
注意,这里又出现了一个 imulq 指令,不过它是单操作数的,汇编器能够通过计算操作数的数目来分辨出想用哪条指令。单操作数的 imulq 指令和 mulq 指令分别是计算两个 64 位值的全 128 位乘积,前者计算补码乘法,后者计算无符号数乘法。它们都要求一个参数必须在寄存器 %rax 中,而另一个作为指令的源操作数给出,然后乘积存放在寄存器 %rdx(高 64 位)和 %rax(低 64 位)中。下面这段 C 代码说明了如何从两个无符号 64 位数字 x 和 y 生成 128 位的乘积。
#include <inttypes.h> typedef unsigned __int128 uint128_t; void store_uprod(uint128_t *dest, uint64_t x, uint64_t y){ *dest = x * (uint128_t)y; }
这里的 unsigned __int128 类型是 GCC 提供的 128 位整数支持,改为 uint128_t 类型别名是为了沿用 inttypes.h 中其他数据类型的命名规律。最终的乘积存放在指针 dest 指向的 16 字节处。这段代码对应的汇编代码大致如下(对应的是小端法机器)。
; void store_uprod(uint128_t *dest, uint64_t x, uint64_t y) ; dest in %rdi, x in %rsi, y in %rdx store_uprod: movq %rsi, %rax ; Copy x to multiplicand mulq %rdx ; Multiply by y movq %rax, (%rdi) ; Store lower 8 bytes at dest movq %rdx, 8(%rdi) ; Store upper 8 bytes at dest+8 ret
除了 64 位乘法指令,这里还提供了之前的算术表里没有的除法和取模操作。它们也是单操作数的。其中,有符号除法指令 idivq 将寄存器 %rdx(高 64 位)和 %rax(低 64 位)中的 128 位数作为被除数,而将操作数作为除数,最终得出的商存储在寄存器 %rax 中,余数则存储在寄存器 %rdx 中。对于 64 位的被除数,其值应该存放在寄存器 %rax 中,而把 %rdx 的位设置为全 0(无符号运算)或者 %rax 的符号位(有符号运算)。后面这个操作可以用图中的指令 cqto 来完成,该指令不需要操作数,它会隐含读出 %rax 的符号位,并将它复制到 %rdx 的所有位。
下面这个 C 函数说明了 x86-64 是如何实现除法的,它计算了两个 64 位有符号数的商和余数。
void remdiv(long x, long y, long *qp, long *rp){ long q = x / y; long r = x % y; *qp = q; *rp = r; }
该函数对应的汇编代码大致如下。
; void remdiv(long x, long y, long *qp, long *rp) ; x in %rdi, y in %rsi, qp in %rdx, rp in %rcx remdiv: movq %rdx, %r8 ; Copy qp movq %rdi, %rax ; Move x to lower 8 bytes of dividend cqto ; Sign-extend to upper 8 bytes of dividend idivq %rsi ; Divide by y movq %rax, (%r8) ; Store quotient at qp movq %rdx, (%rcx) ; Store remainder at rp ret
发表评论
-
浮点运算指令
2019-05-22 23:13 1575上一节介绍了浮点数与各种数值类型之间的相互转换 ... -
浮点数类型转换指令
2019-05-15 22:37 1710在浮点寄存 ... -
浮点寄存器概述
2019-05-14 22:31 2590本文介绍的浮点寄存器是基于 AVX2(Adva ... -
汇编指令之跳转指令
2019-04-15 00:21 4799正常执行的情况下,指令会按照顺序一条条地执行, ... -
汇编指令之条件码
2019-04-08 21:05 2359在系统底层,除了整数寄存器,CPU 还维护着一 ... -
汇编指令之数据传送指令
2019-03-25 21:28 1289在x86-64 中的 ... -
x86-64 中的寄存器与汇编操作数杂述
2019-03-20 21:45 993Intel 中常用 ... -
hello 程序执行背后的故事
2018-12-26 21:48 608源文件 hello. ... -
linux启动服务概述
2017-04-08 02:43 398传统的linux中定义了七个运行级,分别如下: ... -
unix限制
2017-04-04 16:08 579UNIX系统实现定义了很多幻数和常量,其中有很 ... -
linux引导加载程序--GRUB
2017-04-04 04:22 625linux世界里有两种 ... -
存储器映射
2016-06-13 00:12 553注:本文摘自《深入理解计算机操作系统》第九章--虚拟存 ... -
虚拟存储器对存储器管理的作用
2016-06-10 16:00 696注:本文中的大部分内容均是摘录自《深入理解计算机系统》一书,权 ... -
信号处理问题
2016-06-03 08:31 562注:本文摘自《深入理解计算机系统》第8章 --- 异常控制流。 ... -
僵尸进程
2016-05-23 23:57 361在解释僵尸进程的概念之前,我们得先了解这样的一个事实: 一个进 ... -
程序优化之存储器别名使用
2016-05-20 08:55 797说明:本文示例摘自《深入理解计算机系统》第五章----优化程序 ... -
条件变量基本概念与原理(转载)
2016-05-20 08:54 1580对于条件变量,我一直感到很困惑,搞不清其与互斥锁到底有啥区别, ... -
CPU与磁盘的交互过程
2016-05-19 09:05 1840对于计算机系统底层技术,想必很多人都和我一样不太了解,最近在学 ... -
存储器层次结构中基本的缓存原理
2016-05-19 09:00 668对于操作系统,我们知道,越靠近CPU的存储器,其存储速度就会越 ... -
异常处理
2016-05-19 00:29 424我知道很多人都知道异常处理,但可能对其底层并不太了解,现在我们 ...
相关推荐
汇编指令是计算机硬件能够直接理解和执行的基本操作,每条指令对应一个特定的机器码。汇编指令查询器是一款工具,帮助程序员和计算机科学学习者快速查找并理解各种汇编指令的含义和用法。 汇编语言的核心在于它的...
本实验旨在帮助学生深入理解并掌握汇编语言中的算术逻辑运算指令和移位指令的功能,并通过实际编程加深对标志寄存器各标志位意义的理解以及这些指令执行后如何影响标志寄存器的状态。 #### 实验预习要求 1. **复习...
总结来说,STM8S汇编指令集是STM8微控制器编程的基础,包含了各种操作数据、控制流程、访问I/O和处理中断等功能的指令。熟练掌握这些指令,将有助于开发者编写出更加高效、针对性强的嵌入式程序,充分利用STM8S的...
ARM汇编指令集包括数据处理指令、分支指令、加载/存储指令、算术逻辑单元(ALU)操作以及处理器状态控制等。以下是一些关键的指令类型: 1. **数据处理指令**:包括加法(ADD)、减法(SUB)、逻辑操作(AND、ORR、...
C51单片机汇编指令全集 ...C51单片机汇编指令全集提供了非常详细的汇编指令手册,涵盖了各种数据传输、算术操作、布尔变量操作和控制转移的指令,对于单片机程序设计和开发具有非常重要的参考价值。
RH850 D1汇编指令作为RH850系列微控制器的核心组成部分之一,其强大的功能和灵活性使其成为实现高性能、低功耗应用的理想选择。通过对汇编指令的深入了解和掌握,开发者能够更好地利用微控制器的各项特性,从而提高...
数据处理指令用于执行算术运算和逻辑运算;转移指令控制程序流程,如跳转、循环等;输入/输出指令则负责与外部设备交互;处理器控制指令则用来改变处理器的状态或控制硬件操作。 在学习汇编语言时,汇编指令查询器...
1. 数据处理指令:这类指令主要用于执行基本的算术和逻辑运算,例如加法(ADD)、减法(SUB)、乘法(MUL)、除法(DIV)以及位操作(AND、OR、XOR、NOT)。这些指令在处理数值计算和逻辑判断时起到关键作用。 2. ...
该文档包含了DSP C6000系列芯片的全部汇编指令,涵盖了数据传输、输入输出端口传送、目的地址传送、标志传送、算术运算、逻辑运算等多个方面。 一、数据传输指令 数据传输指令用于在存贮器和寄存器、寄存器和输入...
汇编指令通常包括数据传输指令、算术运算指令、逻辑运算指令、控制流指令、输入输出指令等。例如,`MOV`指令用于在寄存器和内存之间传输数据,`ADD`指令执行加法操作,`AND`指令进行按位逻辑与运算,`JMP`指令用于...
汇编指令通常包括数据处理、转移控制、输入输出、算术运算、逻辑运算等多种类型。例如,`ADD`指令用于执行加法操作,`SUB`用于减法,`MOV`用于数据传输,`JMP`用于跳转,`CALL`用于调用子程序,`RET`用于返回主程序...
单片机汇编指令大全是指单片机编程中使用的汇编语言指令集,用于控制和操作单片机的寄存器、内存和外设。这些指令是单片机编程的基础部分,正确地使用这些指令是编写高效、可靠的单片机程序的关键。 在单片机汇编...
1. 数据处理指令:这类指令用于对寄存器中的数据进行算术和逻辑运算。例如: - ADD:加法操作,将两个寄存器的值或一个寄存器与一个立即数相加。 - SUB:减法操作,从一个寄存器的值中减去另一个寄存器的值或一个...
综上所述,Intel汇编指令集包含了一系列丰富的指令,能够满足各种不同的编程需求,从简单的数据传输到复杂的数学计算和逻辑操作。通过对这些指令的学习和掌握,开发者能够有效地利用处理器的能力来构建高效、可靠的...
汇编语言是计算机编程的一种低级语言,它与机器语言密切相关,每一个汇编指令通常对应一个特定的机器码,直接控制计算机硬件的操作。以下将对汇编语言的一些核心概念和常见指令进行深入探讨。 首先,汇编语言的基本...
MIPS汇编指令集包含多种指令类型,支持算术运算、逻辑运算、位字段操作、跳转与分支、乘法与除法等基本操作。MIPS指令集旨在实现简单、对称和一致的指令编码,它具有以下特点: - 32个通用寄存器(R0-R31)。 - ...
通常,汇编指令包括数据传输、算术运算、逻辑操作、流程控制等类别,每种指令都有其特定的语法和操作。使用asmfun,用户不仅可以查询已有的汇编指令,还可以自定义添加新的或非标准的指令,这对于处理特殊硬件或特定...
1. **数据处理指令**:包括算术运算(如ADD、SUB、MUL、DIV)、逻辑运算(AND、OR、NOT、XOR)和移位操作(SHL、SHR)等,用于执行基本的数值计算和数据处理任务。 2. **控制流程指令**:如JMP、CALL、RET、jecomp...
本文将详细解析51汇编指令集,包括常用的基本操作,如算术运算、逻辑运算等。 一、51汇编指令集概述 51汇编指令集主要包括算术运算、逻辑运算、转移指令、控制指令、位操作等。这些指令在51单片机中用于控制硬件...
- **数据处理指令**:用于执行算术运算、逻辑运算和数据移动等基本操作。 - **控制流指令**:用于改变程序的执行顺序,如条件跳转、无条件跳转和循环控制。 - **输入/输出指令**:用于与外部设备或系统内存进行通信...