4

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

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

我不是在谈论

 #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 问题;我试图理解为什么有这么多汇编程序。似乎一切都可以由预处理器完成,而汇编器确实是程序员的偏好;或者我缺少技术限制。

我想这可能与“你可以用汇编程序做的事情,而你不能用shell 代码做的事情”有关。

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

4

2 回答 2

4

我认为XY 问题是一个错误的描述。问题更多的是“需要概念A来评估概念B ”。


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

请参阅:David Solomon汇编程序和装载程序。[一些智慧的珍珠,一些古老的琐事]

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

一个汇编程序包括,

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

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


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

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

大型汇编程序例程

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

多架构代码

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

自修改代码

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

另见:黄金博客,伊恩·兰斯·泰勒( Ian Lance Taylor)。[虽然他使用<templates>]

于 2013-03-21T03:09:36.677 回答
3

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

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

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

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

也许这是一个 XY 问题

这是肯定的。

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

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

于 2013-03-17T20:46:27.097 回答