汇编的基础

本文介绍了如何在DOSBox中设置编程环境,使用Debug调试工具进行CPU寄存器、内存内容的查看与修改,讲解了包括移动、加减、乘除、逻辑运算在内的基本汇编指令,以及栈操作、循环、函数调用的实现。同时,文章涵盖了内存地址的概念和数据段的组织,以及字符串处理的一些实例。
摘要由CSDN通过智能技术生成

原视频

基础篇:1.1编程环境的安装

打开DOSBox 0.74-3 Options.bat调整窗口大小

windowresolution=1200x640
output=ddraw
mount c D:\masm
c:
debug

DEBUG

用Debug的R命令查看、改变CPU寄存器的内容:
用Debug的D命令查看内存中的内容:
用Debug的E命令改写内存中的内容:
用Debug的U命令将内存中的机器指令翻译成汇编指令:
用Debug的T命令执行一条机器指令:
用Debug的A命令以汇编指令的格式在内存中写入一条机器指令。

mov,add,sub

mov ax,bx
ax=bx
add ax,bx
ax+=bx
sub ax,bx
ax-=bx

mul,div,and,or

mul乘法指令

因下面要用到,这里介绍一下mul指令,mul是乘法指令,使用mul做乘法的时候,
注意以下两点。
(1)两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中:如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中。
(2)结果:如果是8位乘法,结果默认放在AX中:如果是16位乘法,结果高位默认在DX中存放,低位在AX中放。


mul bl
al*bl
结果在ax

mul bx
ax*bx
结果高位在DX 低位在AX

div除法指令

(I)除数:有8位和16位两种,在一个reg或内存单元中。
(2)被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,
默认在AX中存放:如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。
(3)结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数:
如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。


div bl
ax/bl
结果ah为余数 al为商

div bx
(dx*2^32+ax)/bx
结果dx为余数 ax为商

and or

(I)and指令:逻辑与指令,按位进行与运算。
例如指令:
mov al,01100011B
and al,00111011B
执行后:al=00100011B
(2)or指令:逻辑或指令,按位进行或运算。
例如指令:
mov al,01100011B
or al,00111011B
执行后:al=01111011B

shl

是逻辑左移指令,它的功能为

(1)将一个寄存器或内存单元中的数据向左移位:
(2)将最后移出的一位写入CF中
(3)最低位用0补充。


mov al,01001000b
shl al,1
执行后al=10010000b cf=0

shr

是逻辑右移指令,它和shl所进行的操作刚好相皮

(1)将一个寄存器或内存单元中的数据向右移位:
(2)将最后移出的一位写入CF中:
(3)最高位用0补充。shr是逻辑右移指令,它和shl所进行的操作刚好相反


mov al,10000001b
shr al,1
执行后:(al)=01000000b,CF=1

dec inc neg xchg

dec ax
ax--
inc ax
ax+=
neg ax
ax取反
xchg ax,bx
ax与bx的值交换

int

 int指令是X86汇编语言中最重要的指令之一。它的作用是引发中断,调用“中断例程”(interrupt routine)。本文将介绍int指令的基本原理和应用,以及BIOS和DOS系统的中断例程。

一、int指令的原理

1,指令原型
int n
注:    
1)n 表示中断号,也可以称为中断类型码。n是一个字节大小的正整数,范围为“0 - 255”。
2)执行“int n”时,CPU从中断向量表中,找到第n号表项,修改CS和IP

    (IP)=(n*4),(CS)=(n*4+2)

3)对8086PC,中断向量表指定放在内存地址0处(地址固定),共1024个字节。每个表项占两个字,低字存放偏移地址,高字存放段地址。

ds寄存器,段地址,偏移地址,物理地址

ds用来放段地址
存放当前正在运行的程序代码所在段的段基值
073f:0100
段地址为073f
偏移地址为0100
物理地址为073f*16+0100

给ds寄存器赋值
mov ax,0100
mov ds,ax

cs:ip

基地址:偏移地址

cs 为代码段寄存器,一般用于存放代码;
通常和IP 使用用于处理下一条执行的代码

jmp

jmp bx
将ip寄存器的值改为bx

ss-sp pop push

存储栈的地址
ss-sp指向栈顶
push寄存器
:将一个寄存器中的数据入栈
pop寄存器
:出栈,用一个寄存器接收出栈的数据
-a
073F:0100 mova×,1234
073F:0103 push a×
073F:0104 mov b×,5678
073F:0107 push bx
073F:0108 pop ax
073F:0109 pop bx
073F:010A

sp=00fd
sp=00fb
sp=00f9

073F:0100                       78 56 34 12 00 00 00

bp si di

mov ax,[bx]
mov ax,[si]
mov ax,[si+1]
mov ax,[si+bx]
错误指令
mov ax,[bx+bp]
mov ax,[si+di]

存放段地址的寄存器可以是默认的,比如:
mov ax,[0]
mov ax,[di]
mova,[bx+8]
mowa%,[bx+si]
mov ax,[bx+si+B]
等指令,段地址默认在ds中:
mov ax,[bp]
mov ax,[bp+8]
mov ax,[bp+si]
mov ax,[bp+si+8]
等指令,段地址默认在ss中。


(3)只要在[...]中使用寄存器bp,而指令中没有显性地给出段地址,段地址就默认在ss中。

es 为扩展段寄存器; ss 为栈段寄存器,一般作为栈使用 和sp搭档;

es 为扩展段寄存器;

flag寄存器

标志truefalseName(名称)命题
OFOV (Overflow)NV (Not Overflow)0verflowFlag(是否溢出)存在溢出?
SFNG(NeGative负的)PL(Plus正的)Sign Flag(结果的符号是正还是负)是负数(正数看做无符号)?
ZFZR(Zero)NZ(Not Zero)Zero Flag(运算结果是否为0)是0?
PFPE(Even偶数)Po(odd奇数)Parity Flag(结果中二进制位个数的奇偶性)是偶数个1?
CFCY(Carry yes)NC(Not carry)Carry Flag(进位标志)有进位?
DFDN (Down)UP(Up)Direction Flag(方向标志)si、di递减?

adc

adc ax,bx
ax=ax+bx+CF

sbb

sbb ax,bx
ax=ax-bx-CF

cmp

cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
cmp ax,bx
ax-bx

如果(ax)=(bx)则(ax)-(bx)=0,所以:zf=1
如果(ax)≠(bx)则(ax)-(bx)≠0,所以:zf=0
如果(ax)<bx)则(ax)-(bx)将产生借位,所以:cf=l
如果(ax)≥(bx)则(ax)-(bx)不必借位,所以:cf=0
如果(ax)>(bx)则(ax)-(bx)既不必借位,结果又不为0,所以:cf=0并且zf=0
如果(ax)≤(bx)则(ax)-(bx)既可能借位,结果可能为0,所以:cf=1或zf=1
指令含义检测的相关标志位
je等于则转移zf=1
jb低于则转移cf=1
ja高于则转移cf=0且zf=0
cmp ax,bx
je 073f:0106

运行asm文件

masm
输入文件名
link 文件名
debug 文件名.asm

循环语句loop

loop指令的格式是:loop标号,CPU执行loop指令的时候,要进行两步操作,
①cx=cx-1:②判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。
下面例子中ax=2^12
assume cs:code
code segment
  start:mov ax,2
		mov cx,12
		s:
		 add ax,ax
		 loop s
		int 21H
code ends
end start

call ret

call在执行时会先将下一条指令所对应的ip地址入栈,然后修改ip的值实现跳转, ret指令执行的时候,将ip地址pop出来进行跳转

call s ;
标号里面存放的是ip偏移地址 如果写成call 3H  
那么意思就是跳转到CS:0003h这个位置

执行函数s
assume cs:code
code segment
  start:mov ax,2
		mov cx,12
		call s
		int 21H
		s:
		add ax,ax
		loop s
		ret
code ends
end start

call Far ptr retf

ret和call配套使用,retf和call Far ptr 配套使用

可以通过标号(函数名称)之间数值相减计算函数体代码所占用的内存空间大小

retf需要配合栈进行使用,当程序执行到retf这条指令时,会连续从栈中pop两次数据,第一次的数据赋值给CS,第二次的数据赋值给IP,那么如果我们想要跳转到指定的指令,需要将该指令的段地址和偏移地址分别push进栈中

stack segment
	db 128 dup(0)
stack ends

code segment
	start:
		mov ax,stack
		mov ss,ax
		mov sp,128
		
		mov ax,0710H ;指定段地址
		push ax
		mov ax,0003H ;指定偏移地址
		push ax
		
		retf ;程序跳转到0710:0003H这个位置
code ends
end start

内存地址    机器码                         汇编指令
1000:0      b8 00 00                      mov ax,0
1000:3      9a 09 00 00 10            call far ptr s
1000:8      40                                inc ax
1000:9      58                             s:pop ax
                                                     										add ax,ax
                                                     										pop bx
                                                     										add ax,bx
为什么ax会是1010?详细解答

执行指令先要读入到指令缓冲区中
读进去以后IP已经指向下一条指令了
call far ptr执行了push cs,push ip,jmp far ptr
这么指行的话call far ptr s的cs:1000,ip:8
把cs先扔进栈,后扔ip
那么到了s:pop ax这个时候应该是ip先出来,所以ax=8
接着执行add ax,ax=6
接着pop bx,现在bx=1000
然后执行add ax,bx
那么就是ax=1010H

代码段、数据段、栈段、dup指令

assume cs:codesg,ds:data,ss:stack
MASM内部以数基的个数定义了多种数据类型
BYTE,db,8位
WORD,dw,16位
DWORD,dd,32位
QWORD,dq,64位

db 10 dup (0)
初始化10个值为0的空间
assume cs:codesg,ds:data,ss:stack
data segment
		dw 123H,456H,789H,OabcH,OdefH
		db 3 dup(1,2,3)
		db 3 dup ('abc,'def)
data ends
stack segment
		db 10 dup (0)
stack ends
codesg segment
		start:
		dw 'hellow rold'
		mov ax,3
		mov cx,11
		call s
		inc bx
		inc bx
		int 21H
		add ax,ax
		loop s
codesg ends
end start

offset

操作符offset在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址。比如下面的程序:
assume cs:codesg
codesg segment
	start:mov ax,offset start;相当于mov ax,0
		s:mov ax,offset s;相当于mov ax,3
codesg ends
end start

jmp short s jmp far s

跳转到s位置
jmp short s 
机器码显示距离
jmp far s
机器码显示距离地址

jmp dword ptr

功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。
内存单元地址可用寻址方式的任一格式给出。
比如,下面的指令:
mov ax,0123H
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]

数组

data1    dd 0, 1, 2, 4                 ;
相当于 int data1[] = { 0, 1, 2, 3 };
data1[1]是内存地址+1(不论什么类型都是1个字节)

lea

lea是“load effective address”的缩写
简单的说,lea指令可以用来将一个内存地址直接赋给目的操作数
例如:lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。
而mov指令则恰恰相反,例如:mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。

5.11输出hello world

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'hello world','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
		mov ax,data
		mov ds,ax
		lea dx,str		
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start

5.12字符串转大写

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'hello world','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,11
	s:
		mov al,[bx]
		and al,1011111B
		mov [bx],al
		inc bx
		loop s
		
		;mov dx,offset str
		lea dx,str		
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start







5.13字符串转小写

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'hello world','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,11
	s:
		mov al,[bx]
		or al,0100000B
		mov [bx],al
		inc bx
		loop s
		
		;mov dx,offset str
		lea dx,str		
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start

















5.14求数组最小值

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'hello world','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,11
	mov ah,0FFH
	s:
		mov al,[bx]
		cmp ah,al
		jna s1
		mov ah,al
	s1:
		mov [bx],al
		inc bx
		loop s
		
		;mov dx,offset str
		lea dx,str		
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start


















5.15求数组最大值

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'hello world','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,11
	mov ah,0
	s:
		mov al,[bx]
		cmp ah,al
		jnb s1
		mov ah,al
	s1:
		mov [bx],al
		inc bx
		loop s
		
		;mov dx,offset str
		lea dx,str		
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start

















5.21数组求和

assume cs:code,ds:data,ss:stack
data segment 
	arr db 1,2,3,4,10,20,30,40
	res db 8 dup (0)
data ends

stack segment 
	
	db 100 dup (0)
stack ends

code segment 
	start:
		mov ax,data
		mov ds,ax
		
		mov bx,0
		mov cx,8
		for:
			add al,arr[bx]
			inc bx
		loop for
			
		mov ax,4c00H
		int 21
code ends
end start


5.22拷贝数组

assume cs:code,ds:data,ss:stack
data segment 
	arr db 1,2,3,4,10,20,30,40
	res db 8 dup (0)
data ends

stack segment 
	
	db 100 dup (0)
stack ends

code segment 
	start:
		mov ax,data
		mov ds,ax
		
		mov bx,0
		mov cx,8
		for:
			mov al,arr[bx]
			mov ds:res[bx],al
			inc bx
		loop for
			
		mov ax,4c00H
		int 21
code ends
end start



5.23用si,di翻转数组

assume cs:code,ds:data,ss:stack
data segment 
	arr db 1,2,3,4,10,20,30,40
	res db 8 dup (0)
data ends

stack segment 
	
	db 100 dup (0)
stack ends

code segment 
	start:
		mov ax,data
		mov ds,ax
		
		mov si,0
		mov di,7
		mov cx,8
		for:
			mov al,arr[si]
			mov ds:res[di],al
			inc si
			dec di
		loop for
			
		mov ax,4c00H
		int 21
code ends
end start



5.31用栈翻转数组

assume cs:code,ds:data,ss:stack
data segment 
	arr dw 1111H,2222H,3333H,4444H,5555H,6666H,7777H,8888H
	res db 800 dup (0)
data ends

stack segment 
	db 1000 dup (0)
stack ends

code segment 
	start:
		mov ax,data
		mov ds,ax
		mov ax,stack
		mov ss,ax
		mov sp,100

		mov bx,0
		mov cx,8
		for:	
			push ds:arr[bx]
			add bx,2
 		loop for

		mov bx,0
		mov cx,8
		for1:	
			pop ds:arr[bx]
			add bx,2
 		loop for1

			
		mov ax,4c00H
		int 21
code ends
end start




5.32动态规划求斐波那契数列

assume cs:code,ds:data,ss:stack
data segment 
	arr dw 1H,1H,100 dup (0)
	res db 800 dup (0)
data ends

stack segment 
	db 100 dup (0)
stack ends

code segment 
	start:
		mov ax,data
		mov ds,ax
		mov ax,stack
		mov ss,ax
		
		mov bx,4
		mov cx,30
		for :
			mov dx,0
			add dx,ds:arr[bx-2]
			add dx,ds:arr[bx-4]
			mov ds:arr[bx],dx
		add bx,2
		loop for
			
		mov ax,4c00H
		int 21
code ends
end start






5.41循环把二维矩阵某一列转大写

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc ','$'

data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,4
		for:
			mov al,ds:str[bx+5]
			and al,11011111B
			mov ds:str[bx+5],al
	add bx,16
	loop for
		
	lea dx,str		
	mov ah,9
	int 21H

	mov ah,4cH
	int 21H
codesg ends
end start















5.42二重循环把指定矩形转大写

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc '
	db 'aaaaabbbbbccccc ','$'

data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,4
	for:
	      mov dx,cx
		mov si,0
		mov cx,5
		for1:
			mov al,ds:str[bx+si]
			and al,11011111B
			mov ds:str[bx+si],al
		inc si
		loop for1
	     mov cx,dx
	add bx,16
	loop for
		
	lea dx,str		
	mov ah,9
	int 21H

	mov ah,4cH
	int 21H
codesg ends
end start


















5.51冒泡排序

assume cs:codesg,ds:data,ss:stack
data segmeNT
	arr db 0A2H,24H,07H,3AH,1BH,0F1H,3BH,25H,81H

data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
	mov ax,data
	mov ds,ax
	
	
	mov bx,0
	mov cx,8
	for:
	      mov dx,cx
		mov si,8
		mov cx,8
		sub cx,bx
		for1:
			mov ah,ds:arr[si]
			mov al,ds:arr[si-1]
			cmp ah,al
			jnb all
				xchg ah,al
				mov ds:arr[si],ah
				mov ds:arr[si-1],al				
	
			all:
				
		dec si
		loop for1
	     mov cx,dx
	add bx,1
	loop for

	mov ah,4cH
	int 21H
codesg ends
end start















5.61十进制转16进制

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db '00012345','$'
data ends
stack segment
	db 10 dup (0) 
stack ends
codesg SEgment
	start:	
		mov ax,data
		mov ds,ax

		mov bx,0
		mov cx,8
		mov ax,0
		s:
			mov dx,ax
			shl ax,1
			shl ax,1	
			shl ax,1
			shl dx,1
			add ax,dx
;乘10

			add al,str[bx]
			adc ah,0
			sub ax,30H		
		
			inc bx 
			loop s
	



		mov ah,4cH
		int 21H
codesg ends
end start








5.61十进制转16进制并输出

assume cs:codesg,ds:data,ss:stack
data segmeNT
	str db '00002333','$'
	res db '0000','$'
data ends
stack segment
	db 100 dup (0) 
stack ends
codesg SEgment
	start:	
		mov ax,data
		mov ds,ax
		mov ax,stack
		mov ss,ax		
		mov sp,10
		mov si,4

		mov bx,0
		mov cx,8
		mov ax,0
		s:
			mov dx,ax
			shl ax,1
			shl ax,1	
			shl ax,1
			shl dx,1
			add ax,dx
;乘10

			add al,str[bx]
			adc ah,0
			sub ax,30H		
		
			inc bx 
			loop s
		
;ax=3039
	
		mov cx,4
		l:
			mov dx,ax
			and dx,0FH
			add dx,30H
			cmp dx,3AH
			jb s1
			add dx,7H
;求出3039的ASCII码,push
		s1:
			dec si
			mov ds:res[si],dl
			shr ax,1
			shr ax,1
			shr ax,1
			shr ax,1
			loop l

		;mov dx,offset res
	 	lea  dx,res
		mov ah,9
		int 21H

		mov ah,4cH
		int 21H
codesg ends
end start











  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanlangke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值