ComputerSystems
大约 5 分钟
ComputerSystems
目录
算术和逻辑操作
整数算术操作(分为4组:加载有效地址、一元操作、二元操作、移位)
指令 | 单词 | 操作数 | 效果 | 描述 |
---|---|---|---|---|
leaq | S、D | D < &S | 加载有效地址 | |
—————— | —————— | —————— | —————— | |
INC | increase | D | D < D+1 | 加1 |
EDC | decrease | D | D < D-1 | 减1 |
NEG | negative | D | D < -D | 取负(-D=~D+1) |
NOT | not | D | D < ~D | 取补(D+~D=-1) |
—————— | —————— | —————— | —————— | |
ADD | add | S、D | D < D+S | 加 |
SUB | subtraction | S、D | D < D-S | 减 |
IMUL | multiply | S、D | D < D*S | 乘 |
XOR | exclusive or | S、D | D < D^S | 异或 |
OR | or | S、D | D < D|S | 或 |
AND | and | S、D | D < D&S | 与 |
—————— | —————— | —————— | —————— | |
SAL | k、D | D < D<<k | 左移 | |
SHL | k、D | D < D<<k | 左移(等同SAL) | |
SAR | k、D | D < D>>Ak | 算术右移 | |
SHR | k、D | D < D>>Lk | 逻辑右移 |
具体还可细分指令类,如:指令类ADD由四条加法指令组成:addb、addw、addl、addq
加载有效地址
指令 | 操作数 | 效果 | 描述 |
---|---|---|---|
leaq | S、D | D < &S | 加载有效地址 |
- 加载有效地址(load effective address)
leaq
:- 是
movq
指令(传送四字(8字节))的变形,leaq S,D
相当于C语言中的D = &S
即leaq S,D
等同于movq S的地址,D
- 妙用:能执行有限形式的2加法&1乘法,如
leaq (%rdi,%rsi,4), %rax
,十分方便
- 是
一元操作
指令 | 单词 | 操作数 | 效果 | 描述 |
---|---|---|---|---|
INC | increase | D | D < D+1 | 加1 |
EDC | decrease | D | D < D-1 | 减1 |
NEG | negative | D | D < -D | 取负(-D=~D+1) |
NOT | not | D | D < ~D | 取补(D+~D=-1) |
一元:inc和dec类似于C语言中的加1运算符和减1运算符
- 操作数为寄存器或内存地址
地址+1也是加长度而非1,如:
incq (%rsp)
inc/dec
inc reg/mem ; = add ax 1
dec reg/mem ; = sub ax 1
; 注意:他们不影响eflags的CF符号位
mul/div
mul reg/mem ; 操作数应是8/16位
div reg/mem ; 操作数应是8/16位
mul/div
- 只有一个操作数,所以会有一些指定的寄存器,要预先将数放进去
- mul/div操作数都是无符号的 (不能处理负数),而add/sub/adc/sbb这些都可以处理有符号数
mul,注意结果会影响标志位
被乘数 | 乘数 | 乘积 |
---|---|---|
reg/mem8 | al | ah:al |
reg/mem16 | dx | dx:ax |
div,注意结果不会影响标志位
被除数 | 除数 | 余数 | 商 |
---|---|---|---|
ax | reg8/mrm8 | ah | al |
dx:ax | reg16/mem16 | dx | ax |
实战:
如果需要做一些高位除法,例如32位除以16位的除法,则需要自己写汇编代码
例如:0x00090006除以2 = 0x00048003余0
; 准备
mov dx, 0x0009 ; 高16位
mov ax, 0x0006 ; 低16位
mov cx, 0x0002 ;
push ax ; 低16位入栈
mov ax, dx ; 高16位放到ax
mov dx, 0 ; dx置为0
; ax=0x0009, bx=0x????, cx=0x0002, dx=0x0000, 栈=[0x0006]
; 高位除法
div cx ; 先做高位除法
mov bx, ax ; 商保存至bx
pop ax
; ax=0x0006, bx=0x0004, cx=0x0002, dx=0x0001, 栈=[]
; 注意一下这里的dx是参与在被除数中的,即被除数是0x00010006,结果是不溢出的16位
; 低位除法
div cx ;
; ax=0x8003, bx=0x0004, cx=0x0002, dx=0x0000, 栈=[]
; 最终计算结果 = bx:ax余dx = 0x00048003余0,符合
二元操作
指令 | 单词 | 操作数 | 效果 | 描述 |
---|---|---|---|---|
ADD | add | S、D | D < D+S | 加 |
SUB | subtraction | S、D | D < D-S | 减 |
IMUL | multiply | S、D | D < D*S | 乘 |
XOR | exclusive or | S、D | D < D^S | 异或 |
OR | or | S、D | D < D|S | 或 |
AND | and | S、D | D < D&S | 与 |
二元:add和sub类似于C语言中的x+=a和x-=a
第一个操作数为立即数、寄存器或内存地址
- 第二个操作数为寄存器或内存地址。为内存时:处理器会先读出值、执行操作、再把结果写回内存
add/sub
基本使用
add reg/men reg/mem/imm ;加法,两操作数分别应是8/16位
sub reg/men reg/mem/imm ;减法,两操作数分别应是8/16位
; 注意add或sub会产生借位或进位,必须将借位或进位保存下来
; CPU内部有一个标志寄存器(eflags),第0位是CF位,用来保存进位和借位
验证:addsub.asm
;不产生进位的加法
mov ax, 0x0001
mov bx, 0x0002
add ax, bx
;产生进位的加法
mov ax, 0xf000
mov bx, 0x1000
add ax, bx
;不产生进位的减法
mov cx, 0x0003
mov dx, 0x0001
sub cx, dx
;产生进位的减法
mov cx, 0x0001
mov dx, 0x0002
sub cx, dx
xh: jmp xh ; xh是自定义命名
times 510($-$$) db 0
add/sub衍生指令 adc/sbb
adc = add with carry = 被加数+加数+CF
sbb = sub with carry = 被减数-减数-CF
应用场景:处理高位的加减法
; 例如计算0x0001f000 + 0x000101000,但只有4位寄存器
; bx:ax=0x0001f000
mov bx, 0x0001
mov ax, 0xf000
; dx:cx=0x00101000
mov dx, 0x0010
mov cx, 0x1000
; 低位相加。此时CF=0,可不用adc
add ax, cx
; 高位相加。此时使用adc,若CF=1则会加上CF
adc bx, dx
jmp $
times 510($-$$) db 0
; 结果为bx:ax=0x00120000
and/
and dest目的(reg/mem) source源(reg/mem/imm)
or dest目的(reg/mem) source源(reg/mem/imm)
not reg/mem
xor dest目的(reg/mem) source源(reg/mem/imm) ; 会影响标志位
骚操作
- 当仅取某一位时,用一个数 (如1100) 来与其进行and运算,有1的部分才会保留
- 当想将某一位强制变1,用一个数 (如0010) 来与其进行or运算,有1的部分强制变1
- 可以用来匹配两个数是否相同,若是则结果全0。可以用来置零
移位操作
指令 | 操作数 | 效果 | 描述 |
---|---|---|---|
SAL | k、D | D < D<<k | 左移 |
SHL | k、D | D < D<<k | 左移(等同SAL) |
SAR | k、D | D < D>>Ak | 算术右移 |
SHR | k、D | D < D>>Lk | 逻辑右移 |
骚操作
- 当乘或除以一个2^n数时,直接左移或右移
其他
讨论
cmp 比较指令
cmp dest(reg/mem) source(reg/mem/imm)