【问题标题】:Assembly segment declaration syntax汇编段声明语法
【发布时间】:2016-11-26 20:17:23
【问题描述】:

我刚开始使用 ASM 和 x8086 架构,在跟进一些 emu8086 附带的示例时遇到了一些问题。

SSEG    SEGMENT STACK   'STACK'
DW      100h    DUP(?)
SSEG    ENDS

好吧 SSeg ,我猜它是作为堆栈段的标签, SEGMENT 关键字表示前面是一个段,但是STACK 'STACK' 代表什么为了?

在下面,我认为它的意思是“分配(我不知道在哪里)100h 16 位字,没有值”
这是否正确,如果正确,分配在哪里?

【问题讨论】:

  • phatcode.net/res/223/files/html/Chapter_8/CH08-2.html .. 关于“分配” - 是的,它将在某处保留 512 个字节(somewhere 在总内存中,从源点来看,它将在开头堆栈段,因为它是在 SEGMENT -> ENDS 块中定义的第一个字节),链接器 + 链接器脚本将决定“堆栈”段的目标位置,然后可执行文件的操作系统加载程序将进行最终重定位。
  • 由于 emu8086 集成了以下软件包:仿真器、IDE、调试器、汇编器、链接器和泰式足部按摩(可能最后一个仅在付费版本中),因此您可以有效地从编译/链接/启动/loading_executable 进程的微小细节,所以除非你真的坚持不懈,否则放弃这些​​细节(here 是emu8086 中模拟机器的总内存映射,但它没有回答它的 DOS 是如何加载的。 exe 并重新定位它,在调试器中检查cs/ds/ss 值)。

标签: assembly emu8086


【解决方案1】:

我假设 emu8086 在声明段时支持与 TASM 相同的语法,而 TASM 又支持与 MASM 相同的语法。


段用<name> SEGMENT [attributes]SEGMENT <name> [attributes] 声明。 属性 是可选的,如果缺少任何值,则推断默认值。

<name> 可以是任何尚未定义的有效名称(注意.MODEL 指令定义了一些名称,包括_TEXT_DATA)。

[attributes] 分为五个类别,每个类别都有一个或多个值可供选择。 不同类别的值用空格分隔,不能再出现任何类别的单个值。

细分组合属性
这些属性值定义了两个或多个段如何组合在一起。

  • PUBLIC 使链接器连接在不同模块(即源文件)中定义的具有相同名称的段。
  • PRIVATE 与上述相反,在当前模块之外定义的同名段不会被连接(注意在同一个文件中同名的段仍然被认为是同一个段)。
  • STACKPUBLIC 相同,但在生成的二进制文件中,会创建元数据,以便操作系统使用此属性将 SS:SP 设置为段的末尾(在发生连接之后)。
  • MEMORYSTACK 的别名和 TASM 手册中的拼写错误。
  • COMMON 所有具有相同名称的段将重叠而不是串联。最后一段与最长的COMMON 段一样长。
  • VIRTUAL 用于声明在最终二进制文件中只能出现一次的段,无论在所有模块中声明了多少次。
  • AT 在特定地址放置一个段。
  • UNINIT 将该段标记为包含未初始化的数据(就像 ELF 中的 .bss 部分一样)

段类属性

这是一个带引号的字符串,表示段类。段类是仅对链接器有意义的字符串,它有助于在最终二进制文件中创建元数据时对段进行排序和识别目的。
链接器识别的类是:_TEXTFAR_DATAFAR_BSS_DATACONST_BSSSTACK

段对齐属性
这些值指定段必须具有的对齐方式。
简而言之,它们告诉链接器一个段可以从哪个倍数开始,例如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 二进制文件。
这些值为EXECONLYEXECREADREADONLYREADWRITE。名字很有说服力。


段定义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' 对的最终效果是:

  1. 初始化SS:SP
  2. 将堆栈放在数据之后。

DW 100h DUP(?) 行就像你说的那样,但是正确的术语是 reserve 因为我相信二进制文件中没有为堆栈分配空间。链接器可能足够聪明,可以识别出具有未初始化数据的'STACK' 分类段不需要在磁盘上发生。
但我可能错了,我不记得二进制文件的 MZ 头是否允许这样做。

另一种声明预定义大小的堆栈段的更简单方法是.STACK 200h(如果您可以使用 1KiB 的堆栈,也可以直接使用 .STACK)。


Chapter 7 of the TASM manual 有关于这个长主题的更完整信息。


1 为了更好地理解这一点,值得注意的是生成的 EXE 有一个头文件,链接器可以在其中指定这些寄存器的初始值,操作系统将在加载时重新定位并设置它们二进制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    相关资源
    最近更新 更多