首页 > 编程语言 >汇编程序语言设计的一些小点

汇编程序语言设计的一些小点

时间:2023-11-05 22:47:12浏览次数:38  
标签:语言 db mov 汇编程序 cx 小点 offset DATA 21h

汇编学的时间好短,尽力速成一下程序设计,其他就靠背了

DOS功能调用

 1 - 键盘输入
- 2 - 屏幕输出 
- 3 - 辅助输入
- 4 - 辅助输出
- 5 - 打印器输出
- 6 - 直接控制台输入/输出
- 7 - 直接控制台输入,不回显
- 8 - 读取键盘不回显
- 9 - 显示字符串

- 0Ah -Buffered键盘输入

- 0Bh - 检查键盘输入

-4ch-结束正在运行的程序直接返回DOS

 当作一个模块来做

mov ah, 2    ; 功能号 2 - 输出字符
mov dl, al
int 21h      ; 输出

 

 1. mov ah, 2   设置ah寄存器为2,这对应DOS中断INT 21h的输出字符功能号。

2. mov dl, al   将al寄存器中的字符移动到dl寄存器中。DOS 21h号中断的输出字符功能需要将要输出的ASCII字符存放在dl寄存器中。

3. int 21h     触发DOS中断INT 21h,调用ah寄存器所指定的输出字符功能,将dl寄存器中的ASCII字符输出到屏幕上。

简单记一下就好

我们记住以上的模块就可以做相应的输入输出

PS:当我们输出字符串的时候,需要有$作为结尾,否则会超量输出

简单代码阅读

 

.486

DATA SEGMENT USE16

    MESG1 db 'PLEASE INPUT YOUR USER: $'  
    MESG2 db 'PLEASE INPUT YOUR PASSWORD: $'
    U db 15  
    db ?
    db 15 dup(?)     
    PWD db 15 
    db ?
    db 15 dup(?)                  
    USER db '123'
    ULEN equ $-USER        
    PASSWORD db '0'
    MLEN equ $-PASSWORD   

    WELCOME db '-----------WELCOME!-----------$' 
    ERROR db '------ERROR!------$'

DATA ends

CODE SEGMENT USE16
assume CS:CODE, DS:DATA  

START:
    mov ax, DATA
    mov ds, ax

PRINT_USERNAME:  
    mov ah, 9    
    mov dx, offset MESG1
    int 21h

GET_USERNAME:   
    mov ah, 0Ah
    mov dx, offset U  
    int 21h
          
PRINT_NEWLINE:             ;换行
    mov ah, 2
    mov dl, 0ah      
    int 21h

PRINT_PWD:
    mov ah, 9
    mov dx, offset MESG2   
    int 21h   

GET_PASSWORD:
    mov ah, 0Ah
    mov dx, offset PWD  
    int 21h

CHECK_USER_PWD:

                    ;检查用户名
mov bx, offset USER  
mov si, offset U+2
mov cx, 3

check_user:
mov al, [bx]
cmp al, [si]  
jne PRINT_ERROR

inc bx
inc si
dec cx       ; 减少循环计数器
jnz check_user ; 如果cx不为零,则继续循环

;检查密码
mov bx, offset PASSWORD
mov si, offset PWD+2
mov cx, 1
check_pwd:
mov al, [bx]
cmp al, [si]
jne PRINT_ERROR
inc bx  
inc si
dec cx       ; 减少循环计数器
jnz check_pwd ; 如果cx不为零,则继续循环
;检查完成,用户名密码正确  
jmp welcomeTo
PRINT_ERROR: 
mov ah, 2    ; 功能号 2 - 输出字符
mov dl, 10   ; ASCII码值为10,表示换行
int 21h      ; 输出换行字符

mov ah, 9
mov dx, offset ERROR
int 21h

mov ah, 2    ; 功能号 2 - 输出字符
mov dl, 10   ; ASCII码值为10,表示换行
int 21h      ; 输出换行字符
jmp START
welcomeTo:
mov ah, 2    ; 功能号 2 - 输出字符
mov dl, 10   ; ASCII码值为10,表示换行
int 21h      ; 输出换行字符

mov ah, 9
mov dx, offset WELCOME  
int 21h

EXIT: 
mov ah, 4Ch
int 21h

CODE ends
end START

 

以上这段代码没有使用ULEN和MLEN但进行了定义,这是对用户名长度和密码长度进行比较的,这段代码没有加入这部分

DATA SEGMENT USE16
   ; 数据定义
DATA ends

CODE SEGMENT
  assume CS:CODE, DS:DATA
; 代码主体
CODE ends

end START

 

我们首先看一下以上这段代码的结构或者框架,如上

.486就不说了

然后就是

DATA SEGMENT 
   ; 数据定义
DATA ends

这段数据定义后接着是代码段

CODE SEGMENT
  ; 代码主体
CODE ends

在代码段之后,我们就要指定整个程序的入口点

也就是

end START

从我刚才的描述可以发现,这里的START是指定的,它叫什么都无所谓,也可以叫常规的BEG,也可以叫abcd

因为我们迟早会指定一个标签

刚才的整段代码段分成下面的部分

 ; 打印用户名段
    PRINT_USERNAME:
       ; 打印提示用户名的消息 

    ; 获取用户名段   
    GET_USERNAME:
      ; 调用DOS获取用户名存入缓冲区

    ; 打印密码段
    PRINT_PWD:
      ; 打印提示密码的消息
    
    ; 获取密码段
    GET_PASSWORD:
       ; 调用DOS获取密码存入缓冲区

    ; 检查验证段  
    CHECK_USER_PWD:
       ; 检查用户名密码是否匹配

    ; 输出结果段  
    PRINT_RESULT:
       ; 根据检查结果打印成功或失败消息 

    ; 结束段
    EXIT:
      ; 程序退出前的收尾工作

 

当我们将这些分开之后,相关的功能就可以分开解决了

这些都是标签名,并不影响代码的运行,反而是大家都爱用的NEXT等等这些会可读性很差

初始化的问题

START:
    mov ax, DATA
    mov ds, ax

 

这里的就是将DATA段地址转入ax,再用ax初始化ds

不要直接转入ds

 

键盘输入与输出

阅读了我刚才的代码,可以发现我在DATA提供了

U db 15  
    db ?
    db 15 dup(?)

 

这是用以键盘输入的一个结构

mov ah, 0Ah
    mov dx, offset U  
    int 21h

 

这里对U进行输入

但字符串是存储在U+2的

所以我们在使用的时候是用

mov si, offset U+2

 

输出就以之前说的就好

cmp的一些问题

首先cmp自己有特定的使用要求

mov al, [bx]
cmp al, [si]

 

 在比较的时候不要使用两个[偏移地址]进行比较

循环的一些小问题

1. 循环计数循环:
mov cx, 5 ;循环次数

loop:
   ;循环体 
   dec cx
   jnz loop

 

2.利用cx寄存器作为计数器,执行循环体,dec指令递减cx,jnz判断cx是否为0,不为0则跳转继续循环。2. 标签循环:
begin:
   ;循环体
   jmp begin ;无条件跳转到begin标签

 

3.通过无条件跳转begin实现循环,begin标签标记循环位置。3. 比较循环:
mov cx, 0

cmp_loop:
  cmp cx, 5 ;比较计数器cx和5
  jl cmp_loop ;小于则跳转继续循环
  
  ;循环体
  inc cx ;计数器++

 

4.利用cmp和条件跳转jl实现计数器判断,控制循环执行。4. REP指令:
mov cx,5 ;循环次数

repeat:
  ;循环体

  rep repeat ;重复执行repeat循环

 

 REP前缀可以重复执行循环体,通过CX控制次数。

这里的标签依然是之前所说的,无所谓什么名字

甚至这里的循环都是通过指令实现的罢了并非坚固不可摧

剩下的就是一些简答输入输出问题

我们可以发现跟我们写一个普通程序一样,使用大脑的地方并不多

但剩下的地方需要你不断完善以合适用户真正的使用流程,这段代码比较用户名和密码的部分并不多

;检查用户名
mov bx, offset USER  
mov si, offset U+2
mov cx, 3

check_user:
mov al, [bx]
cmp al, [si]  
jne PRINT_ERROR

inc bx
inc si
dec cx       ; 减少循环计数器
jnz check_user ; 如果cx不为零,则继续循环

;检查密码
mov bx, offset PASSWORD
mov si, offset PWD+2
mov cx, 1;这里可以改成
MLEN
 check_pwd: mov al, [bx] cmp al, [si] jne PRINT_ERROR inc bx inc si dec cx ; 减少循环计数器 jnz check_pwd ; 如果cx不为零,则继续循环 ;检查完成,用户名密码正确  jmp welcomeTo

 

就这些部分罢了,其他都是满足用户流程

第二段代码

.486
DATA  SEGMENT USE16
  BUF db 'ABC6DED55BV99CADE77ABD5AERS2AV1BA$' ; 保存字符串的缓冲区
  count dw 0 ; 统计结果存放变量
DATA    ENDS
CODE   SEGMENT         USE16
         ASSUME CS:CODE,   DS:DATA
START:  
        MOV AX,                 DATA
        MOV DS,                  AX
        MOV DH,                 0H
        MOV BX,                 OFFSET BUF
        CMP BYTE PTR [BX], 42H
        JB   NEXT
        CMP BYTE PTR [BX], 45H
        JA  NEXT
        INC DH    ;首先判断第一个字符是否满足条件,满足了就DH加1
LAST:   
        INC BX    ;接着通过加BX继续判断后面的字符
        CMP BYTE PTR [BX], 42H
        JB   NEXT
        CMP BYTE PTR [BX], 45H
        JA  NEXT
        INC DH
NEXT:   CMP BYTE PTR [BX], 24H ;判断'$',结尾
        JNE LAST
        MOV CX,8
XUN:    ROL DH,1    ;开始进行左移位,循环判断输出0、1
        MOV DL,                 30H
        JNC CON
        INC DL
CON:    MOV AH,                 02H
        INT 21H
        LOOP    XUN
        MOV AH,                 4CH
        INT 21H
CODE    ENDS
         END START

 

简单解释几个代码

CMP BYTE PTR [BX], 42H
        JB   NEXT

 

这是一段比较的代码,下面的NEXT可以做到循环判断,不过也可以让地址+1在直接跳转到自己的标签位置,不需要使用两个标签做循环

汇编的代码相当自由

XUN:    ROL DH,1    ;开始进行左移位,循环判断输出0、1
        MOV DL,                 30H
        JNC CON
        INC DL
CON:    MOV AH,                 02H
        INT 21H
        LOOP    XUN
        MOV AH,                 4CH
        INT 21H

 

这里的输出没有像我之前说的那么模块化,少用了寄存器,这样当然更有优势

可读性上和写起来都要多想一层

1. XUN标签处是循环体,ROL DH,1实现了DH寄存器左移1位的逻辑运算。

2. JNC CON判断左移后最高位是否为1,如果是则不跳转,否则跳转到CON。

3. INC DL指令将DL寄存器的值+1,这里用于统计左移中1的个数。

4. CON标签输出当前DH的最低位,MOV DL,30H将DL预置为0,然后判断左移后最高位,如果为1则DL加1,记录1的个数。

5. 调用INT 21H中断打印DL的值,0或1。

6. LOOP XUN实现循环控制。

7. 最后调用INT 21H和INT 4CH结束程序。

 

 

这篇文章只是简单写了几个小点,并且很多地方并没有写的很细,只是为了着半个学期的课程做个小努力

标签:语言,db,mov,汇编程序,cx,小点,offset,DATA,21h
From: https://www.cnblogs.com/nish1hundun/p/17811406.html

相关文章

  • C++_01_初步认识C++语言 - 重写版
    一、认识“C++语言”一、首先聊聊什么是语言?语言是一套具有“语法”、“词法”规律的系统,是思维的工具。计算程序设计语言是计算机可以识别的语言,用于描述解决问题的方法,供计算机阅读和执行。语言由低级到高级依次分为4类:1、机器语言     (由......
  • B站C语言第11课——函数和递归
    1.工具cpulspuls.com  程序员知乎:stackoverflow.com232.递归——程序调用自身的编程技巧称为递归史上最简单的递归intmain(){ printf("hehe\n"); main(); return0;}递归常见的错误:栈溢出——例子1:#include<stdio.h>voidprintf(intn){if(n>9){print(n/10);}pr......
  • 实验3_C语言函数应用编程
    task1.c#include<stdio.h>#include<stdlib.h>#include<time.h>#include<windows.h>#defineN80voidprint_text(intline,intcol,chartext[]);//函数声明voidprint_spaces(intn);//函数声明voidprint_blank_lines(intn);//函数声......
  • C语言循环语句---其一
    一、while语句通常,我们可以用while语句实现一种循环,本质上就是满足条件后跳出循环,不满足条件则执行大括号中的语句。它的通常结构是这样的while(conditiom){code}比如,把1-100之间的偶数全部打印出来,就可以用这个代码intn=1while(n<=100){if(n%2==0)printf("%d",n);n++;}通常,还会......
  • 实验3 C语言函数应用编程
    实验任务1源代码:1#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);//函数声明8voidprint_spaces(intn);//函数声明9voidprint_blan......
  • 分治算法(C语言)
    一、棋盘覆盖问题1、问题2、分析(1)当k>0时,将2k×2k棋盘分割为4个(2k-1)×(2k-1)子棋盘,如图(a)所示。每一次分解,都将原本大小的棋盘,划分为四份,即行号和列号各自缩减一半。(2)特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。(3)为将无特殊方格子棋盘转化为特......
  • Go语言使用range修改值,需要使用切片的指针 &slice[index]
    由于Value是值拷贝的,并非引用传递,所以直接改Value是达不到更改原切片值的目的的,需要通过&slice[index]获取真实的地址packagemainimport("fmt")funcmain(){ slice:=[]int{10,20,30,40} forindex,value:=rangeslice{ fmt.Printf("Value=%d,value-addr......
  • go语言Context应用全讲解
    Go语言Context应用全攻略:异步编程利器原创 Go先锋 Go先锋 2023-11-0511:42 发表于广东收录于合集#Go语言包32个Go先锋读完需要17分钟速读仅需6分钟  概述在Go语言中,Context(上下文)是一个非常重要的概念,特别是在处理请求时。允许在请求的整个生命周期......
  • SATA基础+更改终端颜色+PCI.ids位置+Linux和Windows的scanf+C语言C++的局部变量与全局
    SATA基础https://zhuanlan.zhihu.com/p/554251608物理信号物理层功能时钟恢复:对于高频传输,一般是采用差分信号传输,并且没有单独的时钟,时钟存在于编码内部串并转换:对于高频传输,串联信号可以做到更高的频率。字节对其:8/10编码转换的10bit对其链路层、传输层链路层和传输......
  • 试验3 c语言函数应用编程
    实验任务1源代码1#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);8voidprint_spaces(intn);9voidprint_blank_lines(intn)......