跳至主要內容

ComputerSystems

LincZero大约 5 分钟

ComputerSystems

目录

算术和逻辑操作

整数算术操作(分为4组:加载有效地址、一元操作、二元操作、移位)

指令单词操作数效果描述
leaqS、DD < &S加载有效地址
————————————————————————
INCincreaseDD < D+1加1
EDCdecreaseDD < D-1减1
NEGnegativeDD < -D取负(-D=~D+1)
NOTnotDD < ~D取补(D+~D=-1)
————————————————————————
ADDaddS、DD < D+S
SUBsubtractionS、DD < D-S
IMULmultiplyS、DD < D*S
XORexclusive orS、DD < D^S异或
ORorS、DD < D|S
ANDandS、DD < D&S
————————————————————————
SALk、DD < D<<k左移
SHLk、DD < D<<k左移(等同SAL)
SARk、DD < D>>Ak算术右移
SHRk、DD < D>>Lk逻辑右移

具体还可细分指令类,如:指令类ADD由四条加法指令组成:addb、addw、addl、addq

加载有效地址

指令操作数效果描述
leaqS、DD < &S加载有效地址
  • 加载有效地址(load effective address)leaq
    • movq指令(传送四字(8字节))的变形,leaq S,D相当于C语言中的D = &Sleaq S,D等同于movq S的地址,D
    • 妙用:能执行有限形式的2加法&1乘法,如leaq (%rdi,%rsi,4), %rax,十分方便

一元操作

指令单词操作数效果描述
INCincreaseDD < D+1加1
EDCdecreaseDD < D-1减1
NEGnegativeDD < -D取负(-D=~D+1)
NOTnotDD < ~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/mem8alah:al
reg/mem16dxdx:ax

div,注意结果不会影响标志位

被除数除数余数
axreg8/mrm8ahal
dx:axreg16/mem16dxax

实战:

如果需要做一些高位除法,例如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,符合

二元操作

指令单词操作数效果描述
ADDaddS、DD < D+S
SUBsubtractionS、DD < D-S
IMULmultiplyS、DD < D*S
XORexclusive orS、DD < D^S异或
ORorS、DD < D|S
ANDandS、DD < 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。可以用来置零

移位操作

指令操作数效果描述
SALk、DD < D<<k左移
SHLk、DD < D<<k左移(等同SAL)
SARk、DD < D>>Ak算术右移
SHRk、DD < D>>Lk逻辑右移

骚操作

  • 当乘或除以一个2^n数时,直接左移或右移

其他

讨论

cmp 比较指令

cmp dest(reg/mem) source(reg/mem/imm)

特殊的算术操作