Ubuntu x86-64汇编(3) 数值操作指令

指令标注 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

.

.

posted on 2018-05-28 10:46  Milton  阅读(793)  评论(0编辑  收藏  举报

导航