为什么 SEG 不给出带有此代码片段的错误消息?
Why does SEG not give an error message with this code fragment?
下面一行没有汇编程序产生的错误:
mov ax,seg TEXT:frewd
(见下面的程序片段)
我希望汇编程序创建一条错误消息,因为 frewd
不在 TEXT
段中但在 TEXT1
段中并且不存在 GROUP
语句.
我是不是漏掉了什么?
我已经用虚拟数据填充了两个段,所以有 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
MASM 没有理由给出这一行的错误。 SEG 运算符获取它所使用的表达式的帧的段地址(实模式下的段落地址)。帧是地址的最终偏移量由 linker 确定的段或组。默认情况下,地址的帧与地址段相同,除非地址段属于一个组。请注意,这意味着 MASM 中的地址包含三个部分,一个帧、一个段和一个偏移量。
由于 TEXT:frewd
是一个地址,这意味着它有一个框架,因此 SEG 运算符计算该表达式的框架。事实证明,表达式 TEXT:frewd
的框架并不是它看起来的样子,但如果它实际上是 TEXT
,那么 MASM 就没有理由不能无误地计算表达式. frewd
不在 TEXT
基数 64k 以内的问题直到 link 时间才知道。
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_label
或 mov ax, SEG DATA2:data1_label
),则 SEG 运算符将计算为 "frame" 中给出的内容注释。
这个故事的寓意是,您几乎永远不想使用 MASM 来分割名称作为段覆盖,因为它几乎肯定不会做您想要的。也很少需要使用组名称作为段覆盖,因为汇编程序默认情况下将使用组来定义组中的任何内容。 (请注意,这与 MASM 5 或更早版本不同,如果标签是 DGROUP 的一部分,您必须使用 OFFSET DGROUP:label
才能获得正确的结果。)
在 MASM 中使用段覆盖的唯一真正有用的方法是在左侧使用段寄存器。在这种情况下,它可以替代使用 ASSUME 或者当内存操作数中没有涉及标签时,例如索引寻址(例如 mov ax, es:[di]
)。
下面一行没有汇编程序产生的错误:
mov ax,seg TEXT:frewd
(见下面的程序片段)
我希望汇编程序创建一条错误消息,因为 frewd
不在 TEXT
段中但在 TEXT1
段中并且不存在 GROUP
语句.
我是不是漏掉了什么?
我已经用虚拟数据填充了两个段,所以有 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
MASM 没有理由给出这一行的错误。 SEG 运算符获取它所使用的表达式的帧的段地址(实模式下的段落地址)。帧是地址的最终偏移量由 linker 确定的段或组。默认情况下,地址的帧与地址段相同,除非地址段属于一个组。请注意,这意味着 MASM 中的地址包含三个部分,一个帧、一个段和一个偏移量。
由于 TEXT:frewd
是一个地址,这意味着它有一个框架,因此 SEG 运算符计算该表达式的框架。事实证明,表达式 TEXT:frewd
的框架并不是它看起来的样子,但如果它实际上是 TEXT
,那么 MASM 就没有理由不能无误地计算表达式. frewd
不在 TEXT
基数 64k 以内的问题直到 link 时间才知道。
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_label
或 mov ax, SEG DATA2:data1_label
),则 SEG 运算符将计算为 "frame" 中给出的内容注释。
这个故事的寓意是,您几乎永远不想使用 MASM 来分割名称作为段覆盖,因为它几乎肯定不会做您想要的。也很少需要使用组名称作为段覆盖,因为汇编程序默认情况下将使用组来定义组中的任何内容。 (请注意,这与 MASM 5 或更早版本不同,如果标签是 DGROUP 的一部分,您必须使用 OFFSET DGROUP:label
才能获得正确的结果。)
在 MASM 中使用段覆盖的唯一真正有用的方法是在左侧使用段寄存器。在这种情况下,它可以替代使用 ASSUME 或者当内存操作数中没有涉及标签时,例如索引寻址(例如 mov ax, es:[di]
)。