assembly - 使用 $ 符号为上一行中存在的变量赋值

标签 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 公共(public)变量 DMAADD,然后将值 80H 分配给变量 DMAADD 第一个字,然后 ? 到第二个单词。我心里有一些疑问,也许最重要的问题是 - 为什么要这样做,而不是仅仅将 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

最佳答案

开发人员似乎有意使用 I_AM宏使符号(指向字节、字和双字)可供其他模块公开访问。问题是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

可能 DOS 开发人员总是通过 I_AM 导出指向 BYTE、WORD、DWORD 数据的标签。宏作为 Microsoft 的编码要求。这完全是推测。他们可能认为通用宏可以让他们改变导出此类数据的方法,而无需在无数地方更改代码。

关于assembly - 使用 $ 符号为上一行中存在的变量赋值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56623552/

相关文章:

gcc - 如何获取g++汇编代码指令地址

gcc - 在 GCC 内联汇编中检索 ZF

assembly - 避免 AVX-SSE (VEX) 转换惩罚

编译器错误 C2432 : illegal reference to 16-bit data in 'identifier'

hash - 对于 4 个以上具有相同前 6 个字符的文件,Dos 8.3 文件名哈希值是多少?

ide - 在线测试 MASM 程序

assembly - 使用 int 21h, 2Ch 显示系统时间

assembly - x86组装设备vs =

汇编语言随机数生成器

variables - 在 DOS 中比较两个数字不起作用