
首先得了解汇编指令吧,其次得用机器的逻辑思考问题,明白其中的存储、累加、判断、转移等概念。
比如,1+2++100这样的问题,虽然我们可以给出公式计算,但机器并不知道,它只能知道,而且只能每次做一个加法,而且鉴于CPU的架构不能存所有的这些数值-如果这些数量不定的话更复杂,比如这些数是放在一个内存区域的,内存区域约定如下:第一个数表示总共有多少个数,后面是相应的数据,在这些数没有规律时是不能用公式的。
另外,许多CPU约定只有一个累加器(同时也是一个寄存器,假设它是寄存器AX),它允许从内存读一个数(MOV或者LD指令),只能进行内存数据加法(ADD [地址])。
于是我们只能这样,首先设置指针寄存器BX:
start: mov BX,#地址 ; 设置内存区域起始地址,保存在BX中
mov CX,[BX]; 取出总数到CX中,假设CX可以做简单递增或递减
dec CX ; 预减一次计数器,因为加法只需做CX-1次
inc BX
mov AX, [BX]; 取出数据
loop: inc BX ;递增BX,使之指向真实数据
ADD AX,[BX];用下一数据进行累加,并将结果保存在AX中
dec CX ;假定这个减法会影响标志位ZF
JNZ loop ;如果没有减到0就继续loop到这里之间的 *** 作
mov [BX], AX; 保存累加结果到数据区的尾部
HALT ; 停机
可以看出,上述代码并不能告诉我具体结果是多少,除非我们通过工具去访问这一内存区域,于是一个系统会设计出来专门让我们进行基本的输入输出,把计算机的内部情况甚至内存情况通过I/O口送出来,这些IO设备,比如键盘负责接收我们的机器指令(可以是汇编结果,也可以是高级语言产生的二进制指令和数据流),把结果输出到打印机或者CRT这样的输出设备上(通常映射为端口,IO PORT)。这就是BIOS完成的工作,如int 8负责时钟,int 10负责屏幕,int 16负责键盘等等。更进一步,可以进一步封装称DOS调用,如int 21负责基本的输入输出包括文件 *** 作等等。WINDOWS等 *** 作系统则通过驱动层进行多级抽象提供 *** 作界面给编程人员,编程人员再进一步封装出对话框或全屏文字菜单或流式(行式 *** 作) *** 作界面给最终用户。
data segment
INPUT db 'The ASCII code of $'
OUTPUT db ' is $'
msg db 0dh,0ah,'is 0DH $'
A db 0
data ends
code segment
start proc far
assume cs:code,ds:data
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
AGAIN: MOV DX,OFFSET INPUT
MOV AH,9
INT 21H
MOV AH,1
INT 21H
cmp al,0dh
jz tj
MOV A,AL
MOV AH,9
MOV DX,OFFSET OUTPUT
INT 21H
mov bl,a
mov bh,0
call dispa;以十进制形式显示ASCII码
mov dl,0dh
mov ah,2
int 21h
mov dl,0ah
mov ah,2
int 21h
jmp again
tj:
lea dx,msg
mov ah,9
int 21h
mov ah,1
int 21h
ret
start endp
dispa proc near
mov cx,100d
call dec_div
mov cx,10d
call dec_div
mov cx,1d
call dec_div
ret
dec_div proc near
mov ax,bx
mov dx,0
div cx
mov bx,dx
mov dl,al
add dl,30h
mov ah,2
int 21h
ret
dec_div endp
dispa endp
code ends
end start
ORG 0000H
AJMP MAIN
ORG 0030H
MAIN: MOV SP,#0X80
LCALL CX
AJMP $
//返回值在R7中
CX:
MOV R0,#0X40
MOV R7,#0
CX1: MOV A,@R0
CJNE A,#0X01,CX2
MOV R7,#1
AJMP CX_OUT
CX2: INC R0
MOV A,R0
CJNE A,#0X7F+1,CX1
CX_OUT: RET
END
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN:
MOV R0,#30H
MOV 20H,#0
LOOP:
MOV A,@R0
CJNE A,#13,LOOP1
SJMP LOOPE
LOOP1:
CJNE A,#'a',LOOP2
INC 20H
LOOP2:
INC R0
SJMP LOOP
LOOPE:
SJMP $
END
;在MASM 615下编译通过
data segment
msg1 db 'Input String1:$'
msg2 db 'Input String2:$'
msg3 db 'Found str2 in str1 at:$'
msg4 db 'str2 not in str1',0dh,0ah,'str1+str2=$'
str1 db 255;输入缓冲区大小
db ;实际输入的字符数
db 255 dup();存贮STRING1
str2 db 255
db
db 255 dup();存贮STRING2
Pos db 3 DUP('$');用来存位置对应的数字字符串(16进制形式),第一个字符位置为00H
data ends
sta segment stack
db 1024 dup(0)
sta ends
CRLF macro;输出回车换行符
mov ah,02h
mov dl,10
int 21h
mov ah,02h
mov dl,13
int 21h
endm
code segment
assume cs:code,ds:data,es:data,ss:sta
FindInStr proc far
;入口参数
;[bp+8]=string2的开始地址
;[bp+6]=string1的开始地址
;[bp-2]=string2的长度,字节
;[bp-4]=string1的长度,字节
;[bp-6]=string1位置变量,字
;[bp-8]=最大查找次数,字节
;出口:AL=如果STR2在STR1中,则为第一次匹配时的位置,如果没找到,则为0FFH
push bp
mov bp,sp
add sp,-8
cld
;局部变量初始化
mov si,[bp+8]
mov di,[bp+6]
mov [bp-6],di
mov al,[si-1]
mov [bp-2],al
mov al,[di-1]
mov [bp-4],al
sub al,[bp-2]
inc al
mov [bp-8],al
mov cl,[bp-8]
xor ch,ch
LP_CMP:
push cx
mov si,[bp+8]
mov di,[bp-6]
mov cl,[bp-2]
xor ch,ch
repe cmpsb
jne Next
mov ax,[bp-6]
sub ax,[bp+6]
jmp RetHere
Next:
inc byte ptr [bp-6]
pop cx
loop LP_CMP
mov al,0FFH
RetHere:
mov sp,bp
pop bp
ret 4
FindInStr endp
TRANBUFF proc far;转化16进制数字串,入口参数AL=位置
CLD
XOR AH,AH
MOV BL,16
DIV BL
LEA DI,Pos
CMP AL,0AH
JB L1
ADD AL,37H
JMP L2
L1:
ADD AL,30H
L2:
STOSB
MOV AL,AH
CMP AL,0AH
JB L3
ADD AL,37H
JMP L4
L3:
ADD AL,30H
L4:
STOSB
ret
TRANBUFF endp
start:
mov ax,data
mov ds,ax
mov es,ax
mov ah,09h
lea dx,msg1
int 21h;显示Input String1:
mov ah,0ah
lea dx,str1
int 21h;用户输入STRING1
CRLF
mov ah,09h
lea dx,msg2
int 21h;显示Input String2:
mov ah,0ah
lea dx,str2
int 21h;用户输入STRING2
CRLF
lea ax,str2+2
push ax
lea ax,str1+2
push ax
call FindInStr
cmp al,0FFH
jz NoMatch
call TRANBUFF
mov ah,09h
lea dx,msg3
int 21h
mov ah,09h
lea dx,Pos
int 21h;显示找到的位置
jmp DONE
NoMatch:
cld
lea si,str2+2
lea di,str1
add di,2
xor ax,ax
mov al,str1+1
add di,ax
xor ax,ax
mov al,str2+1
mov cx,ax
rep movsb
mov byte ptr [di],'$'
mov ah,09h
lea dx,msg4
int 21h
mov ah,09h
lea dx,str1+2
int 21h;显示str2连接到str1后合并的字符串
DONE:
mov ax,4c00h
int 21h
code ends
end start
首先创建一个工程:Create a new project -> ConsoleApplication -> 填上工程文件名和project路径 -> 调试器和编译器默认。
随便在工程里写点什么代码,比如下面的一个递归代码为例:
#include "stdioh"
#include "mathh"
int factorial(int n);
int main(void)
{
int n, rs;
printf("请输入斐波那契数n:");
scanf("%d",&n);
rs = factorial(n);
printf("%d \n", rs);
return 0;
}
// 递归
int factorial(int n)
{
if(n <= 2)
{
return 1;
}
else
{
return factorial(n-1) + factorial(n-2);
}
}
点击“菜单栏 Debug -> Debugging windows -> disassembly”,把汇编窗口呼出来。
设定断点。就是设置查看汇编的那一段代码。在代码的左边(代码行)右键就可以设定调试断点了。
点击调试,就可以看到汇编代码了。如下:
如果想看指针或数组,可以编辑watch窗口,定义你想watch变量的类型。有很多窗口,自己可以多探索尝试。
以上就是关于如何快速看懂汇编语言程序全部的内容,包括:如何快速看懂汇编语言程序、汇编:编写ASCII码的查询程序、80c51单片机中,写一段汇编程序 在40H~7FH 中查找 一个数01H 若存在等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)