使用`GCCs`预处理器作为汇编程序

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

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

我不是在谈论内联汇编 。

  #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问题 ; 我试图理解为什么有这么多assembly工。 似乎所有事情都可以由预处理器完成,而汇编程序实际上是程序员的首选; 或者我缺少技术限制。

我想这可能与’你可以使用汇编程序做的事情有关,你无法用shell代码做’。

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

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

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

首先,正如您刚刚自己展示的那样,您无法使用英特尔或AT&T风格的常规汇编语法。 你必须使用那些丑陋的括号。

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

也许这是一个XY问题

这是肯定的。

我试图理解为什么有这么多assembly工。

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

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


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

请参阅: 大卫·所罗门的 assembly者和装载者。 [一些智慧的珍珠,一些古老的琐事]

我很快发现这个领域缺乏文献资料。 与存在大量文献的编纂者形成鲜明对比的是,关于assembly工和装载机的编写量很少。

汇编程序包括,

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

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


概念B:使用’C’预处理器作为汇编程序。

最好的’C’预处理器可以模拟一个1遍汇编器。 可以像这样编码一大类CPU /指令; 虽然宏可能很麻烦。 没有列表外部参照 ,但大多数人不会错过这些function。 而且,由于预处理器的限制,语法将是奇数。 处理地址修复很困难,因为标签要么通过使用指针重新使用’C’符号表,要么使用手动编码#define来重复标记偏移。 这将此方法限制为除基本块之外的任何其他方法。

大型汇编程序

诸如YUV / RGB变换或MP3解码之类的大型汇编程序很难以这种方式使用。

多拱代码

多种架构代码非常常见。 例如,ARM wifi芯片可能将其代码嵌入Linux内核中作为固件。 这种技术可能在这里很有用。 但是,对于不同的体系结构使用单独的编译器/汇编程序然后使用objcopy来嵌入它们会更加明智。

自修改代码

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

另见: 黄金博客 ,作者: Ian Lance Taylor 。 [虽然他使用 ]