【新书推荐】19.1 DOS程序段前缀PSP

本节内容:介绍DOS程序段前缀及其应用。

         ■程序段前缀PSP:DOS系统加载程序时,在程序段前设置一个具有256字节的信息区称为程序段前缀PSP。

         ■终止程序的另一途径:利用程序段前缀PSP偏移地址0处的“INT 20H”终止程序。示例代码t19-1.asm。

         ■应用程序取得命令行参数:DOS系统通过程序段前缀PSP的偏移80H处获取命令行参数。示例代码t19-2.asm、t19-3.asm。

19.1.1 程序段前缀PSP

程序段前缀是DOS加载一个外部命令或应用程序(EXE或COM类型)时,在程序段之前设置的一个具有256字节的信息区。

DOS程序段前缀PSP含有许多可用信息,其中常用信息的安排如表19.1所示:

偏移

内容及意义

偏移

内容及意义

00H

程序终止退出命令INT 20H

16H

保留

02H

可用的内存空间高端段值

2CH

环境块段值

04H

保留

2EH

保留

05H

DOS系统功能远调用指令

5CH

格式化的未打开的文件控制块1

0AH

程序处理中断向量原内容

6CH

格式化的未打开的文件控制块2

0EH

Ctrl+C键处理中断向量原内容

80H

命令行参数长度(字节数)

12H

严重错误处理中断向量原内容

81H

命令行参数

                                                表19-1 程序段前缀PSP的常用信息

当DOS把控制权转给外部命令或应用程序之时,数据段寄存器DS和附加段寄存器ES均指向其PSP,即均含有PSP的段值,而不是指向程序的数据段或附加段。这样应用程序可方便的使用PSP中的有关信息,参见例1。

如图19-1所示,debug调试器刚加载test.exe程序时,段寄存器DS和ES的值均为075AH。从075A:0开始的256个字节就是程序段前缀PSP区域。请读者对照表19-1,了解程序段前缀PSP区域的内容。需要特别关注的是偏移地址0处的INT 20H和偏移地址80H处的命令行参数,其他内容这里不再赘述。

                                                图19-1 程序段前缀PSP

19.1.2 终止程序的另一途径

回顾一下我们前面写过的所有程序,都是利用DOS的4CH号系统功能调用能够终止程序,然后把控制权转交回DOS。但早期是利用DOS提供的20H号中断处理程序来终止程序的。

       通过20H号中断处理终止程序有一个条件,即进入20H中断处理程序之前,代码段寄存器CS必须含有PSP的段值。由于对EXE类型的应用程序而言,其代码段和PSP段不是同一个段,所以不能简单的直接利用指令“INT 20H”来终止程序。DOS系统注意到了这一点,在PSP的偏移0处,安排了一条“int 20h”指令(机器码CD 20)。于是,应用程序只要转到PSP的偏移0处,就能实现程序的终止。请看下面的例子。

例1:INT 20H退出程序

动手实验111写一个显示字符串'HELLO'的程序。要求使用INT 20H退出程序。

在理解下面示例程序的基础上,自己独立编写源程序。编译完成后,在debug调试器中单步跟踪调试,以验证程序的正确性。

算法分析:

使用ret指令转移到DOS段前缀PSP的 int 20H处退出程序。

示例代码87

;程序名:t19-1.asm

;功能:显示信息'HELLO'

;INT 20H

;---------------------------------

assume cs:code,ds:data,ss:stack

stack segment

         dw 256 dup(?)

stack ends

data segment

mess db 'HELLO',0dh,0ah,'$'

data ends

code segment

main proc far

start:

         push ds              ;把PSP的段值压入堆栈

         xor ax,ax

         push ax             ;把0000H偏移压入堆栈

         ;

         mov ax,data

         mov ds,ax

         mov dx,offset mess

         mov ah,9

         int 21h

         ret                      ;转PSP的偏移0处执行        

main endp

        

code ends

end start

标号start开始处的三条指令将PSP的段值和偏移压入堆栈,最后返回指令RET从堆栈弹出程序开始时压入堆栈的PSP段值和偏移0到CS:IP,随后CPU就执行位于PSP首的“INT 20H”,此时CS含PSP的段值,程序终止,控制返回DOS。

提示

注意main proc far远过程伪指令,对应的返回指令ret,masm编译时当作远过程返回指令,TASM汇编时,则必须使用RETF指令。

不鼓励采用这种特殊形式,建议使用int 21H  4ch指令退出程序。

19.1.3 应用程序取得命令行参数

DOS加载一个外部命令或应用程序时,允许在被加载的程序名之后,输入多达127个字符(包括最后的回车符)的参数,并把这些参数送到PSP的非格式化参数区,即PSP中从偏移80H开始的区域。

应用程序可从PSP中获得命令行参数。PSP的偏移80H处含命令行参数的长度(字节数),从PSP的偏移81H开始存放命令行参数。通常以空格符引导,至回车符(0dh)结束。注意:命令行中的重定向符和管道符及有关信息不作为命令行参数送到PSP。

例2:显示命令行参数

动手实验112写一个显示命令行参数的程序。

在理解下面示例程序的基础上,自己独立编写源程序。编译完成后,在debug调试器中单步跟踪调试,以验证程序的正确性。

算法分析:

先从PSP中把命令行参数传到程序定义的缓冲区,然后再显示。

示例代码88

;例1:写一个显示命令行参数的程序

;程序名:t19-2.asm

;先从PSP中把命令行参数传到程序定义的缓冲区,然后再显示。

;--------------------------------------------------------------

assume cs:code,ds:code

code segment

buffer db 128 dup(?)        ;存放命令行参数的缓冲区

start:

         cld

         mov si,80h

         lodsb                  ;取得命令行参数的长度,字节数

         mov cl,al

         xor ch,ch

         push cs              ;该程序数据和代码在同一个段中

         pop es

                   mov di,offset buffer

         push cx

         rep movsb         ;传命令行参数

         pop cx

         ;

         push es

         pop ds                ;置数据段寄存器

         mov si,offset buffer

         mov ah,2

         jcxz over

next:

         lodsb                  ;显示命令行参数

         mov dl,al

         int 21h

         loop next

over:

         mov ax,4c00h

         int 21h     

code ends

end start

注意

1.必须输入命令行参数才会显示:

                                     图19-2显示命令行参数

2.没有输入命令行参数和输入命令行参数对比:

                        图19-3 没有命令行参数与有命令行参数对比

例3:命令行参数给出文件名

动手实验113写一个显示文本文件内容的程序,文件名作为命令行参数给出。

在理解下面示例程序的基础上,自己独立编写源程序。编译完成后,在debug调试器中单步跟踪调试,以验证程序的正确性。

算法分析:

第一步:从DOS程序段前缀PSP中取出文件名命令行参数;

第二步:打开文件;

第三步:读取文件内容;

第四步:关闭文件。

示例代码89

;例3:写一个显示文本文件内容的程序。文件名作为命令行参数给出。

;程序名:t19-3.asm

;功能:显示文本文件的内容

;=======================================================

assume cs:code,ds:data

;符号常量定义

lenofid=128               ;文件标识符最大长度

space=' '                     ;空格

tab=09h

eof=1ah

data segment

fname db lenofid dup(?)           ;准备存放的文件名串

error0 db 'Required parameter missing',0

error1 db 'File not found',07h,0       ;提示信息07h=响铃

error2 db 'Reading error',07h,0

buffer db ?                 ;1字节的缓冲区

data ends

code segment

start:

         cld

         mov si,80h

         lodsb                            ;取命令后参数长度

         or al,al                        ;是否有命令行参数

         jnz getfid1                  ;有

fiderr:

         mov ax,seg error0   ;没有命令行参数处理

         mov ds,ax

         mov si,offset error0

         call dmess

         jmp over

getfid1:

         mov cl,al

         xor ch,ch                    ;cx含命令行参数长度

getfid2:

         lodsb                            ;取参数一字节

         cmp al,space             ;为空格

         jz getfid3                    ;是,跳过

         cmp al,tab                 ;为制表符?

         jnz getfid4                  ;不是,表示已去掉前导空格       

getfid3:

         loop getfid2               ;跳过前导空格和制表符

         jmp fiderr                   ;命令行参数没有其他符号,转

getfid4:

         dec si                           ;字符串指令自动+1,需要回退1

         mov ax,seg fname   ;把剩下的命令行参数送入

         mov es,ax

         mov di,offset fname

         rep movsb                           ;文件标识符区

         xor al,al

         stosb                                     ;再补一个0,形成ASCIIZ串

         ;

         mov ax,data

         mov ds,ax

         ;

         mov dx,offset fname        ;置文件名首地址

         mov ax,3d00h                     ;只读方式打开文件

         int 21h

         jnc open_ok                        ;CF=0打开成功转

         mov si,offset error1          ;打开失败

         call dmess                            ;显示打开不成功提示信息

         jmp over                              ;结束

open_ok:

         mov bx,ax                           ;保存文件柄

;从文件中读取一个字符

cont:

         call readch                          ;从文件中读取一个字符

         jc readerr                            ;如读错,则转

         cmp al,eof                         ;读到文件结束符?

         jz type_ok

         call putch                            ;显示所读字符

         jmp cont 

readerr:

         mov si,offset error2

         call dmess                           ;显示错误提示信息                

type_ok:

         mov ah,3eh                        ;关闭文件

         int 21h

over:

         mov ax,4c00h

         int 21h

;--------------------------------------------------   

;子程序 ,屏幕显示al内容

;2号调用功能,向屏幕写入dl内容

;入口参数dl

putch proc

         push dx

         mov dl,al

         mov ah,2

         int 21h

         pop dx

         ret

putch endp

;--------------------------------------------------

;子程序:从文件中读取一个字符

;子程序名:readch

readch proc

         mov cx,1                              ;置读字节数

         mov dx,offset buffer        ;置读缓冲区地址

         mov ah,3fh                          ;置功能调用号

         int 21h

         jc readch2                            ;cf=1

         cmp ax,cx          ;判断文件是否结束,ax为实际读到的字节数

         mov al,eof        ;设文件已结束,置文件结束符,此时CF=0

         jb readch1        ;文件已结束,转

         mov al,buffer   ;文件结束,取所读字符

readch1:

         clc

readch2:

         ret

readch endp

;--------------------------------------------------

;子程序显示一个以0结尾的字符串

;子程序名:dmess

;入口参数si=字符串首地址

;出口参数无

dmess proc

dmess1:

         mov dl,[si]

         inc si

         or dl,dl

         jz dmess2

         mov ah,2

         int 21h

         jmp dmess1

dmess2:

         ret   

dmess endp

        

code ends

end start

注意

1.文件名必须是零结尾的字符串。

2.取命令行参数时,需要考虑过滤掉前导空格。

本文摘自编程达人系列教材《X86汇编语言基础教程》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/446809.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

每日五道java面试题之springMVC篇(二)

目录: 第一题. 请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?第二题. MVC是什么?MVC设计模式的好处有哪些?第三题. 注解原理是什么?第四题. Spring MVC常用的注解有哪些?第五题. SpingMvc中的…

Java EE之wait和notify

一.多线程的执行顺序 由于多个线程执行是抢占式执行,就会导致顺序不同,同时就会导致出现问题,就比如俩个线程同时对同一个变量进行修改,我们难以预知执行顺序。 但在实际开发中,我们希望代码按一定的逻辑顺序执行&am…

HTML5 Web Worker之性能优化

描述 由于 JavaScript 是单线程的,当执行比较耗时的任务时,就会阻塞主线程并导致页面无法响应,这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程(称为工作线程)中执行耗时的任务。这使得 JavaScript 代码可…

Node.js:构建高性能网络应用的利器

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

吴恩达机器学习-可选实验室:逻辑回归,决策边界(Logistic Regression,Decision Boundary))

文章目录 目标数据集图数据逻辑回归模型复习逻辑回归和决策边界绘图决策边界恭喜 目标 在本实验中,你将:绘制逻辑回归模型的决策边界。这会让你更好地理解模型的预测。 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_co…

基于WEB的服务器运行状态的监控分析系统

摘要: 随着云计算和电子商务规模的扩大和复杂性的增加,企业数据中心Web服务器数量急剧增加,用户对网络性能的要求也越来越高,导致企业和用户对数据中心的通信服务稳定性和快速响应要求越来越高。本作品提供一套行之有效的Web服务器性能监控系…

RabbitMQ - 05 - Direct交换机

部署demo项目 通过消息队列demo项目进行练习 相关配置看此贴 http://t.csdnimg.cn/hPk2T 注意 生产者消费者的yml文件也要配置好 什么是Direct交换机 Direct 交换机是 AMQP(高级消息队列协议)中的一种交换机类型,它根据消息的路由键&am…

【R语言】R包-探索ggtree进化树美化

文章目录 R包-探索ggtree进化树美化分析流程1. 关于包的下载2. 绘制一个基本的进化树图3. 添加样本名称3. 添加节点节点高亮4. 添加分组小结 R包-探索ggtree进化树美化 提示:基于nwk文件进行进化树美化,如更换进化树格式,添加分组、节点、遗传…

【大厂AI课学习笔记NO.78】智能芯片产业人才能力图谱

有志于从事智能芯片产业的朋友,可以参考下上面的图谱。 比如C站的程序猿很多,那么技能能力中,你要掌握的就包括C/C、Python、Bash等常用的编程语言。 还要熟悉TensorFlow、PyTorch等主流的深度学习框架。 这两个框架,我们都介绍…

SpringSecurity两种验证方式及调用流程

一、HttpBasic方式 <security:http-basic/> 二、Formlogin方式 <security:form-login login-page"/userLogin" /> 三、SpringSecurity执行流程

论文阅读《FENET: FOCUSING ENHANCED NETWORK FOR LANE DETECTION》

ABSTRACT 受人类驾驶专注力的启发&#xff0c;这项研究开创性地利用聚焦采样&#xff08;Focusing Sampling&#xff09;、部分视野评估&#xff08;Partial Field of View Evaluation&#xff09;、增强型 FPN 架构和定向 IoU 损失&#xff08;Directional IoU Loss&#xff…

uniapp:小程序数字键盘功能样式实现

代码如下&#xff1a; <template><view><view><view class"money-input"><view class"input-container" click"toggleBox"><view class"input-wrapper"><view class"input-iconone"…

01hadoop概念

大数据与Hadoop 大数据指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 Hadoop是什么&#xff1f; Hadoop是一种分析和处理海量数据的…

OD_2024_C卷_200分_8、攀登者2【JAVA】【逻辑分析】

package odjava;import java.util.Arrays; import java.util.HashSet; import java.util.Scanner;public class 八_攀登者2 {// 输入处理public static void main(String[] args) {Scanner sc new Scanner(System.in);int[] heights Arrays.stream(sc.nextLine().split("…

驱动开发常见的通信接口介绍

本文将为您详细讲解驱动开发中常见的通信接口&#xff0c;以及它们的特点、区别和应用场景。在操作系统和硬件设备之间&#xff0c;通信接口扮演着至关重要的角色&#xff0c;它们定义了数据如何在软件和硬件之间传输和交互。 1. 串行通信接口&#xff08;Serial Communication…

防御保护作业六

实验拓扑图&#xff1a; 配置过程&#xff1a; FW1 自定义服务ike 创建nat策略&#xff0c;让10.0.2.0/24访问192.168.1.0/24的流量不进行nat转换,并将这条策略置于nat策略最上面&#xff0c;优先匹配 FW3 测试

CodeReview 规范及实施

优质博文&#xff1a;IT-BLOG-CN 一、为什么需要CodeReview 随着业务压力增大&#xff0c;引发代码质量下降&#xff0c;代码质量的下降导致了开发效率的降低&#xff0c;维护成功高等问题&#xff0c;开发效率下降后又加重了业务压力&#xff0c;最终陷入了死亡三角的内耗之…

Shell常用脚本:文件或目录一键同步到多台服务器

注意&#xff1a; 将本地文件&#xff0c;同步到【/opt/module/script/xsyncByFileIp.txt】里面的目标机器 xsyncByFile.sh #!/bin/bash# 入参参数个数 argsCount$#if(($argsCount0)); thenecho "同步失败&#xff1a;请输入待同步的文件或者目录" exit; fiecho &q…

【大厂AI课学习笔记NO.68】开源和开源发展情况

开源即源代码公开&#xff0c;任何人能获取源代码&#xff0c;查看、修改、分发他们认为合适的代码。 依托同行评审和社区生成&#xff0c;旨在以分散、协作的方式开发。 我们曾经很详细的讨论过开源协议的问题&#xff0c;详细可以参考我的文章&#xff1a; https://giszz.…

OpenCV的常用数据类型

OpenCV涉及的常用数据类型除包含C的基本数据类型,如&#xff1a;char、uchar&#xff0c;int、unsigned int,short 、long、float、double等数据类型外, 还包含Vec&#xff0c;Point、Scalar、Size、Rect、RotatedRect、Mat等类。C中的基本数据类型不需再做说明下面重点介绍一下…