【问题标题】:Using `GCCs` pre-processor as an assembler使用 `GCCs` 预处理器作为汇编器
【发布时间】:2013-03-06 03:33:14
【问题描述】:

有各种开源汇编器,例如。它们有不同的 pseudo-opsmacro 语法。对于许多开源项目,汇编程序经过预处理以替换常量和平台条件。

假设您可以使用所有当前的attributes#pragmasgcc 创建汇编程序会有什么限制,不包括翻译性能(编译/汇编到二进制时间)?

我不是在谈论

 #define MOV(RA,RB)  (OXFEB10000UL | RA << 16 | RB)  
 #define ADD(RA,RB)  (OXFEB20000UL | RA << 16 | RB)  
 #define RET         (OXFEB7ABCDUL)  

 unsigned long add4[] __attribute(section(".text")) =
 {
    ADD(R0,R1),
    ADD(R2,R3),
    MOV(R1,R2),
    ADD(R0,R1),
    RET()
 };

我相信使用指针算法可以模拟.和其他labels。也许这是一个XY problem;我试图理解为什么有这么多汇编程序。似乎一切都可以由预处理器完成,而汇编器确实是程序员的偏好;或者我缺少技术限制。

我想这可能与“使用汇编程序可以做的事情,而 shell code 无法做到的事情”有关。

编辑:我已将它从 C 重新标记为 compiler。我对汇编程序的技术细节感兴趣。它是简单的1-1 翻译和发射重定位(编译器会这样做)还是还有更多?正如我上面所概述的那样,我并不是要人们编写汇编程序。我试图了解汇编程序在做什么。我不相信有适合装配工的龙书。当然,预处理器不能自己创建binary,需要额外的机器;它只翻译文本。

【问题讨论】:

  • 我认为这不适用于 x86。为特定指令选择最佳编码并非易事,对齐会很棘手,据我所知,优化分支大小是完全不可能的。在任何情况下,您都会在螺丝上使用锤子。
  • @Harold:你能详细说明它是如何不起作用的吗?对于 x86,它会复杂得多,并且需要 byte 对齐。 x86 汇编器是否必须在内存中保留较大的基本块才能生成操作码?
  • @Bill - x86 有可变长度指令,助记符和操作码之间没有 1-1 的关系。例如,一个“简单”的 MOV 有 20 多种不同的变体,例如 MOV AX,1MOV other_reg,1 不同。
  • @BillPringlemeir 否,但它最终会在内存中保留大块,以满足对齐约束,同时优化分支大小。它仅需要字节对齐,但它确实喜欢某些分支目标的 16 对齐。
  • 您可能会发现这本古代汇编器手册很有用。 bitsavers.org/pdf/dec/pdp1/PDP-1_Macro.pdf

标签: gas nasm yasm inline-assembly c gcc assembly compiler-construction


【解决方案1】:

我认为XY Problem 是错误的描述。问题更多的是“Concept A需要评估Concept B”。


概念 A:什么是汇编程序?

参见:Assemblers and Loader,作者 David Solomon。 [一些智慧的珍珠,一些古老的琐事]

我很快发现这个领域缺乏文献。与存在大量文献的编译器相比,汇编器和加载器几乎没有写过。

一个汇编程序包括,

  • Symbol table 有助于通过某些对象格式进行链接。
  • LexerParser 用于将文本转换为数据结构或直接转换为机器代码。
  • Does 2 passes 用于最有效的分支和子例程调用。
  • 一个操作码表。

汇编器通常是1-1 的翻译。但是,通常会存在几种分支和调用的变体;通常称为 longshort 版本。使用的操作码取决于到目的地的距离;需要一个两遍编译器来优化前向分支。Harold暗示


概念 B:将“C”预处理器用作汇编器。

“C”预处理器可以模拟的最好的是 1-pass 汇编器。一大类 CPU/指令可以这样编码;尽管宏可能很麻烦。不会有 listingsxrefs,但大多数人不会错过这些功能。此外,由于预处理器的限制,语法会很奇怪。处理地址修复将很困难,因为标签将通过使用指针或手动编码 #define 来重新使用“C”符号表作为标签偏移量。这将这种方法限制在basic block之外的任何地方。

大型汇编程序例程

YUV/RGB 转换或 MP3 解码等大型汇编程序例程极不可能以这种方式使用。

多架构代码

多架构代码很常见。例如,ARM wifi 芯片可能将其代码作为固件嵌入到 Linux 内核中。这种技术可能在这里有用。但是,为不同的架构使用单独的编译器/汇编器,然后使用objcopy 嵌入它们要明智得多。

自修改代码

这可能是最有用的。事实上,许多工具,例如链接器和加载器,都具有在运行时修补代码的高级功能。它还可以用于在运行时有条件地更改例程;函数指针几乎同样快速且易于理解,更不用说缓存一致性问题了。

另请参阅:Gold Blog,作者 Ian Lance Taylor。 [虽然他使用&lt;templates&gt;]

【讨论】:

  • 遗漏的重要一点是搬迁。汇编器编写目标文件,其中的内容被链接器或加载器标记为可重定位。使用预处理器的概念仅限于 PC 相关的叶函数(或没有外部的代码)。
【解决方案2】:

gcc 创建汇编器 [...] 有什么限制?

很多。我们使用汇编器进行汇编,使用 C 预处理器进行预处理是有原因的。

首先,正如您刚刚自己展示的那样,您不能使用普通的汇编语法,无论是 Intel 还是 AT&T 风格。你必须使用那些丑陋的括号。

其次,您所说的那些__attribute__ 指令与预处理器无关,它甚至无法识别它们。它们是对编译器的提示, 编译器将依次生成由这些属性(或不是)引导的汇编代码。

也许这是一个 XY 问题

这是肯定的。

我试图理解为什么有这么多汇编程序。

出于同样的原因,市面上有各种类型的编程语言、编译器、汽车和衣服:一种工具无法满足所有人的需求。人们是不同的,他们用他们的工具链做不同的事情,他们发现一个比另一个更容易使用(如果它不需要 AT&T 语法,我个人会使用 GNU 汇编器,我只是不能支持),等等

【讨论】:

  • 我真的不认为你(或任何人)理解我的问题。也许这是我的问题?
猜你喜欢
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
相关资源
最近更新 更多