2. 第一个程序、BX和loop指令

第一个程序、BX和loop指令

一个汇编源程序需要经过编译、链接生成可执行文件。可执行文件包括两个部分:1)程序和数据。2)相关的描述信息(如程序有多大、占用多少内存空间等)。

1 源程序

先给出一个简单的范例:

sql 复制代码
 assume cs:codesg
 ​
 codesg segment
 ​
         mov ax, 0123H
         mov bx, 1456H
         add ax, bx
         add ax, ax
         
         mov ax, 4c00H
         int 21H
         
 codesg ends
 ​
 end

在汇编语言源程序中,包含两种指令。一种是汇编指令,可以被编译为机器指令;另外一种是伪指令,由编译器执行。上述代码中出现了三种伪指令。

segment 和 ends是一对成对使用的伪指令,它的功能是定义一个段。一个段必须有一个名称来标识,使用格式为:

复制代码
 段名 segment
 ​
 段名 ends

一个汇编程序由多个段组成,这些段被用来存放代码、数据或当作栈来使用。同时一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。

end是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了指令end,就结束对源程序的编译。

注意:end是标记整个程序的结束;而ends是标记一个段的结束,并且与segment成对使用。

assume指令可以把段寄存器和一个具体的段相联系。

2 程序返回

我们的程序经编译、链接后转变为机器码,存储在可执行文件上。那么它是如何运行的呢?

一个单任务DOS系统为例:

一个程序P2在可执行文件中,则必须由一个正在运行的程序P1,将P2从可执行文件中加载如内存后,将CPU的控制权交给P2,P2得以运行。P2开始运行后,P1暂停运行。而当P2运行完毕后,将CPU的控制权交还给P1。

arduino 复制代码
 mov ax, 4c00H
 int 21H

这两条指令所实现的功能就是程序返回。

3 实验三

重点理解一下实验的第三个小问。

程序在被加载到内存后,DS中存放着程序所在内存区的段地址 ,这个内存区的偏移地址为0,则程序所在的内存区的地址为DS:0

这个内存区的前256个字节用来存放的是PSP,是DOS用来和程序进行通信的

所以CS指向的地址应该比DS指向的地址大10H。

4 [bx]和内存单元的描述

bx\]和\[0\]类似,都是代表内存单元。只不过\[0\]代表偏移地址是0,\[bx\]代表偏移地址是寄存器bx中的值。 > * **在汇编源程序中当直接给出数字时,不能是字母开头。所以类似A023H的数字必须在前面加一个0,即0A023。** > * 形如 mov ax, \[0\] 这样的汇编语句,本意是地址为ds:0的数据送入寄存器ax,但是debug程序和汇编解释器对它的解释不一致。汇编解释器对上面的语句解释为: mov ax, 0 ,想要执行我们的预期结果需要改用如下形式:***mov ax, ds:\[0\]或者是 mov bx, 0 mov ax, \[bx\]*** 定义一个描述性的符号:"()",它表示一个寄存器或内存单元中的内容。如: (ax)表示寄存器ax中的内容、(al)表示寄存器al中的内容。 (20000H)表示内存20000H单元的内容。那么((ds)\*16 + (bx))表示:ds中的ADR1作为段地址,bx中的ADR2作为偏移地址,即ADR1:ADR2单元的内容。 > 注意:"( )"中的元素可以有3种类型:\*\*1)寄存器名;2)段寄存器名;3)内存单元的物理地址(一个20位的数据) ### 5 Loop指令 loop指令的格式是:loop 标号,CPU指令loop指令的时候,要进行两部操作,1) **(cx) = (cx) - 1** , 2)**判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。** 也就是说,cx的值影响loop指令的执行结果,**cx中存放的是循环次数**。 如编程计算2\^12的值: ```arduino assume cs:codesg ​ codesg segment mov ax, 2 mov cx, 11 s: add ax, ax loop s mov ax, 4c00H int 21H code ends ​ end ``` 计算ffff:0006单元中的数乘以3,结果存储在dx中。 ```less assume cs:code ​ code segment mov ax, 0ffffH mov ds, ax mov cx, 3 mov dx, 0 mov ah, 0 mov al, ds:[0006H] s: add dx, ax loop s mov ax, 4c00H int 21H code ends ​ end ``` 这道题需要注意以下几点: * 循环结构不要冗余,比如取数这个操作不要放到循环里。 * **注意ffff:6是一个字节单元,而ax是16位寄存器,数据长度不一样需要适配。** * 有的题目要注意数据溢出的可能。 ### 6 在debug中跟踪用loop指令实现的循环程序 在debug中通过"u cs: 偏移地址"可以查看内存中汇编指令,可以发现**loop指令其实就是通过改变IP寄存器的内容来实现循环。** 具体的调试不难,此时引入两个新的debug命令。 * g 偏移地址,可以避免t命令一条一条的执行,直接执行到指定地址。如"g 0012", CS:0012之前的程序段被执行 * 遇到loop指令用p命令,可以直接一次性执行循环体。 ### 7 loop和\[bx\]的联合应用 考虑这样一个问题,计算ffff:0\~ffff:b单元中数据的和,结果存储在dx中。 注意细节如下: * 运算后的结果是否会超过dx的存储范围? * 能否把ffff:0\~ffff:b中的数据直接累加到dx中? * 我们能否将ffff:0\~ffff:b中的数据累加到dl中,并设置(dh) = 0,从而实现累加到dx中? ```less assume cs:code ​ code segment mov ax, 0ffffH mov ds, ax mov cx, 0bH mov dx, 0 mov bx, 0 mov ah, 0 s: mov al, [bx] add dx, ax inc bx loop s code ends ​ end ``` ### 8 段前缀的使用 指令" mov ax, \[bx\]"中默认的段地址寄存器是ds,但实际上我们可以在访问内存单元的指令中显示的给出内存单元的段地址所在的寄存器。 我们考虑一个问题,将内存ffff:0~~ffff:b单元中的数据复制到0:200~~0:20b中。分析过程如下: * **0:200~~0:20b单元等同于0020:0~~0020:b单元**,它们描述的是同一段内存空间。 ```less assume cs:code ​ code segment ​ mov ax, 0ffffH mov ds, ax mov ax, 0020H mov es, ax mov bx, 0 mov cx, 12 s: mov dl, [bx] mov es:[bx], dl inc bx loop s ​ mov ax, 4c00H int 21H ​ code ends ​ end ``` ### 9 实验四 0. 编程,像内存0:200~~0:23F依次传送数据0~~63(3FH)。 ```less assume cs:code ​ code segment ​ mov ax, 0020H mov ds, ax mov cx, 3FH mov bx, 0 s: mov [bx], bx inc bx loop s mov ax, 4c00H int 21H ​ code ends ​ end ``` 2. 下面的程序的功能是将"mov ax, 4c00H"之前的指令复制到内存0:200处,补全程序上机调试。跟踪运行结果。 ```less assume cs:code code segment mov ax, cs mov ds, ax mov ax, 20H mov es, ax mov bx, 0 mov cx, 17H s: mov al, [bx] mov es:[bx], al inc bx loop s mov ax, 4c00H int 21H code ends end ``` **寄存器cx的值需要debug去查看前面的指令占多少字节。**

相关推荐
hui函数2 小时前
Flask电影投票系统全解析
后端·python·flask
小厂永远得不到的男人4 小时前
基于 Spring Validation 实现全局参数校验异常处理
java·后端·架构
毅航8 小时前
从原理到实践,讲透 MyBatis 内部池化思想的核心逻辑
后端·面试·mybatis
展信佳_daydayup8 小时前
02 基础篇-OpenHarmony 的编译工具
后端·面试·编译器
Always_Passion8 小时前
二、开发一个简单的MCP Server
后端
用户721522078778 小时前
基于LD_PRELOAD的命令行参数安全混淆技术
后端
笃行3508 小时前
开源大模型实战:GPT-OSS本地部署与全面测评
后端
知其然亦知其所以然8 小时前
SpringAI:Mistral AI 聊天?一文带你跑通!
后端·spring·openai
庚云8 小时前
🔒 前后端 AES 加密解密实战(Vue3 + Node.js)
前端·后端
超级小忍9 小时前
使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
java·spring boot·后端