汇编复习笔记(也可作为进阶篇)

本文最后更新于:2021年1月1日 晚上

计算机中的数

二进制的补码

对于8位的二进制来说,+0和-0的补码都是00000000(只有一种表示)

但是按道理来说10000000是表示-0的,这个二进制就用来表示-128。同理100000000用来表示-256
所以对于8位的补码表示的数的范围为-128 ~ +127

补码的符号扩展

比如16位补码(一字节)扩展为32位补码(双字):正数高位补零,负数高位补一

字节,节,页

256个字节 = 16个节 = 1个页

存储数据

存储器

我们除了数据存入寄存器中,其他的数据就是存在内存中的,内存中以字节为单位存储信息。内存中的数据存入方式是由低地址到高地址。

但是当要存储的数据由多个字节组成(如双字数据)时,我们要遵守大大小小原则即低位字节存入低地址,高位字节存入高地址

地址的分段

80的地址总线宽度是20位,也就是说寻址空间正好是2²⁰ = 1M的空间大小。

于是我们用实模式的两种地址来表示实际的逻辑地址:段地址左移一位 + 偏移地址正好就是5位的16进制数

部分指令详解

在指令部分,我其实已经有写过(其实是搬运)一篇文章来记录所有基本的指令,这里我只是挑一些进行详细解读

类型转换指令

cbw(convert byte to word)———- 字节转字

cwd(convert word to double word)———- 字转双字

ps:
cbw较为常用,其中前者默认是将AL中内容扩展到AX,后者默认是AX扩展到DX : AX中的双字(所以有DX代表双字的说法

加减1指令

这俩指令用的很多,平时却有点记不住,特在此记下:

inc(increment)——— 加一操作

dec(decrement)———- 减一操作

因为neg(求补)和dec是在一起的,也在此说明一下:
neg(negate)——— 单纯就是将操作数按位求反后加一

逻辑指令

and ——— 逻辑与
or ———— 逻辑或
not ———- 逻辑非
xor(exclusive or)——— 异或
test ——— 测试

这些指令都是后接两个操作数,结果保存到前一个操作数,除了test

test两个操作数相与的结果不保存,只根据其特征置条件码:利用ZF改变,存放结果

移位指令

shl(shift logical left)——- 逻辑左移
sal(shift arithmetic left)—— 算术左移
shr(shift logical right)—— 逻辑右移
sar(shift arithmetic right)—— 算术右移
rol(rotate left)———— 循环左移
ror(rotate right)————- 循环右移
rcl(rotate left through carry)——- 带进位循环左移
rcr(rotate right through carry)——- 带进位循环右移

逻辑和算术移位都是缺位补零,进位送CF。(算术右移是将其自身填入空缺位)
循环移位是循环移位一次,进位给CF。

方向标志改变指令

CLD(clear direction flag)——- 使DF = 0

STD(set derection flag)———- 使DF = 1

汇编程序基本格式

datas SEGMENT
    ...
datas ENDS

stacks SEGMENT
    db 100 dup(0)
stacks ENDS

codes SEGMENT
    assume cs:codes,ds:datas,ss:stacks
start:
    mov ax,datas
    mov ds,ax
    ...
    mov ah,4ch
    int 21h
codes ENDS
end start

伪操作

assume

用来明确段和段寄存器之间的关系,我们通常会这么写:

assume cs:codes,ds:datas,ss:stacks

但是如果我们要取消前面的指定可以用:

assume nothing

类型转换

同一个变量可以具有不同的类型属性

eg:

oper1 db 1,2

mov ax,oper1+1

显然这个表达是错的(会报错),oper1的类型是字节,而ax的类型是字,类型不匹配。

ptr

我们用ptr可以把oper1的类型转换成字:

mov ax,word ptr oper1+1

这样就不会有类型的报错了,同时word这里还可以是bytedword等多个类型

label

除了ptr的转换,我们还可以用label(相当于是取别名)

对于oper1数据我们可以在定义时:

oper1_word label word
oper1 db 1,2

这样我们用oper1_word进行字的操作,用oper1来进行字节的操作。但是它们指向的是同一个内存空间。

EQU

可以用EQU(equal?)来给一个表达式赋予一个名字(这是一个赋值伪操作),eg:

data equ var+2 

ps:equ不允许重复定义,同时equ伪操作不占用内存空间

warning:=也可以错位赋值伪操作使用(=可以重复使用),但是两者不能同时使用

地址计数器

在汇编中表示当前指令的地址(偏移地址)。

每处理一条指令,地址计数器就增加一个值

org伪操作

此伪操作用来设置当前地址计数器的值,eg:

org 10 		;此时偏移地址为10

基数控制伪操作

warning:汇编程序默认的数为十进制数

.radix伪操作可以把默认的基数改变成2 ~ 16的任何基数,eg:

.radix 16
mov bx,0ff		;16进制就不用写h
mov bx,178d		;10进制就要写d

数值回送操作符

type

如果之后的表达式是一个变量,则汇编程序返回该变量的以字节数表示的类型:db为1,dw为2,dd为4。

array dw 1,2,3
mov si,type array		;等同于mov si,2

length

  • 对于变量使用dup的情况,程序返回分配该变量的单元数(只看第一个dup
  • 对于其他情况一概返回1
fee dw 100 dup(0)
mov cx,length fee		;等同于mov cx,100

size

程序返回伪操作之后变量的type值与length值的乘积,比如之前的fee变量:

mov cx,size fee
;相当于mov cx,200

seg

程序会返回变量或者标号的段地址值

比如如果datas是地址为05000h的数据段段名,oper1是该段中第一个变量名:

mov bx,seg oper1
;相当于是mov bx,05000h

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!