汇编语言笔记(持续更新)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39776901/article/details/79813754

寄存器

汇编程序员通过 汇编指令 修改寄存器中的内容 来控制CPU

AX = AH + AL H = high 高 L = low 低
BX = BH + BL
CX = CH + CL
DX = DH + DL

通用寄存器 一般存放数据

FFFFH

2Byte = 16bit 0-65535

0 - (2的16次方 - 1)

mov ah,40h

寄存器是互相独立的
AH 和 AL 是没有关系的

地址信息

段地址:偏移地址
ds bp
es ip
ss sp
cs si
di
bx

指令执行的过程

1、 CPU从cs:ip所组成的地址中读取指令,将这个指令存放到指令缓存器中
2、 IP = IP + 所读到指令的字节数
3、 执行指令缓存器中的内容,回到步骤1 重复这个过程

debug 调试工具

r 寄存器

d 段地址:偏移地址 - 偏移地址

u 将后续的字节翻译成汇编指令 查看汇编指令 段地址:偏移地址

a 段地址:偏移地址

e 段地址:偏移地址

t

Byte = 8bit (字节型数据) -> 一个内存地址就能保存一个字节
Word = 2Byte = 16bit (字型数据) -> 一个字需要两个地址连续的内存单元来存放 高位地址存放高位字节 低位地址存放低位字节

;=========================================================
1、指令在哪里

2、数据在哪里
3、数据的长度

4、对数据的处理
5、数据存放到哪里
;=========================================================
1、CS:IP指向的地址中的内容CPU当做是指令
2、指令和数据都存放在内存中

;=========================================================
1、数据的长度:字节(Byte)型数据,字型(2Byte)数据
2、字节型数据只需要一个内存地址存放
3、字型数据需要2个连续的内存地址存放,高位地址存放高位字节,低位地址存放低位字节

;=========================================================

移动指令
mov 寄存器,数据 mov ax,10H
mov 寄存器,寄存器 mov ax,bx
mov 寄存器,内存单元 mov ax,ds:[0] 取字型数据 mov
al,ds[0] 取字节型数据
mov 内存单元,寄存器 mov ds:[0],ax
mov 段寄存器,寄存器 mov bx,1000H => mov ds,bx
mov 寄存器,段寄存器 mov bx,ds

不允许 mov ds,1000H

运算指令
add 寄存器,数据 add ax,1
add 寄存器,寄存器 add ax,bx
add 寄存器,内存单元 add ax,ds:[0]
add 内存单元,寄存器 add ds:[0],ax

sub 寄存器,数据 sub ax,1
sub 寄存器,寄存器 sub ax,bx sub ax,ax
sub 寄存器,内存单元 sub ax,ds:[0]
sub 内存单元,寄存器 sub ds:[0],ax

转移指令
jmp
call

;===============================================


一段连续的内存空间,连续的内存地址
特殊在访问形式上

字节型数据
字型数据 2byte

入栈 push 字型数据 -> 数据从哪里来
出栈 pop 字型数据 -> 数据取出到哪里

push -> sp - 2 => 讲从哪里来的字型数据存放到SS:SP
pop -> SS:SP字型数据拿出去哪里 -> sp + 2

伪代码
push 语文书
push 数学书
push 英语书

pop 书架1
pop 书架2
pop 书架3

push 寄存器 -> ax bx cx dx ds es ss sp…. 16bit 一个字

push ds:[0] ->从ds:[0]拿一个字型数据

pop 寄存器

pop ax
pop bx

pop ds:[0]

段地址:偏移地址
ss sp 它们永远指向栈顶数据

;=========================================================

d 2000:0

箱子为什么画在那里? -> 我决定的 -> 栈在哪里和SS:SP有关 -> 由程序员决定SS:SP
箱子是有大小的 -> 也是我决定的 -> 栈也是由程序员决定的

栈的大小 = 16字节 = 8个字

修改SS = 2000H SP = 10H 2000:0 + 10H = 2000:10H

栈都是我们自己安排的,从哪里开始(ss:sp) 大小

栈越界
程序员自己注意

栈最大的作用:临时性保存数据

1、一个栈能够存放最多多少个字型数据? 32768

地址线 -> CPU的寻址能力

SS:SP

0 - FFFFH 字节

ax = FFFFH
ds = FFFFH
ax = 2200H
ss = 2200H
sp = 0100H

;==========================================================

CS:IP 和指令有关
DS:[0] [1] … 和数据有关
SS:SP 临时性数据

数据在哪里
数据的长度 字节型数据 字型数据 AX BX CX DX AH AL BH BL
数据的处理 ADD SUB
数据存放到哪里

数据是我们自己安排
存放到哪里自己安排
指令在哪里自己安排

汇编语言由什么组成

汇编指令
伪指令 由编译器执行的
符号体系

通过汇编指令 修改CPU中寄存器中的内容,控制整个计算机

;===========================================================
数据在哪里? ds:[0]
数据长度? 字节型数据,字型数据

访问内存需要 地址信息ds:[0] 数据长度

ds si

;loop 循环指令 CX = CX - 1 检测CX是不是等于0
;循环体
;CX 循环次数

;============================================================
编程用加法计算123*236 结果存放在AX中
mov ax,0

    mov cx,236

addNumber: add ax,123
loop addNumber ;标号 地址

;=============================================================
;内存安全 保护模式 实模式
;0:2000H ~ 0:2ffH FF 255+1 = 256
;07:7E00H

;=============================================================
ds: 数据从哪里来
es: 数据到哪里去

;=============================================================

代码段
数据段
栈段

1、在加载的过程中系统分配内存
2、在执行过程中向系统申请

数据段在代码段中申请数据空间
dw d = define w = word 字型数据 定义字型数据
db d = define b = byte 字节型数据 定义字节型数据
dw 0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H
cs:0 ————————————–cs:f
23 01 56 04 89 07 BC 0A EF 0D ED 0F BA 0C 87 09

栈段在代码段中申请空间

;============================================================
问题:

数据颠倒

assume cs:code

code segment

dw  0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H

dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0

start: mov ax,cs
mov ss,ax
mov sp,30H

    mov ax,cs
    mov ds,ax
    mov bx,0

    mov cx,8

pushData: push ds:[bx]
add bx,2
loop pushData

    mov cx,8
    mov bx,0

popData: pop ds:[bx]
add bx,2
loop popData

    mov ax,4C00H
    int 21H

code ends

end start

;==============================================================
问题:
1、将内存0:0 ~ 0:fH 内存单元中的 字型数据 改写到代码段中的数据,补全程序
assume cs:code

code segment

dw  0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H

start: mov ax,0
mov ds,ax
mov bx,0

    mov cx,8

copyData: mov ax,ds:[bx]
mov cs:[bx],ax
add bx,2
loop copyData

    mov ax,4C00H
    int 21H

code ends

end start

2、实现将内存0:0 ~ 0:FH 内存单元中的 字型数据 改写到代码段中的数据
但是通过栈空间来实现
assume cs:code

code segment

dw  0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H

dw  0,0,0,0,0,0,0,0

start: mov ax,cs
mov ss,ax
mov sp,32

    mov ax,0
    mov ds,ax
    mov bx,0

    mov cx,8        

popData: push ds:[bx]
pop cs:[bx]
add bx,2
loop popData

    mov ax,4C00H
    int 21H

code ends

end start

;==============================================================
数据段 栈段 代码段
assume cs:code,ds:data,ss:stack

data segment
dw 0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H
data ends

stack segment stack
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,16

    mov ax,data
    mov ds,ax
    mov bx,0

    push ds:[bx]

    mov ax,4C00H
    int 21H

code ends

end start

其中code data stack 这三个名字可以自己起,注意和前面的使用的变化

;===================================================================
实验
assume cs:code,ds:data,ss:stack

data segment
dw 00EEH,00EEH
data ends

stack segment
dw 00FFH,00FFH
stack ends

code segment
… //代码段
code segment
内存中排列为
EE 00 EE 00 00 00 00 00 00 00 00 00 00 00 00 00
FF 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 00
//代码段


如果段中的数据占用N个字节,则程序加载后,该段实际占有空间为_ 补满16的倍数的空间 ( N/16 + 1 ) * 16

;============================================================
vim :set wrap 设置自动折行
:set nowrap 设置不自动折行

;============================================================
实验
程序如下,编写code段中的代码,将a段和b段中的字节型数据依次相加,结果存放到c段中

assume cs:code

a segment
db 1,2,3,4,5,6,7,8
a ends

b segment
db 1,2,3,4,5,6,7,8
b ends

c segment
db 0,0,0,0,0,0,0,0
c ends

code segment
start: mov cx,8
mov bx,0

    mov ax,a
    mov ds,ax

    mov ax,c
    mov es,ax

addNumber: mov dx,0

    mov ax,a
    mov ds,ax
    add dl,ds:[bx]

    mov ax,b
    mov ds,b
    add dl,ds:[bx]

    mov es:[bx],dl

    inc bx
    loop addNumber

    mov ax,4C00H
    int 21H

code ends
end start

程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存放到段b中

assume cs:code

a segment
dw 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0EH,0FH,0FFH
a ends

b segment
dw 0,0,0,0,0,0,0,0
b ends

stack segment stack
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,32

    mov ax,a
    mov ds,ax
    mov bx,0

    mov cx,8

pushNumber: push ds:[bx]
add bx,2
loop pushNumber

    mov ax,b
    mov es,ax
    mov bx,0

    mov cx,8

popNumber: pop es:[bx]
add bx,2
loop popNumber

    mov ax,4C00H
    int 21H

code ends

end start

;=======================================================================
and指令 和 or指令

and指令:逻辑运算指令,按 位 进行 与 运算 真假
or指令: 逻辑运算指令,按 位 进行 或 运算
位 = bit 1代表真 0代表假

   F    F                  0    F

mov al,1111 1111B mov al,0000 1111B
and al,0000 1111B mov al,1111 0000B
al=0000 1111B al=1111 1111B
0 F F F

ASCII码 加单引号
db ‘asdfasdfasdfasdf’

mov al,'a'
mov al,'b'

;=======================================================================
大小写转换问题

字符 十六进制 二进制 转换 十进制
A 41H 0100 0001B or 0010 0000B / or 20H 65
B 42H 0100 0010B 66
C 43H 0100 0011B 67
D 44H 0100 0100B 68

a 61H 0110 0001B and 1101 1111B / or DFH 97
b 62H 0110 0010B 98
c 63H 0110 0011B 99
d 64H 0110 0100B 100

实验 大小写转换
大写———》小写 or 20H
小写———》大写 and 0DFH

assume cs:code,ss:stack,ds:data

data segment
db ‘ABCDEF’
db ‘abcdef’
data ends

stack segment stack
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,data
mov ds,ax
mov bx,0

    mov ax,data
    mov es,ax

    mov cx,6

;全变成小写
lowerLetter: mov dl,ds:[bx]
or dl,00100000B
mov es:[bx],dl
inc bx
loop lowerLetter

    mov cx,6
    mov bx,6

;全变成大写
upperLetter: mov dl,ds:[bx]
and dl,DFH
mov es:[bx],dl
inc bx
loop upperLetter

    mov ax,4C00H
    int 21H

code ends
end start

;==========================================================
偏移地址组合方式[bx+数字] or [bx].数字

mov ax,ds:[bx]
mov ax,ds:[bx+1] or mov ax,ds:[bx].1

ds:[bx+si]
ds:[bx+di]

ds:[bx+si+数字]
ds:[bx+di+数字]
问题
用debug查看内存,结果如下:
2000:1000 BE 00 06 00 00 00
写出下面程序执行后,ax,bx,cx中的内容

mov ax,2000H
mov ds,ax
mov bx,1000H ax = 2000H bx = 1000H

mov si,0 si = 0
mov ax,ds:[bx+si] ax = 00BEH
inc si si = 1
mov cx,ds:[bx+si] cx = 0600H
inc si si = 2
mov di,si di = 2
add cx,ds:[bx+di] cx = 0606

;==========================================================
si和di
一般si和ds匹配,di和es匹配

问题
用si和di实现将字符串”welcome to masm!”复制到后面的数据区中

assume cs:code,ds:data

data segment
db ‘welcome to masm!’
db ‘…………….’
data ends

code segment
start: mov ax,data
mov ds,ax
mov es,ax

    mov si,0        ;ds:[si]    es:[di]
    mov di,16

    mov cx,16

copyData: mov dl,ds:[si]
mov es:[di],dl
inc si
inc di
loop copyData

    mov ax,4C00H
    int 21H

code ends
end start

用push和pop方法解决上面的问题
assume cs:code,ds:data

data segment
db ‘welcome to masm!’
db ‘…………….’
data ends

stack segment stack
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,32

    mov ax,data
    mov ds,ax
    mov es,ax

    mov si,0        ;ds:[si]    es:[di]
    mov di,16

    mov cx,8

copyData: push ds:[si]
pop es:[di]
add si,2
add di,2
loop copyData

    mov ax,4C00H
    int 21H

code ends
end start

;=======================================================
偏移地址组合运用
问题

将data段中每个单词的头一个字母改为大写
assume cs:code,ds:data

data segment
;0123456789ABCDEF
db ‘1. file ’
db ‘2. edit ’
db ‘3. search ’
db ‘4. view ’
db ‘5. options ’
db ‘6. file ’
data ends

code segment
start: mov ax,data
mov ds,ax
mov es,ax

    mov bx,0        ;ds:[si+di]是不允许的
    mov si,3

    mov cx,6

changeLetter: mov dl,ds:[bx+si]
and dl,0DFH
mov es:[bx+si],dl
add bx,16
loop changeLetter

    mov ax,4C00H
    int 21H

code ends
end start

问题
将data段中每个单词都改为大写
assume cs:code,ds:data

data segment
;0123456789ABCDEF
db ‘1. ibm ’
db ‘2. dec ’
db ‘3. dos ’
db ‘4. vax ’
data ends

stack segment
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,32

    mov ax,data
    mov ds,ax
    mov es,ax

    mov cx,4
    mov bx,0
    mov si,3

upLetter: push cx
push si
mov cx,3

upRow: mov dl,ds:[bx+si]
and dl,0DFH
mov es:[bx+si],dl
inc si
loop upRow

    pop si
    pop cx
    add bx,16
    loop upLetter

    mov ax,4C00H
    int 21H

code ends
end start

将data段中每个单词的前4个字母都改为大写
assume cs:code,ds:data

data segment
;0123456789ABCDEF
db ‘1. display ’
db ‘2. brows ’
db ‘3. replace ’
db ‘4. modify ’
data ends

stack segment stack
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,32

    mov ax,data
    mov ds,ax
    mov es,ax

    mov bx,0
    mov si,3

    mov cx,4

upRow: push cx
push si
mov cx,4

upCol: mov dl,ds:[bx+si]
and dl,0DFH
mov es:[bx+si],dl
inc si
loop upCol

    pop si
    pop cx
    add bx,16
    loop upRow


    mov ax,4C00H
    int 21H

code ends
end start

;========================================================
gvim 快捷键

w 向后移动一个单词 b 向前移动一个单词
J 删除换行符,使下一行并上来 nJ 连接后面的n行
;========================================================
数据在哪里 CPU中的寄存器中 内存中 端口

寄存器中
ax,bx,cx,dx ah,al bh,bl ch,cl dh,dl

内存中
地址信息 8086CPU

段地址信息:偏移地址信息 段地址 * 10H + 偏移地址
ds ip
es sp
ss si
cs di
bp(和ss有关)

ds:[0]
ds:[bx]
ds:[si]
ds:[di]
ss:[bp]

ds:[bx+si+2]
ds:[bx+di]
ds:[bx+si]

ss:[bp+si+2]
;===============================================================
不通过寄存器进行操作
字型
mov word ptr ds:[0],1122
inc word ptr ds:[bx]
字节型
mov byte ptr ds:[0],22
inc byte ptr ds:[0]

题目

assume cs:code,ds:data,ss:stack

data segment
db ‘DEC’
db ‘Ken Olsen’
dw 137 ;修改成38 ;12
dw 40 ;修改成70 ;14
db ‘PDP’ ;修改成’VAX’ ;16
data ends

code segment
start: mov ax,data
mov ds,bx
mov bx,0

    mov word ptr ds:[bx+12],38
    mov word ptr ds:[bx+14],70

    mov si,0
    mov byte ptr ds:[bx+16+si],'V'
    inc si
    mov byte ptr ds:[bx+16+si],'A'
    inc si
    mov byte ptr ds:[bx+16+si],'X'

    mov ax,4C00H
    int 21H

code ends

end start
;==========================================================
数据的处理
;加法
add add ax,dx
add ax,ds:[0]
add dx:[0],ax

add word ptr ds:[0],1   ;error 加法和减法必须通过寄存器

;减法
sub ;减法,同上

;除法
div bx(寄存器)/bl
div byte ptr ds:[0]
div word ptr ds:[0]

1、除数: 8bit 16bit 存在内存单元中或者寄存器中
2、被除数: 默认被存放在AX或者AX和DX中,
如果除数为8位,被除数则为16位,存放在AX中
如果除数为16位,被除数则为32位,AX存放低16位,DX存放高16位
结果: 如果除数为8位,则AL存商,AH存放余数
如果除数为16位,则AX存放商,DX存放余数

问题:
利用除法指令计算 100001 / 100

100001 = 186A1H 超过AX所能表示的最大值65535(FFFFH),所以,低16位(86A1)放在AX中,高16位(1)放在DX中
100 = 64H

mov ax,86a1
mov dx,1
mov bx,64
div bx

利用除法指令计算 1001 / 100
assume cs:code

code segment
start: mov ax,1001 ;AX = 3E9
mov bl,100 ;BX = 64
div bl ;AL = 0A AH = 01

    mov ax.4C00H
    int 21H

code ends
end start

;===============================================================
新的数据长度
db 占1个字节 字节型数据
dw 占2个字节 字型数据
dd 占4个字节 双字型数据

;===============================================================
dup指令

eg:
data segment
db 256 dup (0)
data ends

;===============================================================
实验
将年份,年收入,员工数目,对应放入year summ ne中
再用年收入除以员工数目,得到的商,放入 ?? 中

assume cs:code,ds:data,ss:stack

data segment
;年份
db ‘1975’,’1976’,’1977’,’1978’,’1979’,’1980’,’1981’,’1982’,’1983’
db ‘1984’,’1985’,’1986’,’1987’,’1988’,’1989’,’1990’,’1991’,’1992’
db ‘1993’,’1994’,’1995’
;年收入
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;员工数量
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

table segment
;0123456789ABCDEF
db 21 dup (‘year summ ne ?? ‘)
table ends

stack segment stack
db 128 dup (0)
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,128

    mov ax,data
    mov ds,ax
    mov si,0

    mov bx,168

    mov ax,table
    mov es,ax
    mov di,0

    mov cx,21

inputTable: push ds:[si]
pop es:[di]
push ds:[si+2]
pop es:[di+2]

    mov ax,ds:[si+84]
    mov dx,ds:[si+86]
    mov es:[di+5],ax
    mov es:[di+7],dx

    push ds:[bx]
    pop es:[di+10]

    div word ptr es:[di+10]

    mov es:[di+13],ax       ;商

    add si,4
    add bx,2
    add di,16
    loop inputTable

    mov ax,4C00H
    int 21H

code ends
end start

;===========================================================
转移指令 jmp
jmp 2000:0 ;cs = 2000 ip = 0 ;段间转移

mov ax,2222
jmp ax ;ip = 2222 ;短转移

1、CPU从CS:IP读取指令,将指令存放到指令缓存器中
2、IP = IP + 所读指令的字节数(指令的长度)
3、执行指令缓存器中的内容,回到第一步

新指令 OFFSET
作用:得到偏移地址
mov ax,OFFSET next

问题
将 s 偏移地址的指令存放到 s0 偏移地址
assume cs:code

code segment
s: mov ax,bx
mov si,OFFSET s
mov di,OFFSET s0

    _______________     mov dx,cs:[si]
    _______________     mov cs:[di],dx

s0: nop
    nop

    mov ax,4C00H
    int 21H

code ends
end start

jmp指令原理
标号处的地址 - jmp指令后的第一个字节的地址

assume cs:code,ds:data,ss:stack

data segment
db 256 dup (0)
data ends

stack segment stack
db 128 dup (0)
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,128

    call cpy_Tetris

    mov ax,4C00H
    int 21H

Tetris: call clear_screen

    mov ax,4C00H
    int 21H 

clear_screen: mov bx,1000H
mov bx,1000H
mov bx,1000H
mov bx,1000H
mov bx,1000H

    ret

Tetris_end: nop

cpy_Tetris: mov bx,cs
mov ds,bx
mov si,OFFSET Tetris

    mov bx,0
    mov es,bx
    mov di,7E00H

    mov cx,OFFSET Tetris_end - Tetris
    cld
    rep movsb

    ret

code ends
end start
;========================================================
jmp far ptr -32768 ~ 32767
jmp short ptr -128 ~ 127

猜你喜欢

转载自blog.csdn.net/qq_39776901/article/details/79813754