我试图了解MS-DOS v2.0 source code,尤其是MSDATA.ASM中的某些代码。该代码最初是使用35年以上的MASM汇编程序(该版本尚未在市场上出售)进行汇编的。我感兴趣的代码即将开始:
SUBTTL Initialized data and data used at DOS initialization
PAGE
; DATA AREA for MS-DOS
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
EXTRN international_table:BYTE
EXTRN Current_Country:WORD
ORG 0
CONSTRT EQU $ ; Start of constants segment
PUBLIC DevStrLen
DEVSTRLEN DB 3 ; Size of below
PUBLIC DevString
DEVSTRING DB "DEV" ; Dummy device directory
;
; Table of routines for assignable devices
;
; MSDOS allows assignment if the following standard devices:
; stdin (usually CON input)
; stdout (usually CON output)
; auxin (usually AUX input)
; auxout (usually AUX output)
; stdlpt (usually PRN output)
;
; SPECIAL NOTE:
; Status of a file is a strange idea. We choose to handle it in this manner:
; If we're not at end-of-file, then we always say that we have a character.
; Otherwise, we return ^Z as the character and set the ZERO flag. In this
; manner we can support program written under the old DOS (they use ^Z as EOF
; on devices) and programs written under the new DOS (they use the ZERO flag
; as EOF).
; Default FCBs for boot up
sftabl LABEL DWORD ; file table
DW -1
DW -1
DW sf_default_number ; Number of entries in table
DB sf_default_number DUP ( (SIZE sf_entry) DUP (0))
I_AM NoSetDir,BYTE ; true -> do not set directory
I_am DidCTRLC,BYTE ; true -> we did a ^C exit
I_am SpaceFlag,BYTE ; true -> embedded spaces are allowed
; in FCB
; the next two variables relate to the position of the logical stdout/stdin
; cursor. They are only meaningful when stdin/stdout are assigned to the
; console.
i_am CARPOS,BYTE ; cursor position in stdin
i_am STARTPOS,BYTE ; position of cursor at beginning
; of buffered input call
I_AM PFLAG,BYTE
I_AM VERFLG,BYTE ; Initialize with verify off
I_AM CONTPOS,WORD
PUBLIC CHARCO
CHARCO DB 00000011B ; Allows statchks every 4 chars...
I_AM DMAADD,DWORD ; User's disk transfer address
; (disp/seg)
ORG $-CONSTRT-4
DW 80H
DW ?
ENDMEM DW ?
我正试图特别理解此代码:
I_AM DMAADD,DWORD ; User's disk transfer address
; (disp/seg)
ORG $-CONSTRT-4
DW 80H
DW ?
ENDMEM DW ?
似乎定义了DWORD公共变量DMAADD
,然后将变量DMAADD
的值80H
分配给第一个单词,然后将?
分配给第二个单词。我心中有一个疑问,也许最重要的问题是-为什么这样做,而不是将80H
的值分配给变量DMAADD
的下一行。为什么在此应用此策略,其目的是什么?为什么ORG $-CONSTRT-4
?
I_AM
宏的定义和描述方式如下:
;
; define a data item to be public and of an appropriate size/type
;
I_AM MACRO name,size
PUBLIC name
IFIDN <size>,<WORD>
name DW ?
ELSE
IFIDN <size>,<DWORD>
name DD ?
ELSE
IFIDN <size>,<BYTE>
name DB ?
ELSE
name DB size DUP (?)
ENDIF
ENDIF
ENDIF
ENDM
答案 0 :(得分:3)
看来,开发人员打算使用I_AM
宏来使其他模块可以公开访问符号(指向BYTE,WORD和DWORD)。问题是I_AM
宏不允许您指定数据,它使数据未初始化为?
。为了解决这个问题,开发人员决定备份程序计数器以覆盖未初始化的数据,以便他们可以用80h的WORD值和未初始化的第二个WORD(?
)填充它。
不允许使用org
为负的表达式。您无法通过以下方式备份程序计数器:
org -4
您需要一个绝对值。您需要知道程序计数器距段开头的距离。他们选择通过在顶部设置CONSTRT
来做到这一点:
CONSTANTS SEGMENT BYTE PUBLIC 'CONST'
EXTRN international_table:BYTE
EXTRN Current_Country:WORD
ORG 0
CONSTRT EQU $ ; Start of constants segment
在这种情况下,CONSTRT
的值为0(分段的开始)。 $
是相对于段开头的当前程序计数器。
要确定当前程序计数器的绝对值提前4个字节,您可以获取当前程序计数器$
,并将其从段开头(已设置CONSTRT
的程序计数器中减去)至)。一旦知道您离分段的开头有多远,就减去4。
那么我们就是:
I_AM DMAADD,DWORD ; User's disk transfer address
; (disp/seg)
这定义了一个公共可访问的标签,该标签被定义为指向未初始化的DWORD值。这样会将程序计数器备份4,以替换未初始化的DWORD:
ORG $-CONSTRT-4
然后发出WORD值80h,其后是未初始化的WORD值:
DW 80H
DW ?
您可能已经替换了I_AM
宏,备份了指针并将数据替换为:
public DMAADD
DMAADD dd 80h
作为Microsoft的编码要求,DOS开发人员可能总是通过I_AM
宏导出指向BYTE,WORD,DWORD数据的标签。这完全是推测。他们可能认为通用的宏将允许他们更改导出此类数据的方法,而无需在无数地方更改代码。