我假设 emu8086 在声明段时支持与 TASM 相同的语法,而 TASM 又支持与 MASM 相同的语法。
段用<name> SEGMENT [attributes] 或SEGMENT <name> [attributes] 声明。 属性 是可选的,如果缺少任何值,则推断默认值。
<name> 可以是任何尚未定义的有效名称(注意.MODEL 指令定义了一些名称,包括_TEXT 和_DATA)。
[attributes] 分为五个类别,每个类别都有一个或多个值可供选择。
不同类别的值用空格分隔,不能再出现任何类别的单个值。
细分组合属性
这些属性值定义了两个或多个段如何组合在一起。
-
PUBLIC 使链接器连接在不同模块(即源文件)中定义的具有相同名称的段。
-
PRIVATE 与上述相反,在当前模块之外定义的同名段不会被连接(注意在同一个文件中同名的段仍然被认为是同一个段)。
-
STACK 与 PUBLIC 相同,但在生成的二进制文件中,会创建元数据,以便操作系统使用此属性将 SS:SP 设置为段的末尾(在发生连接之后)。
-
MEMORY 是 STACK 的别名和 TASM 手册中的拼写错误。
-
COMMON 所有具有相同名称的段将重叠而不是串联。最后一段与最长的COMMON 段一样长。
-
VIRTUAL 用于声明在最终二进制文件中只能出现一次的段,无论在所有模块中声明了多少次。
-
AT 在特定地址放置一个段。
-
UNINIT 将该段标记为包含未初始化的数据(就像 ELF 中的 .bss 部分一样)
段类属性
这是一个带引号的字符串,表示段类。段类是仅对链接器有意义的字符串,它有助于在最终二进制文件中创建元数据时对段进行排序和识别目的。
链接器识别的类是:_TEXT、FAR_DATA、FAR_BSS、_DATA、CONST、_BSS 和 STACK。
段对齐属性
这些值指定段必须具有的对齐方式。
简而言之,它们告诉链接器一个段可以从哪个倍数开始,例如PARA,对于 paragraph,16 个字节,告诉链接器一个段可以从 16 的倍数开始:0, 16, 32, 48, ...
-
BYTE,对齐 1
-
WORD,对齐 2
-
DWORD,对齐 4
-
PARA,对齐 16
-
PAGE 256 对齐
-
MEMPAGE 4096 对齐
分段大小属性
这些值指定段的代码和数据的大小。
-
USE16 告诉汇编器要生成的代码必须是 16 位的,并且访问的数据必须使用 16 位地址大小。
-
USE32 与上述相同,但大小为 32 位。
分段访问属性
TLINK 不支持的这些属性告诉链接器在段的元数据中设置了什么访问限制。
这不适用于 DOS 二进制文件。
这些值为EXECONLY、EXECREAD、READONLY、READWRITE。名字很有说服力。
段定义SSEG SEGMENT STACK 'STACK' 定义了一个段:
- 姓名
SSEG。
- 组合属性
STACK,使链接器发出元数据以设置SS:SP指向它的末尾。
- 类属性
'STACK' 使链接器将其识别为堆栈段。
使用STACK 组合和'STACK' 类使链接器知道段是堆栈段。
第一个控制SS:SP1 的初始值,并且足以拥有一个堆栈。
第二个指定段本身的排序和分组。
细分分组
链接器可以将段组合在一起,这就像连接段但尊重对齐约束。
通过将段分组在一起,可以使用单个段寄存器来访问所有段。
段分组也用于对段进行逻辑分组,即使链接器对它们一视同仁。
特别是,TASM 隐式定义了DGROUP 组,当使用.MODEL 指令时,其中包括类'DATA' 和'STACK' 的段。
您可以使用.MODEL 指令的FARSTACK 选项从DGROUP 中排除'STACK' 段。
所以'STACK' 类告诉链接器该段必须进入(或不能进入)DGROUP。
此外,在该组内'STACK' 段被放置在任何其他段类之后。
STACK 'STACK' 对的最终效果是:
- 初始化
SS:SP。
- 将堆栈放在数据之后。
DW 100h DUP(?) 行就像你说的那样,但是正确的术语是 reserve 因为我相信二进制文件中没有为堆栈分配空间。链接器可能足够聪明,可以识别出具有未初始化数据的'STACK' 分类段不需要在磁盘上发生。
但我可能错了,我不记得二进制文件的 MZ 头是否允许这样做。
另一种声明预定义大小的堆栈段的更简单方法是.STACK 200h(如果您可以使用 1KiB 的堆栈,也可以直接使用 .STACK)。
Chapter 7 of the TASM manual 有关于这个长主题的更完整信息。
1 为了更好地理解这一点,值得注意的是生成的 EXE 有一个头文件,链接器可以在其中指定这些寄存器的初始值,操作系统将在加载时重新定位并设置它们二进制。