指令标注 Operand Notation

指令instruction即运算operation, 操作的对象为一个或多个运算数operand, 使用不同的标记表示不同的约束

<reg>  寄存器,  运算数必须是一个寄存器. Register operand. The operand must be a register.
<reg8>, <reg16>, <reg32>, <reg64> 指定大小的寄存器运算数 Register operand with specific size requirement. For example, reg8 means a byte sized register (e.g., al, bl, etc.) only and reg32 means a double-word sized register (e.g., eax, ebx, etc.) only.
<dest> 目的运算数, 可以是寄存器或内存, 其内容在运算后将被运算结果覆盖, Destination operand. The operand may be a register or memory. Since it is a destination operand, the contents will be over written with the new result (based on the specific instruction).
<RXdest> 浮点的目的运算数, 必须是一个浮点寄存器. Floating point destination register operand. The operand must be a floating point register. Since it is a destination operand, the contents will be over written with the new result (based on the specific instruction).
<src> 来源运算数, 其值参与运算, 但是在指令操作后不会变化. Source operand. Operand value is unchanged after the instruction.
<imm> 立即数, Immediate value. May be specified in decimal, hex, octal, or binary.
<mem> 内存地址, 可以是一个变量名或者是一个间接引用(如内存地址). Memory location. May be a variable name or an indirect reference (i.e., a memory address).
<op> or <operand> 运算数, Operand, register or memory.
<op8>, <op16>, <op32>, <op64> 指定大小的运算数, Operand, register or memory, with specific size requirement. For example, op8 means a byte sized operand only and reg32 means a double-word sized operand only.
<label> 标记 Program label.

数据移动 Data Movement

mov <dest>, <src>
mov ax, 42
mov cl, byte [bvar]
mov dword [dVar], eax
mov qword [qVar], rdx

将数值从来源寄存器或内存复制到目的寄存器或内存. 来源和目的必须是相同的尺寸(都是byte, 或都是word等). 目的不能是立即数, 来源和目的不能同时为内存. 如果要做内存到内存的复制, 需要两个指令.
特殊情况: 当目标寄存器为double word尺寸的整数寄存器时, 对应此double word的quadword上半部分会被全设为0.

例如当以下指令被执行时, rcx开始时被赋值为-1(全是0xF), 当100被复制到ecx后, rcx的上半部分会被0全部覆盖.

mov eax, 100   ; eax = 0x00000064
mov rcx, ­-1 ; rcx = 0xffffffffffffffff
mov ecx, eax ; ecx = 0x00000064

指令说明
1. 复制来源运算数到目的运算数
2. 两个运算数不能同时为内存
3. 目的运算数不能为立即数
4. 对于来源和目的都是double word的运算数, 目的运算数对应的quadword的上半部分会被置零

地址和数值 Address vs Values

获取内存内容的唯一方法是通过方括号([]), 如果不使用方括号获取的是变量的地址. 例如

mov  rax, qword [var1]  ; 将var1的值复制到rax
mov rax, var1 ; 将var1的地址复制到rax

因为忽略方括号不是语法错误, 编译器不会产生错误信息, 但是这容易让人产生疑惑. 另外, 变量的地址其实可以通过lea (load effective address)指令来获取, 用法举例如下

lea     <reg64>, <mem>    Place address of <mem> into reg64.
lea rcx, byte [bvar]
lea rsi, dword [dVar]

数值转换指令 Conversion Instructions

降级转换 Narrowing Conversion

降级转换用于将一个大尺寸的数值转换为较小类型的数值, 例如word到byte, 或double word到word
在降级转换中不需要特殊的指令, 寄存器或内存的低部可以直接访问, 例如如果数值50(0x32)存储在rax寄存器, 那么可以直接通过al访问获得小尺寸的数值

mov  rax, 50
mov byte [bVal], al

这个例子因为50可以用一个byte表示, 所以al和rax的实际数值大小是一样的. 但是如果500(0x1f4)放置在rax寄存器, 那么寄存器依然可以访问, 但是结果就不一样了. bVal得到的值将会是0xf4

mov  rax, 500
mov byte [bVal], al

升级转换 Widening Conversion

升级转换用于将小尺寸的数值转换为较大尺寸, 例如byte到word或word到double word. 因为尺寸扩大, 高地址部分的bit需要根据带符号或不带符号数做对应的填充. 所以做升级转换时, 必须先知道数值的符号属性, 才能对应使用正确的指令.

无符号转换

对于无符号的升级转换, 高地址部分需要置零. 例如转换值为50的al寄存器, 可以通过以下指令, 完成后rbx寄存器的值就是50

mov  al, 50
mov rbx, 0
mov bl, al

这个通用的方式可以处理内存或其他寄存器. 另外有一个指令可以简化这个处理

movzx  <dest>, <src>
movzx <reg16>, <op8>
movzx <reg32>, <op8>
movzx <reg32>, <op16>
movzx <reg64>, <op8>
movzx <reg64>, <op16>
; Examples
movzx cx, byte [bVar]
movzx dx, al
movzx ebx, word [wVar]
movzx ebx, cx
movzx rbx, cl
movzx rbx, cx

这会将高地址部分的bit置零. 注意: movzx指令不允许使用quadword类型作为目的运算数. 因为之前提到过, mov使用double word作为运算数时, 会同时将其高地址部分的double word也置零.
movzx使用说明
1. 两个运算数不能同时为内存 both operands can not be memory.
2. 目的运算数不能为立即数, destination operands can not be an immediate.
3. 不允许使用立即数值

有符号数的转换

对于有符号数的升级转换, 根据原数值的符号, 高地址部分需要全部被填充为0或者1. 这个操作由一个符号数扩展操作完成. 其实就是将当前数的符号位的值, 直接填充到高地址位. 用于符号数扩展的有一系列的指令, 仅工作在A寄存器上, 用于将A寄存器的数值扩展到高地址位, 有时候会将数值扩展到D寄存器. 例如cwd指令, 用于将ax中的带符号数值, 扩展成double word尺寸的数值, 放入dx(上半部分)和ax(下半部分), 这种结果通常写作 dx:ax. 而cwde指令, 将ax中的带符号数值, 扩展成double word尺寸的数值并存储在eax寄存器.

常用指令用法及说明
cbw    ;Convert byte in al into word in ax. Note, only works for al to ax register.
cwd    ;Convert word in ax into double-word in dx:ax. Note, only works for ax to dx:ax registers.
cwde   ;Convert word in ax into word into double-word in eax. Note, only works for ax to eax register.
cdq    ;Convert double-word in eax into quadword in edx:eax. Note, only works for eax to edx:eax registers.
cdqe   ;Convert double-word in eax into quadword in rax. Note, only works for rax register.
cqo    ;Convert quadword in rax into word in double-quadword in rdx:rax. Note, only works for rax to rdx:rax registers.

movsx, movsxd   ; Signed widening conversion (via sign extension).
Note 1, both operands can not be memory.
Note 2, destination operands can not be an immediate.
Note 3, immediate values not allowed.
Note 4, special instruction (movsxd) required for 32-bit to 64-bit signed extension.

movsx   <dest>, <src>
movsx <reg16>, <op8>
movsx <reg32>, <op8>
movsx <reg32>, <op16>
movsx <reg64>, <op8>
movsx <reg64>, <op16>
movsxd <reg64>, <op32>
movsx cx, byte [bVar]
movsx dx, al
movsx ebx, word [wVar]
movsx ebx, cx
movsxd rbx, dword [dVar]

整数运算指令 Integer Arithmetic Instructions

整数运算包括在整数上的加减乘除

加法 Addition

通用指令为

add   <dest>, <src>
add cx, word [wVvar]
add rax, 42
add dword [dVar], eax
add qword [qVar], 300

1. 结果将被放入目的运算数, 源运算数值不变
2. 两个运算数必须是同一尺寸
3. 目的运算数不能是立即数
4. 两个运算数不能同时为内存

代码例子

bNum1   db 42
bNum1 db 73
bAns db 0
wNum1 dw 4321
wNum2 dw 1234
wAns dw 0
dNum1 dd 42000
dNum2 dd 73000
dAns dd 0
qNum1 dq 42000000
qNum2 dq 73000000
qAns dq 0 ; bAns = bNum1 + bNum2
mov al, byte [bNum1]
add al, byte [bNum2]
mov byte [bAns], al
; wAns = wNum1 + wNum2
mov ax, word [wNum1]
add ax, word [wNum2]
mov word [wAns], ax
; dAns = dNum1 + dNum2
mov eax, dword [dNum1]
add eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 + qNum2
mov rax, qword [qNum1]
add rax, qword [qNum2]
mov qword [qAns], raxInstruction Set Overview
; dAns = dNum1 + dNum2
mov eax, dword [dNum1]
add eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 + qNum2
mov rax, qword [qNum1]
add rax, qword [qNum2]
mov qword [qAns], rax

在一些指令里, 包括上面的指令, 可以不指定具体的数值尺寸(例如byte, word, dword), 因为另一个运算数已经明确指定了尺寸的大小. 保留是为了编程的一致性, 便于阅读和维护.

除了加法指令, 还有一个自增指令, 可以使用于byte, word, dword, qword, 在作用于内存时, 要明确标明尺寸

inc   <operand>
inc word [wVvar]
inc rax
inc dword [dVar]
inc qword [qVar]

代码例子

bNum db 42
wNum dw 4321
dNum dd 42000
qNum dq 42000000
inc rax ; rax = rax + 1
inc byte [bNum] ; bNum = bNum + 1
inc word [wNum] ; wNum = wNum + 1
inc dword [dNum] ; dNum = dNum + 1
inc qword [qNum] ; qNum = qNum + 1

带进位的加法 Addition with Carry

带进位的加法是一个特殊的加法指令, 会在运算中添加前一条指令产生的结果的进位数值. 这在进行大数(超过寄存器尺寸的数字)运算时非常方便.
例如进行如下的运算 17+25=42, 第一步进行7+5的运算, 第二步要紧接着第一步立即执行, 在执行加法时包含前一步产生的进位, 信息存储于rFlag, 通常的计算指令为

adc   <dest>, <src> ;<dest> = <dest> + <src> + <carryBit>
adc rcx, qword [dVvar1]
adc rax, 42

代码例子

dquad1 ddq 0x1A000000000000000
dquad2 ddq 0x2C000000000000000 ;这些都是128bit数值, 会超过64-bit寄存器的尺寸
dqSum ddq 0 mov rax, qword [dquad1]
mov rdx, qword [dquad1+8]
add rax, qword [dquad2]
adc rdx, qword [dquad2+8]
mov qword [dqsum], rax
mov qword [dqsum+8], rdx

减法 Subtraction

减法指令的格式

sub   <dest>, <src>  ;<dest> = <dest> ­ <src>
sub cx, word [wVvar]
sub rax, 42
sub dword [dVar], eax
sub qword [qVar], 300

src被减去dest的数值, 并且结果会保存到desc下. src的值不会改变. desc和src的数值尺寸必须一致, desc不能是立即数, desc和src不能同时为内存.

代码例子

bNum1 db 73
bNum2 db 42
bAns db 0
wNum1 dw 1234
wNum2 dw 4321
wAns dw 0
dNum1 dd 73000
dNum2 dd 42000
dAns dd 0
qNum1 dq 73000000
qNum2 dq 73000000
qAns dd 0 ; bAns = bNum1 ­ bNum2
mov al, byte [bNum1]
sub al, byte [bNum2]
mov byte [bAns], al
; wAns = wNum1 – wNum2
mov ax, word [wNum1]
sub ax, word [wNum2]
mov word [wAns], ax
; dAns = dNum1 – dNum2
mov eax, dword [dNum1]
sub eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 ­ qNum2
mov rax, qword [qNum1]
sub rax, qword [qNum2]
mov qword [qAns], rax

自减指令

除了基本的减法指令外, 可以使用dec指令进行自减操作, 格式为

dec   <operand> ;<operand> = <operand> ­ 1
dec word [wVvar]
dec rax
dec dword [dVar]
dec qword [qVar]

可以作用于byte, word, dword, qword, 如果使用于内存, 需要明确标明数值尺寸
代码例子

bNum db 42
wNum dw 4321
dNum dd 42000
qNum dq 42000000 dec rax ; rax = rax ­ 1
dec byte [bNum] ; bNum = bNum ­ 1
dec word [wNum] ; wNum = wNum ­ 1
dec dword [dNum] ; dNum = dNum ­ 1
dec qword [qNum] ; qNum = qNum ­ 1

.

.

Ubuntu x86-64汇编(3) 数值操作指令的更多相关文章

  1. Ubuntu x86-64汇编(4) 数值操作指令

    整数乘法指令 Integer Multiplication 对于有符号数的乘法有特殊的规则, 因此无符号数乘法和有符号数乘法对应着不同的指令mul和imul. 乘法会产生两倍尺寸的数值结果, 即两个n ...

  2. Ubuntu x86 64 settup nginx rtmp server

    常常搭建nginxserver,可是好像每次的情况都不同,这次具体记录这个过程: 平台:unbutu 10.04 内核:2.6.32-33-generic 1, 编译环境搭建. sudo apt-ge ...

  3. 汇编实现: C库常见函数,串操作指令作用

    目录 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 二丶loads实现Strlen操作. 三丶stos的作用 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 void _ ...

  4. 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构

    引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...

  5. linux常用操作指令

    Linux常用操作指令: 常用指令 ls        显示文件或目录 -l           列出文件详细信息l(list) -a          列出当前目录下所有文件及目录,包括隐藏的a(a ...

  6. ARM指令集——条件执行、内存操作指令、跳转指令

    ARM 汇编指令条件执行 在ARM模式下,任何一条数据处理指令可以选择是否根据操作的结果来更新CPSR寄存器中的ALU状态标志位.在数据处理指令中使用S后缀来实现该功能. 不要在CMP,CMN,TST ...

  7. 第24篇-虚拟机对象操作指令之getfield

    getfield指令表示获取指定类的实例域,并将其值压入栈顶.其格式如下: getstatic indexbyte1 indexbyte2 无符号数indexbyte1和indexbyte2构建为(i ...

  8. 第25篇-虚拟机对象操作指令之putstatic

    之前已经介绍了getstatic与getfield指令的汇编代码执行逻辑,这一篇介绍putstatic指令的执行逻辑,putfield将不再介绍,大家可以自己去研究,相信大家有这个实力. putsta ...

  9. 深入理解JVM(1)——栈和局部变量操作指令

    将常量压入栈的指令 aconst_null 将null对象引用压入栈iconst_m1 将int类型常量-1压入栈iconst_0 将int类型常量0压入栈iconst_1 将int类型常量1压入栈i ...

随机推荐

  1. Table does not have the identity property. Cannot perform SET operation.

    Table   does not have the identity property. Cannot perform SET operation. 解决:   set IDENTITY_INSERT ...

  2. 样条之EHMT插值函数

    核心代码: ////////////////////////////////////////////////////////////////////// // 埃特金插值 ////////////// ...

  3. go语言之进阶篇并行和并发的区别与go语言并发优势

    1.并行和并发的概念 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行. 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在 ...

  4. python对json的操作总结 zz

    Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式.Json最广泛的应用是作为AJAX中web服务器和客户端的通讯的数据格式.现在也常用于h ...

  5. Ios之网络编程NSURLConnection

    通过NSURLConnection主要通过四个类进行网络访问:NSURL,NSURLRequest,NSMutableURLRequest,NSURLConnection 一.基本知识 (1)NSUR ...

  6. Github用.gitignore忽略指定文件

    .gitignore Github提供.gitignore这种功能,可以自己指定哪些文件可以不被管理.具体方法是在版本管理的根目录下(与.git文件夹同级)创建一个.gitignore. 应用实例 项 ...

  7. 2017 年度码云新增项目排行榜 TOP 50,为它们打“call”

    2017 年度码云新增项目排行榜 TOP 50 正式出炉 !2017 结束了,我们来关注一下这一年里码云上新增的最热门的开源项目吧.此榜单根据 2017 年在码云上新增开源项目的 Watch.Star ...

  8. Android Fragment的使用(转载)

    可以分为下面的几部分: 使用支持库 创建一个Fragment 创建一个动态UI 多个Fragment之间的通信 1.使用支持库 如果您的应用需要运行在3.0及以上的版本,可以忽略这部分内容. 如果您的 ...

  9. 向windows添加环境变量

    以NASM为例,软件安装完毕后,启动Windows操作系统的命令窗口,在安装目录(比如C:\Program Files\NASM)下运行nasm是ok的,但是在其他任意目录下运行nasm就会报错. 这 ...

  10. Python爬虫学习系列教程

    最近想学一下Python爬虫与检索相关的知识,在网上看到这个教程,觉得挺不错的,分享给大家. 来源:http://cuiqingcai.com/1052.html 一.Python入门 1. Pyth ...