SEG为什么不使用此代码片段给出错误消息?

时间:2019-08-10 18:39:31

标签: assembly masm x86-16

下面的行没有汇编程序生成的错误:

mov ax,seg TEXT:frewd

(请参见下面的程序片段)

我希望汇编程序会创建一条错误消息,因为frewd不在TEXT段中,而是在TEXT1段中,并且不存在GROUP语句。 / p>

我想念什么吗?

我已经用虚拟数据填充了两个段,以便有2个不同的段,但仍然没有错误。

 .386
 TEXT segment para private
   example dw ?
   dummy byte 65531 dup(0)
   sample dw ?
 TEXT ends
 TEXT1 segment word private 'CODE'
   frew dw ?
   dummy1 byte 65531 dup(0)
   frewd dw ?
 TEXT1 ends
 Cseg segment
   mov ax, seg TEXT:frewd ;no error is generated here by the assembler
   mov es,ax
 Cseg ends
 end

1 个答案:

答案 0 :(得分:2)

MASM没有理由为此行给出错误。 SEG运算符获取其使用的表达式的框架的段地址(实模式下的段地址)。帧是相对于链接程序确定地址最终偏移量的段或组。缺省情况下,地址的帧与地址段相同,除非地址的段属于一个组。请注意,这意味着MASM中的地址分为三部分:帧,段和偏移量。

由于TEXT:frewd是一个地址,这意味着它有一个框架,因此SEG运算符将求值该表达式的框架。事实证明,表达式TEXT:frewd的框架不是它看起来的样子,但是如果实际上是TEXT,则MASM没有理由不能无误评估表达式。 frewd不在TEXT底数的64k范围内的问题要等到链接时间后才能知道。

MASM仅允许地址的帧与地址的段(如果该组是组)不同。这意味着,当将段名称用作标签的段替代时,它实际上不会将地址的框架更改为已命名的段。相反,如果该框架曾经是一个组,则该框架将更改为标签的分段的框架,否则该框架与标签的分段保持相同。但是,如果标签在内存操作数中使用,则段覆盖会根据先前的ASSUME语句更改MASM将用于指令的段寄存器。

我创建了一个示例来尝试演示MASM的行为。每个从内存加载值的MOV指令都带有注释,说明了汇编程序用于指令的段寄存器(sreg),以及用于内存操作数地址的帧和段。所使用的框架和片段会出现在汇编器放入其输出的目标文件中的重定位(或修正)中。

DATA1   SEGMENT PARA
data1_label DW  0
DATA1   ENDS

DATA2   SEGMENT PARA
    DW  2
data2_label DW  4
DATA2   ENDS

DGROUP  GROUP   DATA1, DATA2

FARDATA SEGMENT PARA
    DW  6, 8
fardata_label DW 10
FARDATA ENDS

CODESEG SEGMENT PARA PUBLIC 'CODE'
start:
    mov ax, DGROUP
    mov ds, ax
    mov ax, FARDATA
    mov es, ax
    mov ax, DATA2
    mov ss, ax
    ASSUME  ds:DGROUP
    ASSUME  es:FARDATA
    ASSUME  ss:DATA2
    ASSUME  cs:CODESEG

    ; Since data1_label and data2_label belong to segments that belong to DGROUP,
    ; they're accessed relative to DGROUP by default and through the segment 
    ; register assumed to point to DGROUP. The correct code is generated
    ; without any overrides.

    mov ax, [data1_label]           ; sreg: DS, frame: DGROUP,  segment: DATA1
    mov ax, [data2_label]           ; sreg: DS, frame: DGROUP,  segment: DATA2

    ; No surprises here, fardata_label is accessed relative to the segment its
    ; defined in and using the segment register assumed for that segment.

    mov ax, [fardata_label]         ; sreg: ES, frame: FARDATA, segment: FARDATA

    ; Changing the last three instructions to use DATA2 as a segment override causes
    ; them all to use the SS segment register, the one assumed for SS.  It also
    ; overrides using DGROUP as the frame for data1_label and data2_label, but
    ; doesn't change the frame to DATA2 for either data1_label or fardata_label.
    ; Only the second instruction will work correctly.  The other two instructions
    ; use the wrong segment register access the label at the offset the linker will
    ; end up using.

    mov ax, [DATA2:data1_label]     ; sreg: SS, frame: DATA1,   segment: DATA1
    mov ax, [DATA2:data2_label]     ; sreg: SS, frame: DATA2,   segment: DATA2
    mov ax, [DATA2:fardata_label]   ; sreg: SS, frame: FARDATA, segment: FARDATA

    ; Overriding with CODESEG has the same as effect as overriding with DATA2,
    ; except the CS register is used instead. None of the instructions will
    ; work, since none of them will have offsets relative to CODESEG, the segment
    ; loaded into CS.

    mov ax, [CODESEG:data1_label]   ; sreg: CS, frame: DATA1,   segment: DATA1
    mov ax, [CODESEG:data2_label]   ; sreg: CS, frame: DATA2,   segment: DATA2
    mov ax, [CODESEG:fardata_label] ; sreg: CS, frame: FARDATA, segment: FARDATA

    ; Using DGROUP as an override on fardata_label will work so long as
    ; fardata_label doesn't end up getting placed before the start of the DGROUP,
    ; or someplace 64K beyond the start of DGROUP.  If it does end up outside
    ; DGROUP then the linker will give an error.  The assembler is unable to
    ; detect this.

    mov ax, [DGROUP:fardata_label]  ; sreg: DS, frame: DGROUP,  segment: FARDATA

    ; Using a single segment override on a number works as expected, but 
    ; using multiple overrides only the left-most override has an effect. 

    mov ax, [CODESEG:0]             ; sreg: CS, frame: CODESEG, segment: CODESEG
    mov ax, [DGROUP:0]              ; sreg: DS, frame: DGROUP,  segment: DGROUP
    mov ax, [DGROUP:CODESEG:0]      ; sreg: DS, frame: DGROUP,  segment: DGROUP
    mov ax, [CODESEG:DGROUP:0]      ; sreg: CS, frame: CODESEG, segment: CODESEG
    mov ax, [FARDATA:CODESEG:0]     ; sreg: ES, frame: FARDATA, segment: FARDATA
CODESEG ENDS

    END start

如果您更改MOV指令,以便它们在地址上使用SEG(例如mov ax, SEG data1_labelmov ax, SEG DATA2:data1_label),则SEG运算符将评估注释中作为“框架”给出的内容。

这个故事的寓意是,您几乎从不希望使用MASM来覆盖名称作为细分覆盖,因为它几乎肯定不会满足您的要求。几乎没有必要将组名用作段替代,因为汇编器默认会将组用于组中定义的任何内容。 (请注意,这与MASM 5或更早版本有所不同,如果标签是DGROUP的一部分,则必须使用OFFSET DGROUP:label才能获得正确的结果。)

将分段覆盖与MASM一起使用的唯一真正有用的方法是在左侧使用分段寄存器时。在这种情况下,它可以替代使用ASSUME或在内存操作数中不包含标签的情况下使用,例如使用索引寻址(例如mov ax, es:[di])。