当前位置: 首页 > news >正文

汇编语言学习(四)——汇编语言程序

目录

一、伪指令

二、程序返回

三、汇编语言结构

 四、[...]的规定和(...)的约定

五、Loop指令


一、伪指令

        在汇编语言源程序中,包含两种指令,一种时汇编指令,一种是伪指令。汇编指令是有对应的机器码的指令,可以被编译为机器指令,最终为cpu所执行。伪指令没有对应的机器指令,最终不被cpu所执行。

assume cs:codesgcodesg segmentmov ax, 0123Hmow bx, 0456Hadd ax,bxmov ax,4c00Hint 21H
codesg ends
end

(1) segment 和 ends

段名 segment

        段体内容

段名 ends

        segemt用于定义一个逻辑段的开始, ends用于定义一个逻辑段的结束。它告诉汇编器程序的某一部分将被组织为一个段,该段可以是代码段、数据段或堆栈段。

(2)end

        end是一个汇编程序的结束标记。若程序结尾处不加end,编译器在编译程序时,无法知道程序在何处结束。

(3)assume

assume 段寄存器: 段名

        assume 伪指令用于将特定用途的段与相关的段寄存器关联起来。它告诉汇编器在访问段内变量时,应该使用哪个段寄存器。

二、程序返回

mov ax, 4c00h
int 21h

         这两条指令的作用是安全退出程序,并返回到 DOS 的控制台。这是大多数汇编语言程序的结尾部分,用于确保程序在执行完毕后不会继续运行或占用资源。

三、汇编语言结构

(1)在debug中直接编写汇编程序

  • 可以直接在命令行中输入汇编指令,无需编写复杂的源文件格式。这种方式适合功能简单、短小精悍的程序;
  • 在debug中直接执行、调试和修改程序,无需经过编译和链接过程,调试效率高;

 (2)单独编写源文件后通过编译器生成可执行文件

  • 源文件可以使用文本编辑器编写,便于组织和管理,适合编写复杂、大型程序;
  • 编译器可以对源代码进行优化,生成更高效的机器码;
  • 编译器可以识别并处理伪指令,帮助程序员组织程序结构;
  • 通过编译器生成的可执行文件可以在不同平台上运行,只要目标平台支持相应的编译器和链接器;
特性在DEBUG中直接编写单独编写源文件后编译
适用场景简单、短小程序复杂、大型程序
是否需要伪指令
调试方式直接调试需要编译、链接后调试
代码效率
环境依赖DOS环境现代操作系统
学习成本
适合开发阶段初期快速验证中后期结构化开发

 四、[...]的规定和(...)的约定

(1)[...]——表示一个内存单元

        一个完整的内存单元,需要两种信息:a.内存单元的地址(段地址:偏移地址),b.内存单元的长度(或者字节);

        内存单元的长度可以由具体指令中的其他操作对象(比如寄存器)指出;

        [...]的默认地址为ds,偏移地址为“...”;

指令段地址偏移地址内存单元长度
mov ax,[0]DS0
mov al,[0]DS0字节
mov ax,[bx]DSbx寄存器中
mov al,[bx]DSbx寄存器中字节

 (2)(...)——表示一个内存单元或寄存器中的内容(为了方便学习做出的约定)

        “()”中的元素可以有3种类型:寄存器名、段寄存器名、内存单元的物理地址(一个20位的数据)

描述对象描述方法
ax中的内容为0010H(ax)=0010H
mov ax,[2]的功能(ax)=((ds)*16+2)
add ax,2功能(ax)=(ax)+2
push ax功能

(sp)=(sp)-2

((ss)*16+(sp))=(ax)

2000:1000处的内容为0010H(210000H)=0010H
mov [2],ax 功能((ds)*16+2)=(ax)
add ax,bx功能(ax)=(ax)+(bx)
pop ax的功能

(ax)=((ss)*16+(sp))

(sp)=(sp)+2

(3)约定符号idata表示常量

        mov ax,[idata]         代表mov ax,[1] 、mov ax,[2] 、mov ax,[3] 等;

        mov ax,idata           代表mov ax,1]、mov ax,2 、mov ax,3 等;

        mov ds,idata           代表mov ds,1、mov ds,2 、mov ds,3 等,为非法指令;

 (4)Debug和汇编编译器对指令的不同处理

        Debug将[idata]解释为一个内存单元;编译器将[idata]解释为idata;

任务:将内存2000:0、2000:1、2000:2、2000:3单元中的数据送入al,bl,cl和dl中(1)在Debug中编程实现
mov ax,2000
mov ds,ax
mov al,[0]
mov bl,[1]
mov cl,[2]
mov dl,[3](2)汇编源程序实现
assume cs:code
code segmentmov ax,2000mov ds,axmov al,[0]mov bl,[1]mov cl,[2]mov dl,[3] mov ax,4c00hint 21hcode ends
end 

        a.在汇编源程序中,如果在“[]”里用一个常量idata直接给出内存单元的偏移地址,在“[]”的前面显式地给出段地址所在的段寄存器;

        b.如果在“[]”里用寄存器,则段地址默认为ds,可以不显示的给出段地址所在的段寄存器;

五、Loop指令

(1)功能:实现循环(计数型循环)

 loop 标号

        作用:

                递减 CX 寄存器:在执行 loop 指令时,CPU 会自动将 CX 寄存器的值减 1。

                判断循环条件:如果 CX 不为零,则跳转到指定的 标号 处继续执行循环体;如果 CX 为零,则不跳转,继续执行后续指令。

(2)CPU执行loop指令时要进行的操作

       a. (cx)=(cx)- 1;

       b.判断cx中的值

                不为零则转至标号处执行程序;

                如果为零则向下执行;

(3)实例程序

assume cs:codecode segmentmov ax,2mov cx,11
s:add ax,axloop smov ax,4c00hint 21h
code ends
end

  (4)loop 指令与 [bx] 的结合使用   

    [bx] 是一种内存寻址方式,表示通过 BX 寄存器中的偏移地址访问内存单元。loop 指令可以与 [bx] 结合使用,实现动态访问内存中的数据。

在汇编语言中,当我们需要将内存地址 ffff:0 到 ffff:b(共 12 个字节)中的 8 位数据累加到 16 位寄存器 dx 中时,会面临两个关键问题:

  1. 结果溢出:如果直接使用 8 位寄存器 dl 来存储累加结果,由于 12 个 8 位数据的总和最大为 12 × 255 = 3060,超过了 dl 的最大值 255,因此会导致溢出。

  2. 类型不匹配:如果尝试将 8 位数据直接加到 16 位寄存器 dx 中,由于 dx 是 16 位寄存器,而 add 指令要求两个操作数类型一致,这种直接相加会导致类型不匹配的问题。

为了解决这两个问题,通常采用以下方法:

  • 使用 16 位寄存器作为中介:将内存中的 8 位数据先加载到 16 位寄存器 ax 中,然后将 ax 的内容加到 dx 中。这样可以确保两个操作数的类型一致,同时避免溢出。

  • 循环控制:使用 loop 指令配合 [bx] 寄存器,实现对内存单元的逐个访问和累加,从而高效地完成整个累加过程。

实例演示l


assume cs:code
code aegmentmov ax,0ffffhmov ds,axmov bx,0       ;初始化ds:bx指向ffff:0mov dx,0       ;初始化累加寄存器dx,(dx)=0mov cx,12      ;初始化循环计数寄存器cx,(cx)=12s:mov al:[bx]mov ah,0add dx,ax      ;间接向dx中加上((ds)*16+(bx))单元的数值inc bx         ;ds:bx指向下一个单元loop smov ax,4c00hint 21h
code ends
end

    

http://www.xdnf.cn/news/1035163.html

相关文章:

  • 微信小程序使用图片实现红包雨功能
  • 算法专题八: 链表
  • scanf 读取字符串
  • 本地密码生成管理工具,自定义生成密码
  • Vue3组件生成唯一标识符方法
  • 16.vue.js watch()和watchEffect()的对比?(追踪依赖)(3)
  • 华为OD机考-货币单位换算-字符串(JAVA 2025B卷)
  • CMake 构建系统概述
  • LeetCode - 153. 寻找旋转排序数组中的最小值
  • Hive SQL执行流程深度解析:从CLI入口到执行计划生成
  • 计网复习知识(16)传输层及其协议功能
  • 贝塞尔曲线:优雅的数学艺术
  • C# 解析 URL URI 中的参数
  • OpenWrt | 解决NTFS格式的硬盘意外断电之后无法再次挂载的问题
  • 轻量免安装 透明背景图标一键提取,系统文件图标随取随用
  • NGINX 四层共享内存区同步模块实战 `ngx_stream_zone_sync_module`
  • qml显示svg矢量图形
  • FreeRTOS的低功耗Tickless模式
  • RLHF调参实战手册:实用Trick、现象排查与解决思路(持续更新)
  • 动态BGP服务器的用途都有什么?
  • Softhub软件下载站实战开发(二):项目基础框架搭建
  • 萌系盲盒陷维权风暴,Dreams委托David律所已立案,速避雷
  • 历史数据分析——贵州茅台
  • LeetCode[106]从中序和后序遍历序列构造二叉树
  • Sngine 4.0.4海外社交平台PHP源码 – 多语言支持短视频和博客订阅(源码下载)
  • [学习] 多项滤波器在信号插值和抽取中的应用:原理、实现与仿真(完整仿真代码)
  • 使用Three.js创建炫酷的3D玻璃质感动态效果
  • 大小端的区别
  • MiniCPM4端侧AI模型
  • 机器学习算法_支持向量机