【问题标题】:Compiler vs Assembler编译器与汇编器
【发布时间】:2014-11-30 13:00:00
【问题描述】:

汇编程序将汇编代码作为输入并生成机器代码作为输出。那么是不是说汇编器也要对代码做词法分析和语法分析呢?

例如,它需要某种方式来区分作为指令的 MOV 和作为标签的 MOVXYZ。

以下面这段兼容 8086 的代码为例。

MOV MOVXYZ,013h
MOV BX,023h
ADD BX,MOVXYZ

如果确实需要另一轮词法分析和语法分析,那为什么还要将汇编作为编译的中间步骤?

编辑:

汇编器获取汇编代码作为输入

 MOV AX,MOVXYZ
 ADD AX,BX

它本质上是一个带有字符的文件。我的问题是,如果不是词法分析,它如何区分“MOV”和“MOVS”?

【问题讨论】:

  • 一些汇编程序保留所有操作码,防止将它们用作标签。指令通常有一个前缀 (.)。这使得解析比普通编程语言更容易
  • @EOF Some assemblers reserve all opcodes 操作码?你是说助记词吗?操作码是定义操作的二进制指令的一部分。助记符或操作码助记符是指令的符号名称(一串字符)。
  • @nrz:是的,很抱歉我的术语有点草率。
  • 独立的后端汇编器更像是 unix 的传统,而不是标准的东西。大多数普通的 Windows 编译器默认不使用文本后端。

标签: optimization assembly compiler-construction


【解决方案1】:

汇编程序将汇编代码作为输入并生成机器代码作为输出。那么是不是说汇编器也要对代码做词法分析和语法分析呢?

是的。汇编器可以被认为是一种编程语言,就像任何其他语言一样,尽管它是一种非常低级的语言。

例如,它需要某种方式来区分作为指令的 MOV 和作为标签的 MOVXYZ。

确实

如果确实需要另一轮词法分析和语法分析,那为什么还要将汇编作为编译的中间步骤?

就像你说的,它确实需要分析,事实上大多数编译器使用汇编程序作为中间步骤,而是直接将二进制代码生成某种对象格式,然后将其提供给链接器阶段。

作为一个单独的问题:如果生成一个三地址代码作为中间形式,那么它的优化(由编译器从三地址代码到优化的三地址代码)也需要词法分析。

正确,如果 3 地址代码实际上是作为文本发出的,但实际上它通常以二进制形式发送到内部表中,因此实际上已经被解析/分析了。

【讨论】:

  • gcc 在生成目标代码之前使用汇编程序“as”作为其中间步骤。您能否提供一些关于“as”如何将汇编转换为机器代码的见解?
  • 恐怕我对as 汇编器没有任何见解。
  • 编译器总是生成程序集,但如果您不强制它们向您显示生成的程序集,它们通常会以透明的方式进行。
【解决方案2】:

那么是不是说汇编器也要对代码做词法分析和语法分析呢?

仅以非常有限的方式。它必须在必须提取操作码和参数等的意义上这样做,这意味着它将一系列字符转换为它可以实际使用的内部表示。但与“真正的解析器”不同,解析器组装器通常使用普通的旧字符串处理而不是有限状态机之类的东西。您经常会看到诸如读取一行、将其拆分、将第一部分解释为操作码之类的事情——这不是正确的词法分析的工作方式,但它可以有效地提取标记。

已从问题中删除,但是.. 是的,汇编程序也可能会进行一些优化。不过,没有什么是你期望编译器做的。但有时有几种方法可以将助记符翻译成实际指令,然后选择哪一种可能很重要,而且这种选择可能很重要。一个例子是 x86 上的分支大小,有 2 字节的 7x ofs8 形式,其范围有限,还有 6 字节的 0F 8x ofs32

为了找到指令和标签的地址(从而确定您可以/必须使用哪个分支),它必须知道指令的大小,但是它首先需要这些信息来确定分支的大小。解决此问题的一种常见方法是首先假设小尺寸,然后迭代地将任何未达到其目标的分支更改为更大的变体(这可能会导致其他分支超出范围,等等)。

还有一些汇编语言有“伪指令”,它们被写成一个简单的助记符,但组装成两个或多个实际指令。指令的选择可能取决于操作数等(在这种情况下,它可以有效地针对特定情况进行优化)。或者,更常见的是,它可能只是一个预先确定的宏。 MIPS 和 ARM 都有最后一种伪指令。

这是汇编的怪异之处,他们所做的大部分工作只是获取指令并对其进行编码。例如,如果您编写add eax, edx,它会提取标记addeaxedx,识别这是一条add 指令,其操作数看起来像r32,然后它可以查找一张大表(或巨型switch 或决策树)如何对其进行编码。事实证明,有两种编码适合该模式,01 /r03 /r。所以你可以得到01 D003 C2,这取决于汇编程序的作者所做的一些选择。如果它正在组装 16 位代码,它还会发出操作数大小覆盖。

【讨论】:

  • 关于伪指令的好点,但这取决于汇编程序:一些汇编程序可能无法识别伪指令。
【解决方案3】:

一些汇编程序包含某种形式的高级指令。对于 MASM (ML.EXE) 6.11(在 MSDOS 时代发布)及更高版本,有每行汇编代码生成多个指令的点指令:

        .if     ax == 0 || bx == 0
        ;... conditional code goes here.
        .else
        ;... conditional code goes here.
        .endif

这些类型的指令在减少源代码中的标签数量方面很受欢迎。还有像 .while .break .endw 这样的指令。向下滚动到此网页ml directives 的条件控制流部分。

IBM 的 HLASM 也支持类似的功能:IBM HLASM

许多汇编程序还支持宏,其中定义在宏中的通用指令序列可以通过源代码中的单个宏实例(可选地带有参数)生成。

【讨论】:

  • 这是特定于供应商的功能,不可移植且未标准化。
  • @m0skit0 - 请注意此答案中的初始声明“某些汇编程序...”。这些是非常流行的平台汇编程序,Microsoft MASM / ML 用于 X86 上的 Dos / Windows,以及 IBM HLASM 用于 IBM 大型机。许多其他平台的汇编器至少包含某种形式的宏功能。
【解决方案4】:

这是否意味着汇编程序也必须进行词法分析和 对代码进行语法分析?

是的,解析和词法分析与高级语言相同,但通常要简单得多,因为汇编中的一条指令对应机器码中的一条指令。汇编是机器代码的人工表示,没有像高级语言(例如 C)那样的抽象层。

那么它的优化也需要词法分析

Assembler 不进行优化。它将您的代码按原样转换为机器代码。另一方面,编译器可以优化你的代码;生成的程序集已经过优化。

【讨论】:

  • 那么汇编程序如何识别特定指令中的不同标记,例如: MOV AX,MOVXYZ 进行优化,我的意思是在转换为最终汇编之前将三地址代码转换为更优化的形式代码。
  • MOV -> 指令; AX -> 第一个操作数,MOVXYZ -> 第二个操作数。从汇编语法来看这是微不足道的。不,汇编程序没有这样的优化。
  • 我的意思是编译器在将其转换为汇编代码并将其提供给汇编程序之前,从三地址代码到优化的三地址代码进行优化
  • 我不明白你的意思。举个例子。在任何情况下,优化都是由编译器完成的,它取决于语言,而不是汇编程序。
  • No because one instruction in assembly corresponds to one instruction in machine code. 这不是真的。在 x86 中,许多指令具有 2 种或更多不同的编码。请参阅 harold 对 add eax,edx 示例的回答。更多示例:push edx in 32-bit x86 (IA-32):可以编码为(十六进制字节):ff f2(reg/mem 编码)或52(reg 编码)。在 x86-64 中,某些编码具有固定的 64 位操作数大小,因此对于 64 位操作数,REX 字节的第 3 位可以是 0 或 1。所以 mov r14,cr0 可以是 41 0f 20 c649 0f 20 c6。大多数 x86 和 x86-64 指令都有 2 种或更多可能的编码。
猜你喜欢
  • 1970-01-01
  • 2016-05-04
  • 2014-08-28
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多