使用$符号将值赋给上一行中存在的变量

时间:2019-06-17 00:29:51

标签: assembly dos masm x86-16

我试图了解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

1 个答案:

答案 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数据的标签。这完全是推测。他们可能认为通用的宏将允许他们更改导出此类数据的方法,而无需在无数地方更改代码。