编写汇编
定义一个段
- segment和ends是一对成对使用的伪指令,这是在写可被编译器编译的汇编程序时,必须要用到的一对伪指令。
- segment和ends的功能是定义一个段,segment说明一个段的开始,ends说明一个段的结束。
- 一个段必须有一个名称来表示,使用格式为:
- 段名 segment
- 段名 ends
- 一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当做栈空间来使用。
-
end
end是汇编程序的结束标记,如果碰到伪指令end,就结束对源程序的编译。
程序写完了,在结尾加上伪指令end,不然无法知道程序何时结束。
assume
他假设某一段寄存器和程序中的某一个用segment···ends定义的段相关联。
- 通过assume说明这种关联,在需要的情况下,编译程序可以将段寄存器和某一个具体的段相联系。
汇编源程序
伪指令(编译器处理)
汇编指令(编译为机器码)
程序:源程序中最终由计算机执行、处理的指令或数据。源程序
任务:编写运算2^3。 ``` assume cs:abc
abc segment mov ax,2 mov bx,2 mul ax mul bx
mov ax,4c00H int 21H abc ends
end abc ends
end
<a name="d2WDm"></a>
#### 程序返回
应该在程序的末尾添加返回的程序段。<br />mov ax,4c00H<br />int 21H<br />这两台指令所实现的功能就是程序返回。
<a name="jzfRO"></a>
## 多个段的程序
- 对于使用多个段的问题:编程计算以下4个数据的和,结果存放在ax寄存器中。0123H,0456,0123H,0123H
- 在一个段中存放数据、代码、栈
assume cs:codesg
codesg segment
tong:
dw 0123H,0123H,0123H,0123H,0123H,0123H,0123H,0123H,0123H
xor bx,bx
xor ax,ax
mov cx,9h
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00H
int 21H
codesg ends end tong
dw:定义字型数据。define word 16b。<br />在程序的第一条指令的前面加上了一个标号start,而这个标号在伪指令end的后面出现。<br />end出了通知编辑器程序结束之外,还可以通知编译器程序的入口在什么地方。
- 将一段数据放入栈中,实现逆序存放
assume cs:codesg
codesg segment
start:
dw 0ffffH,0123H,0123H,0123H,0123H,0123H,0123H,0123H
dw 0,0,0,0,0,0,0,0
mov bx,0
mov cx,8
s: push cs:[bx]
add bx,2
loop s
mov cx,8
mov bx,0
s0: pop cs:[bx]
add bx,2
loop s0
mov ax,4c00H
int 21H
codesg ends end start
- 将数据、代码、栈放入不同的段
- 如果数据、栈和代码需要的空间超过64KB,就不能放在一个断中。8086模式的限制,不是每个处理器都是这样。
assume cs:code,ds:data,ss:stack
data segment
dw 0ffffH,0123H,0123H,0123H,0123H,0123H,0123H,0123H
data ends
stack segment dw 0,0,0,0,0,0,0,0 stack ends
code segment
start:
mov ax,stack 分配栈空间
mov ss,ax
mov sp,16 设置栈顶ss:sp stack:16
mov ax,data 分配data空间
mov ds,ax ds指向data段
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov cx,8
mov bx,0
s0: pop [bx]
add bx,2
loop s0
mov ax,4c00H
int 21H
code ends end start
就是秀~~~我也太强了。
- 代码段、数据段、栈段完全是我们自己定义的。
- 用来存放数据段的:data
- 用来存放代码段的:code
- 用来存放栈空间的:stack
<a name="Hv3vK"></a>
## and&or
这个太简单了,没啥好写的。
<a name="opaaf"></a>
## ASCII码
- 世界上很多编码方案,ASCII是计算机通常被采用的
- 编码就是一套规则,用干什么样的信息来表示现实对象
- 比如61H表示'a'
- mov al,'a'相当于mov al,61H
- 大小写转换
code segment
start:
mov al,’A’
or al,20h
and al,0dfh
mov ax,4c00H
int 21H
code ends end start
<a name="Sp0Av"></a>
## [bx+idata]
- mov ax,[bx+200]的含义
- 将一个内存单元的内容送入ax,这个内存单元的长度为2字节,存放一个字,偏移地址为bx中的数据加上200,段地址在ds中。
- 数学化描述:mov ax,[bx+200]=((ds)*16+(bx)+200)
- 数组的处理
datasg segment db ‘abcdefghijklm’ db ‘nopqrstuvwxyz’ datasg ends
code segment
start:
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,13
s: mov al,[bx]
and al,11011111b
mov [bx],al
mov al,[bx+13] —[bx+13]可以表示为13[bx],是不是特别像数组
and al,11011111b
mov [bx+13],al
inc bx
loop s
mov ax,4c00H
int 21H
code ends end start
<a name="DWnuy"></a>
## SI&DI
- SI和DI是8086CPU中与BX功能相近的寄存器,但是SI和DI不能够分成两个8位寄存器来使用。
- 将“tong ge shuai bi”用si,di复制到“................”中
datasg segment db ‘tong ge shuai bi’ db ‘…………….’ datasg ends
code segment
start:
mov ax,datasg
mov ds,ax
mov si,0
mov di,13
mov cx,13
s: mov al,[si]
mov [di],al
inc di
inc si
loop s
mov ax,4c00H
int 21H
code ends end start
<a name="XghvJ"></a>
## 不同的寻址方式和灵活应用
- 几种定位内存地址的方法
- [iata]用一个常量来表示地址,可用于直接定位一个内存单元
- [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元
- [bx+idata]用一个变量和常量表示地址,可在一个起止的基础上用变量间接定位一个内存单元
- [bx+si]用两个变量表示地址
- [bx+si+idata]用两个变量和一个常量表示地址
- 讲前四个字母换成大写字母
stack segment dw 0,0,0,0,0,0,0,0 stack ends
datasg segment db ‘tonggeshuai…..’ db ‘deyipi……….’ datasg ends
code segment
start:
mov ax,datasg
mov ds,ax
mov ax,stack
mov ss,ax
xor bx,bx
mov cx,2
s0:push cx
mov cx,4
xor si,si
s1:mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s1
pop cx
add bx,10h
loop s0
mov ax,4c00H
int 21H
code ends end start
实现了双重循环。吊的一批~~~~
<a name="yOjOK"></a>
## 寄存器集合
- reg:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di
- sreg:ds、ss、cs、es
- 在8086寄存器中,只有bx、bp、si、di可以用在[...]中进行内存寻址
- 在[...]中只能以四个组合出现
- bx&si、bx&di、bp&si、bp&di
- 指令中没有设置段地址(ds没给值),[bp]的段地址默认给ss的段
- mov ax,[bp]=((ss)*16+bp)
<a name="fCrw6"></a>
## 寻址方式
关于DEC公司的一条记录:<br />公司名称:DEC 在内存中如下存放<br />总裁姓名:Ken Olsen seg:60+00<br />排 名:137 'DEC'<br />收 入:40 +03 <br />著名产品:PDP 'ken slsen'<br />2021年同哥的加入公司有了新变化: +0C
1. Ken Olsen在富翁榜上的排名已升至38位; 137
1. DEC的收入增加了70亿美元; +0E
1. 该公司的著名产品已变为VAX系列计算机。 40
任务:编程修改内存中的过时数据。 +10 <br /> 'PDP'
code segment
start:
mov bx,60h
mov si,0
mov word ptr [bx+0Ch],137d
mov word ptr [bx+0Eh],40d
mov byte ptr [bx+10h+si],’P’
inc si
mov byte ptr [bx+10h+si],’D’
inc si
mov byte ptr [bx+10h+si],’P’
inc si
xor si,si
mov word ptr [bx+0ch],38d
mov ax,[bx+0eh]
add ax,70d
mov word ptr [bx+0eh],ax
mov byte ptr [bx+10h+si],'V'
inc si
mov byte ptr [bx+10h+si],'A'
inc si
mov byte ptr [bx+10h+si],'X'
inc si
mov ax,4c00H
int 21H
code ends end start
<a name="reOHz"></a>
## div指令
- div是触发指令,使用div作触发的时候:
- 除数:8位或16位,在寄存器或内存单元中
- 被除数:(默认)放在ax或dx和ax中
- 除数 被除数
- 8位 16位(ax)
- 16位 32位(dx+ax)
- 结果:运算 8位 16位
商 AL AX<br /> 余数 AH DX
- div byte ptr ds:[0]
- (al)=(ax)/((ds)*16+0)的商
- (ah)=(ax)/((ds)*16+0)的余数
- div word ptr es:[0]
- (ax)=[(dx)*10000H+(ax)]/((ds)*16+0)的商
- (dx)=[(dx)*10000H+(ax)]/((ds)*16+0)的余数
- 利用除法指令计算100001/100
code segment
start:
mov dx,1h
mov ax,86a1h
mov bx,100h
div bx
mov ax,4c00H
int 21H
code ends end start
伪指令dd
- db和dw定义字节型数据和字型数据。
- dd是用来定义dword(double word双字)型数据的。
- db 1:01H
- dw 1:00 01H
- dd 1:00 00 00 01H
code segment
start:
mov bx,0h
mov si,0h
mov [bx+si],word ptr 86a1h
add si,2h
mov [bx+si],word ptr 1h
add si,2h
mov [bx+si],word ptr 100d
add si,2h
mov [bx+si],word ptr 0d
mov ax,[0]
mov dx,[2]
div word ptr [4]
mov [6],ax
mov ax,4c00H
int 21H
dup
- db 3 dup(0)
- 定义了3个字节,都为0
- 0,0,0
- db 3 dup(0,1,2)
- 定义了9个字节
- 0,1,2,0,1,2,0,1,2
- db 3 dup(‘abc’,’ABC’)
- 定义了18个字节
- abcABCabcABCabcABC