【问题标题】:Assigning value to the variable present in previous line using $ sign使用 $ 符号为上一行中存在的变量赋值
【发布时间】:2019-06-17 00:29:51
【问题描述】:

我正在尝试理解 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

【问题讨论】:

标签: assembly dos masm x86-16


【解决方案1】:

似乎开发人员打算使用I_AM 宏使符号(指向 BYTE、WORD 和 DWORD)可由其他模块公开访问。问题是I_AM 宏不允许您指定数据,它会将其未初始化为?。为了解决这个问题,开发人员决定备份程序计数器以覆盖未初始化的数据,以便他们可以用 WORD 值 80h 和第二个未初始化的 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 的编码要求。这完全是推测性的。他们可能觉得一个通用的宏可以让他们改变导出此类数据的方法,而无需在无数地方更改代码。

【讨论】:

  • 所以CONSTRT 只是一个常量,需要定义为0 以使org $ - CONSTRT - 4 = org $ - 4?我本来希望org $ - 4 能够独立工作。 (当然org -4 不起作用;它需要一个绝对而不是相对位置。但我认为不需要$ - symbol - 4,除非它可以解决一些汇编程序限制。)
  • @PeterCordes :我可能应该修改我的答案来解释为什么$-4 可能不起作用。 MASM 可能没有将$-4 视为绝对值,因此表达式中不允许使用它。旧的装配工在这方面很挑剔。这就是为什么当我修改问题时,我写下了关于正在使用的 MASM 已经 35 岁的注释,并且不是发布产品的正式版本。开发人员可能正在处理汇编程序的限制。
  • @Petercordes :我回到了 MASM 1.0(和 1.10)并且都在一个段内支持 $-4。很难说。
  • 我不想认为他们不知道您可以在表达式中那样使用$。它记录在 1.00 手册中,或者他们甚至从不支持它的早期版本的 MASM 开始。我现在不知道。
  • 或者,也许有人只是脑放屁,让它变得比必要的复杂,也许是因为他们最初的想法更复杂。我知道我写的东西(事后看来)过于复杂,因为我没有从使问题变得简单的角度来看待问题。这里有点奇怪,因为整个事情只有在 CONSTRT = 0 时才有意义,但是 IDK。
猜你喜欢
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-14
  • 2011-07-13
  • 2015-02-08
相关资源
最近更新 更多