对于MS-DOS和IBM-DOS(我使用的是后者),从地址80 h开始,内存中有一个保留部分用于沿着命令行参数。地址80 h是一个计数器,用于计算该长度,地址81 h是ASCII中参数的开始位置。问题是,这一记忆区域似乎很少真正像预期的那样工作。
当我用参数LOADME
加载到debug.com
中时,内存看起来有点像这样。
-D 80 8F
1039:0080 00 0D 4C 4F 41 44 4D 45-0D 00 00 00 00 00 00 00 ..LOADME........
这里的不一致是地址80 H,它应该包含一个计数器,但显然只读出一个0,尽管LOADME
是完整的。如果我向程序中输入一个更大的参数,事情只会变得更不一致。为了进行比较,下面是参数LOADME NOW
的外观。
-D 80 8F
1039:0080 04 20 4E 4F 57 0D 4D 45-20 4E 4F 57 0D 00 00 00 . NOW.ME NOW....
现在计数器读数为4,这更接近正确,但仍然不正确。此外,LOAD
已完全从参数列表中删除。我还废弃了两个程序,一个来自StackOverflow,另一个是我自己设计的。StackOverflow程序工作完美,能够输出正确的输入。
MOV AH, 40
MOV BX, 0001
XOR CH, CH
MOV CL, [0080]
MOV DX, 0081
INT 21 ; Write directly to device 1, with memory address 80h as your counter and your string beginning at 81
MOV AX, 4C00
INT 21 ; Exit
不管你给这个程序输入什么,它都能把准确的数据输出到屏幕上。不幸的是,除了复制echo命令之外,这种方法的使用非常有限。
反过来,我创建了这个程序,它可以让我复制81 H的内存部分,并尝试读取它。这个程序不能按预期的方式工作,而且在你运行它的时候,它大多数时候都是乱码。这可能是由于编程错误,因为这是我第一次在程序中进行无指导的尝试,但它有助于让我的观点得到理解。
XOR AX, AX ; Clearing out the registers.
XOR BX, BX
XOR CX, CX
XOR DX, DX
MOV DX, 0300 ; A variable offset that I left unused
MOV AX, [0080] ; The counter
MOV BX, 0080 ; The current read position
ADD BX, 01; Begin loop
MOV CX, [BX]
ADD BX, 0300 ; Jump to our offset
MOV [BX], CX
SUB BX, 0300 ; Remove our offset in memory.
DEC AX
JNZ 0111
ADD BX, 0301 ; Loop ended here.
MOV CX, 0024 ; Now, at the end of the string, add a $.
MOV [BX], CX
MOV AH, 09
MOV BX, 301
INT 21 ; Execute "display string"
MOV AX, 4C
INT 21 ; End program
它肯定会读取参数所在的位置,但忽略它倾向于覆盖参数所在的位置的事实,它似乎并不总是这样做,在擦除它们之前只 Flink 我期望输出的片段。
这真的是IBM-DOS的问题,还是debug.com
在捉弄我,我是一个糟糕的程序员?
1条答案
按热度按时间2w2cym1i1#
实际上这是正确的因为
80 h-命令行上的字节数
81 h-FFh-命令行尾部(以0 Dh结尾)
在第一示例中,0 Dh偏移是81 h,因此80 h = 0
在第二示例中,0 Dh偏移是85 h,因此80 h = 4
LOADME不是在当前目录中找到的程序名。
调试程序名参数
更新1:
Debug LOADME
偏移81 h看起来像:
(20h space)LOADME(0dh)
然后系统检查LOADME是否是文件的正确路径。它不是这样检查是否存在参数?不,没有更多的,所以0 dh在81 h打印。
(0dh)LOADME(0dh)
Debug LOADME NOW
偏移81 h看起来像:
(20h space)LOADME(20h space)NOW(0dh)
LOADME不是文件的正确路径,因此在81 h = 0 dh处打印此内容,现在缓冲区看起来像:
(0dh)LOADME(20h space)NOW(0dh)
并检查下一个输入,即(20 h空间)NOW(0 dh)。因此,覆盖,从81 h开始。
(20h space)NOW(0dh)ME(20h space)NOW(0dh)
更新2:
我不知道该加什么。我可以写东西,但如果这将是你的答案你在寻找?
DOS可以加载和执行两种类型的文件,com和exe。被执行的程序及其环境被称为进程。DOS一次只能运行一个进程。除了内存中的常驻程序。进程可以调用另一个进程暂时挂起它的工作。然后程序创建父子进程的层次结构。在大多数情况下,父节点是command.com。PSP中的偏移量16 h显示父进程的段,因此如果我运行debug.exe,则父进程段为0 b18(command.com)
``
如果我检查段0 b18,这确实是www.example.com的PSPcommand.com。父进程段是0 b18,这意味着command.com没有父进程。指向自身。
``
还有一种叫做DTA(磁盘传输区)的东西
Source Wikipedia
DTA的初始地址被设置为覆盖PSP中的区域(在地址0x 80),其中存储命令行参数,使得程序需要在调用利用DTA的DOS函数之前解析该区域以获得命令行参数(例如阅读文件记录),除非程序小心地将DTA的地址更改为其他内存区域(或者不完全使用DTA/FCB函数,这些函数很快就被弃用,转而支持文件句柄)。
您可以使用
ah=1ah int 21h
更改此设置,并请求DTA地址ah=2fh int 21h
。只是我发现,从来没有测试过这个功能。更新3:
如果我运行
debug testcode.exe -a abc -3
内存转储看起来像这样:``
这是testcode.exe,在偏移量81 h处,我们可以看到确切的参数列表。父进程位于此处05 89,它是debug.exe,偏移量为81 h的是debug的参数。
``
debug的父进程位于这里04 1 E,它是cmd.exe,因为我这次在windows下运行了它。
``