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

news2024/10/2 16:18:28

本节内容:介绍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汇编语言基础教程》。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第三百九十二回

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何混合选择多个图片和视频文件"相关的内容,本章回中将介绍如何通过相机获取图片文件.闲话休提,让我们一起Talk Flutter吧。 1. …

NoSQL--3.MongoDB配置(Linux版)

目录 2.2 Linux环境下操作 2.2.1 传输MongoDB压缩包到虚拟机: 2.2.2 启动MongoDB服务: 2.2 Linux环境下操作 2.2.1 传输MongoDB压缩包到虚拟机: (笔者使用XShell传输) 如果不想放在如图的路径,删除操作…

【Python使用】python高级进阶知识md总结第2篇:HTTP 请求报文,HTTP响应报文【附代码文档】

python高级进阶全知识知识笔记总结完整教程(附代码资料)主要内容讲述:操作系统,虚拟机软件,Ubuntu操作系统,Linux内核及发行版,查看目录命令,切换目录命令,绝对路径和相对…

(001)UV 的使用以及导出

文章目录 UV窗口导出模型的主要事项导出时材质的兼容问题unity贴图导出导出FBX附录 UV窗口 1.uv主要的工作区域: 2.在做 uv 和贴图之前,最好先应用下物体的缩放、旋转。 导出模型的主要事项 1.将原点设置到物体模型的底部: 2.应用修改器的…

【SpringCloud】微服务重点解析

微服务重点解析 1. Spring Cloud 组件有哪些? 2. 服务注册和发现是什么意思?Spring Cloud 如何实现服务注册和发现的? 如果写过微服务项目,可以说做过的哪个微服务项目,使用了哪个注册中心,常见的有 eurek…

跨平台大小端判断与主机节序转网络字节序使用

1.macOS : 默认使用小端 ,高位使用高地址,转换为网络字节序成大端 #include <iostream> #include <arpa/inet.h> int main() {//大小端判断union{short s;char c[sizeof(short)];}un;un.s = 0x0102;printf("低地址:%d,高地址:%d\n",un.c[0],un.c[1]);if …

腾讯云8核16G服务器支持多少人同时访问?性能和价格测评

腾讯云8核16G轻量服务器CPU性能如何&#xff1f;18M带宽支持多少人在线&#xff1f;轻量应用服务器具有100%CPU性能&#xff0c;18M带宽下载速度2304KB/秒&#xff0c;折合2.25M/s&#xff0c;系统盘为270GB SSD盘&#xff0c;月流量3500GB&#xff0c;折合每天116.6GB流量&…

STM32---ADC

ADC 概念 众所周知&#xff0c;GPIO只能读入高电平或者低电平&#xff0c;那如果现有一个模拟量&#xff0c;该如何读取呢&#xff0c;比如电压的范围是0~3.3v&#xff0c;如何获取电压的值。就需要ADC&#xff08;Analog-Digital Converter&#xff09;了。ADC可以将引脚上连…

童装WP模板

童装WP模板 https://www.wpniu.com/moban/6359.html

学习和认知的四个阶段,以及学习方法分享

本文分享学习的四个不同的阶段&#xff0c;以及分享个人的一些学习方法。 一、学习认知的四个阶段 我们在学习的过程中&#xff0c;总会经历这几个阶段&#xff1a; 第一阶段&#xff1a;不知道自己不知道&#xff1b; 第二阶段&#xff1a;知道自己不知道&#xff1b; 第三…

在 Python 中加速卫星时间合成的生成️

基于 fastnanquantile 库计算基于分位数的时间复合的更快方法 简要背景 为了从卫星图像创建时间合成图像,我们通常只获取云量低于特定阈值(例如 40%)的图像,遮盖云和云阴影,并随时间聚合图像。例如,如果我们一年中有 50 张图像(在云层覆盖限制内以及云/阴影遮罩之后),…

【经管数据-更新】华证ESG评级得分数据(2009-2023年)

一、数据说明 参考《经济研究》中方先明&#xff08;2023&#xff09;的做法&#xff0c;将华证ESG评级进行赋值&#xff0c;指标包含C、CC、CCC、B、BB、BBB、A、AA、AAA共9个等级&#xff0c;将上市公司ESG 等级从低到高分别赋值为1至9 二、数据来源&#xff1a;世界银行&am…

Linux多线程之线程控制

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目录 一、pthread_crate 二、pthread_join 三、p…

diffusion model(十三):DiT技术小结

infopaperhttps://arxiv.org/abs/2212.09748githubhttps://github.com/facebookresearch/DiT/tree/main个人博客主页http://myhz0606.com/article/ditcreate date2024-03-08 阅读前需要具备以下前置知识&#xff1a; DDPM(扩散模型基本原理)&#xff1a;知乎地址 个人博客地址…

英伟达jetson nano第一次进入镜像配置

我所用产品为jetbot Ubuntu18.04LTS CtrlAltT启动终端 设置分辨率 xrandr –output HDMI-0 –mode “1920x1080” 最好在设置中重新配置下 不然重启又得调 联网-更新语言包 reboot重启

【Tauri】(5):本地运行candle和 qwen 大模型,并测试速度

1&#xff0c;本地运行candle 关于candle项目 https://github.com/huggingface/candle Hugging Face 使用rust开发的高性能推理框架。 语法简单&#xff0c; 风格与 PyTorch 相似。 CPU 和 Cuda Backend&#xff1a;m1、f16、bf16。 支持 Serverless&#xff08;CPU&#xff…

【二分】第十二届蓝桥杯省赛第一场C++ B组/C组《杨辉三角形》(c++)

【题目描述】 下面的图形是著名的杨辉三角形&#xff1a; 如果我们按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如下数列&#xff1a; 1&#xff0c;1&#xff0c;1&#xff0c;1&#xff0c;2&#xff0c;1&#xff0c;1&#xff0c;3&#xff0c;3&…

Orange3数据预处理(转换器组件)

该组件接收数据&#xff0c;然后重新应用之前在模板数据上执行的转换。 这些转换包括选择变量的子集以及从数据中出现的其他变量计算新的变量&#xff0c; 例如&#xff0c;离散化、特征构建、主成分分析&#xff08;PCA&#xff09;等。 在Orange3中&#xff0c;描述的这个组件…

python爬虫(4)

#前期先说明一下为啥爬虫需要学习数组的存储和处理&#xff0c;只是说在你后期接触到最简单的爬虫后有一个地方可以存放你的数据# 下面为大家带来一个我在做excel表整理时的代码以及上次代码的结果 上次代码的结果&#xff1a; 新的代码&#xff1a; import numpy as np im…

使用python翻转图片

原图 代码 from PIL import Imagedef flip_image(image_path):# 打开图片with Image.open(image_path) as img:# 获取图片的模式&#xff08;RGB/RGBA/其他&#xff09;mode img.mode# 创建一个新图片&#xff0c;模式与原图一样&#xff0c;大小为原图的翻转大小flipped_img…