Assigning value to the variable present in previous line using $ sign

我是研究僧i 提交于 2019-12-02 06:11:09

问题


I'm trying to understand the MS-DOS v2.0 source code, and in particular some of the code in MSDATA.ASM. This code was originally assembled with a 35+ year old MASM assembler (a version that wasn't commercially available). The code I'm interested in is near the beginning:

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'm trying to understand this code in particular:

        I_AM    DMAADD,DWORD            ; User's disk transfer address
                                        ; (disp/seg)
            ORG     $-CONSTRT-4
            DW      80H
            DW      ?

ENDMEM      DW      ?

It appears to define a DWORD public variable DMAADD then it assigns the variable DMAADD the values 80H to the first word and then ? to the second word. I have some doubt in my mind and perhaps the most important question is - why is it doing it this way, instead of just assigning value of 80H to the variable DMAADD to the next line. Why is this strategy being applied here, and what is its purpose? WHy the ORG $-CONSTRT-4?


The I_AM macro is defined and described this way:

;
; 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:


It appears that the developers were intent on using the I_AM macro to make symbols (that point at BYTEs, WORDs, and DWORDs) publicly accessible by other modules. The problem is that the I_AM macro doesn't allow you to specify the data, it leaves it uninitialised as ?. To get around that the developers decided to back the program counter up to overwrite the uninitialised data so they could fill it in with a WORD value of 80h and a second WORD that is uninitialised (?).

You aren't allowed to use an expressions with an org that is negative. You couldn't back the program counter up with:

org -4

You need an absolute value. You need to know how far the program counter is from the beginning of the segment. They chose to do that by setting up CONSTRT at the top with:

CONSTANTS       SEGMENT BYTE PUBLIC 'CONST'
        EXTRN   international_table:BYTE
        EXTRN   Current_Country:WORD


        ORG     0
CONSTRT EQU     $               ; Start of constants segment

In this case CONSTRT is given the value 0 (the start of the segment). $ is the current program counter relative to the beginning of the segment.

To determine the absolute value of the current program counter 4 bytes earlier you can take the current program counter $ and subtract it from the program counter at the beginning of the segment (which CONSTRT is set to). Once you know how far you are from the beginning of the segment you subtract 4.

What we have then is:

    I_AM    DMAADD,DWORD            ; User's disk transfer address
                                    ; (disp/seg)

That defines a publicly accessible label that is defined as pointing at an uninitialised DWORD value. This backs up the program counter by 4 to replace the uninitialised DWORD:

        ORG     $-CONSTRT-4

This then emits the WORD value 80h followed by an uninitialised WORD value:

        DW      80H
        DW      ?

You could have replaced the I_AM macro, the backing up of the pointer and replacing of the data with:

        public DMAADD
        DMAADD dd 80h

It may be that the DOS developers always exported labels that point at BYTE, WORD, DWORD data via the I_AM macro as a coding requirement at Microsoft. This is entirely speculative. They may have felt that a common macro would allow them to change the method of exporting such data without changing code in countless places.



来源:https://stackoverflow.com/questions/56623552/assigning-value-to-the-variable-present-in-previous-line-using-sign

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!