(九)《汇编语言(王爽)》 | 实验 5:编写、调试具有多个段的程序

2024-01-05 18:08

本文主要是介绍(九)《汇编语言(王爽)》 | 实验 5:编写、调试具有多个段的程序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(1)编写下述程序并运行,然后用 Debug 加载、跟踪。

assume cs:code,ds:data,ss:stack
data segment	;数据段dw 0123H,0456H,0789H,0abch,0defh,0fedh,0cbah,0987H
data ends
stack segment	;栈段dw 0,0,0,0,0,0,0,0
stack ends
code segment	;代码段
start:	mov ax,stackmov ss,axmov sp,16		;定义一个空栈mov ax,datamov ds,axpush ds:[0]		;入栈push ds:[2]		;入栈pop ds:[2]		;出栈后元素放到数据段data中,偏移地址为2pop ds:[0]		;出栈后元素放到数据段data中,偏移地址为0mov ax,4c00h	;程序返回int 21h
code ends
end start	;start标号处作为程序入口
  • CPU 执行程序,程序返回前,data 段中的数据为 没有变化

end start 指明程序将标号 start 作为程序入口,代码段部分分为以下功能:定义空栈,设置寄存器 DS 的值,两次入栈,两次出栈。由于两次入栈出栈的地址逆序,且都是针对 DS 操作,所以以寄存器 DS 为标识的代码段部分数据没有改变。

  • CPU 执行程序,程序返回前,cs= 076C、ss= 0769、ds= 075A

程序加载后,系统为代码段、数据段和栈段自动分配内存空间,空间的段地址分别由代码段寄存器 CS栈段寄存器 SS数据段寄存器 DS 表示。直接使用 Debug 加载程序后,使用 r 指令查看各段寄存器的内容即可。

请添加图片描述

  • 设程序加载后,code 段的段地址为 X,则 data 段的段地址为 X-2,stack 段的段地址为 X-1。使用 d 指令查看数据段的内容:

请添加图片描述
在 076A:0~076A:F 这段内存存放了数据段,共 16 个字节;栈段的段地址为 076B,如果偏移为零,则可以写作 076A:10,而上图中恰好有连续 10 个字节的零,与定义的栈段内容相符,为证实这一结论,使用 u 指令查看 076A:20 的汇编指令内容:

请添加图片描述
这部分恰好是定义的代码段部分,所以 076A:10~076A:1F 部分是定义的栈段,后面 6 字节系统自动做了填充,以 16 字节对齐。由此得知,系统以各段的定义顺序为各段分配空间,并且空间以 16 字节对齐

(2)编写下述程序并运行,然后用 Debug 加载、跟踪。

assume cs:code,ds:data,ss:stack
data segment		;数据段dw 0123H,0456H
data ends
stack segment		;栈段dw 0,0
stack ends
code segment		;代码段
start:	mov ax,stackmov ss,axmov sp,16		;定义一个栈mov ax,datamov ds,axpush ds:[0]		;入栈push ds:[2]		;入栈pop ds:[2]		;出栈后元素放到数据段data中,偏移地址为2pop ds[0]		;出栈后元素放到数据段data中,偏移地址为0mov ax,4c20h	;程序返回int 21h
code ends
end start
  • CPU 执行程序,程序返回前, data 段中的数据为 前 4 个字节存放定义的数据、后面为填充数据

请添加图片描述

  • CPU 执行程序,程序返回前,cs= 076C、ss= 076B、ds=076A
  • 设程序加载后,code 段的段地址为 X,则 data 段的段地址为 X-2,stack 段的段地址为 X-1
  • 对于如下定义的段:
name segment...
name ends

如果段中的数据占 N 个字节,则程序加载后,该段实际占有的空间为 N/16*16+(N%16!=0)*16

前面由实验得知,各段的大小在实际存储时有 16 字节的对齐。所以,当 N 能整除 16 时,该段实际占用空间为 N;当 N 不能整除 16 时,占有的空间向上 16 字节对齐。

(3)编写下述程序并运行,然后用 Debug 加载、跟踪。

assume cs:code,ds:data,ss:stack
code segment	;代码段
start:	mov ax,stackmov ss,axmov sp,16		;定义一个栈mov ax,datamov ds,axpush ds:[0]		;入栈push ds:[2]		;入栈pop ds:[2]		;出栈后元素放到数据段data中,偏移地址为2pop ds:[0]		;出栈后元素放到数据段data中,偏移地址为0mov ax,4c00h	;程序返回int 21h
code ends
data segment	;数据段dw 0123H,0456H
data ends
stack segment	;栈段dw 0,0
stack ends
end start
  • CPU 执行程序,程序返回前, data 段中的数据为

这段程序与上段程序不同的是,数据段、代码段和栈段的定义顺序不同。根据寄存器的段地址可知,各段的存放顺序与定义顺序相同,即先代码段、然后数据段、最后栈段。根据下一题的答案,076A0~076CF 部分存放代码段,076D:0 ~076D:F 部分存放数据段,076E:0~076E:F 部分存放栈段。

请添加图片描述

  • CPU 执行程序,程序返回前,cs= 076A、ss= 076E、ds= 076D

请添加图片描述

  • 设程序加载后,code 段的段地址为 X,则 data 段的段地址为 X+3,stack 段的段地址为 X+4

(4)如果将上面三题中最后一条伪指令 end start 改为 end,则哪个程序仍可以正确执行。

end start 指明程序入口为 start 标号处,没有指明程序入口时程序将从加载的第一条指令开始执行,所以只有(3)能够正确运行。这里也可以看出,代码和数据在内存中的存放形式都是一致的,关键是编写代码的人去控制 CPU 执行指令实为指令的代码、使用实为数据的代码。所以,在编写程序时最好指定程序入口。

(5)编写 code 段中的代码,将 a 段和 b 段中的数据依次相加,将结果存到 c 段中。

assume cs:code
a segment		;段adb 1,2,3,4,5,6,7,8	;使用dw定义时以字为单位,使用db定义时以字节为单位
a ends
b segment		;段bdb 1,2,3,4,5,6,7,8
b ends
c segment		;段cdb 0,0,0,0,0,0,0,0
c ends
code segment	;代码段
start:	?		;待完成部分
code ends
end start
  • 题目要求将两个段 a 和 b 的内容依次相加,将相加结果存入另一个段 c 中,每个段的大小都是 8 个字节。即,考虑首先将段 a 的内容复制到 段 c 中,然后再将段 b 和段 c 的内容相加,在代码部分使用两个循环。
  • 首先,我们需要使用段寄存器指向某个段,段寄存器有 CS、DS、SS、ES,CS 用于代码段的管理、SS 用于栈段的管理,这里使用 DS 和 ES 两个段寄存器。待完成部分:
	mov ax,amov ds,ax	;使用段寄存器DS指向段amov ax,cmov es,ax	;使用段寄存器ES指向段cmov cx,8	;定义循环次数,一共有8个字节的数据mov bx,0	;定义偏移量
s1:	mov al,ds:[bx]	;每次处理1个字节mov es:[bx],alinc bx			;每次偏移1个字节loop s1			;第一个循环完成将段a的内容复制到段cmov ax,b		;移动mov ds,ax		;使用段寄存器DS指向段bmov cx,8		;定义循环次数,一共有8个字节的数据mov bx,0		;定义偏移量
s2:	mov al,ds:[bx]	;每次处理1个字节add es:[bx],al	;相加inc bx			;每次偏移1个字节loop s2			;第二个循环完成段b和段c的内容相加mov ax,4c00h	;程序返回int 21h

先使用指令 g 跳转到 076D:0010 处查看段 a 和 段 c 的内容:

请添加图片描述
执行完第一次循环后查看段 c 的内容:

请添加图片描述
查看段 b 的内容和执行完第二次循环后查看段 c 的内容:

请添加图片描述

(6)编写 code 段中的代码,用 push 指令将 a 段中的 word 数据,逆序存储到 b 段中。

assume cs:code
a segmentdw 1,2,3,4,5,6,7,8
a ends
b segmentdw 0,0,0,0,0,0,0,0
b ends
code segment
start:	?
code ends
end start
  • 题目要求逆序存放,利用栈先进后出的特点即可。由于入栈时栈顶寄存器 SP 的值减小而出栈时 SP 的值增大。所以,直接将段 a 中的数据入栈,同时将段 b 作为栈段,即可将段 a 中的字数据逆序存放到段 b 中。
	mov ax,amov ds,ax	;使用段寄存器DS指向段amov ax,bmov ss,ax	;使用段寄存器SS指向段bmov sp,16	;初始化空栈,SP指向栈顶的下一个位置mov cx,8	;循环次数mov bx,0	;偏移量
s:	push ds:[bx]add bx,2	;每次偏移一个字loop smov ax,4c00h;程序返回int 21h

先使用指令 g 跳转到 076C:0013 处查看循环前段 a 和 段 c 的内容(暂不清楚栈为什么栈段部分不全为零):

请添加图片描述

执行循环后段 c 的内容:

请添加图片描述

这篇关于(九)《汇编语言(王爽)》 | 实验 5:编写、调试具有多个段的程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/573708

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完