在C程序中使用汇编语言的目的是什么?

时间:2013-01-03 01:59:22

标签: c assembly inline-assembly

在C程序中使用汇编语言的目的是什么?编译器已经能够生成汇编语言。在什么情况下编写汇编比C更好?性能是否需要考虑?

6 个答案:

答案 0 :(得分:14)

除了每个人所说的:并非所有的CPU功能都暴露给C.有时候,特别是在驱动程序和操作系统编程中,需要明确地使用特殊的寄存器和/或其他无法使用的命令。

也是矢量扩展。

在编译器内在函数出现之前尤其如此。这些在某种程度上减轻了对内联装配的需求。

内联汇编的另一个用例与C与反射语言的接口有关。具体来说,如果您需要在编译时不知道其原型时调用函数,则必须进行汇编。换句话说,当该函数的参数的数量和数据类型是运行时变量时。在这种情况下,C变量函数和stdarg机制将无法帮助您 - 它们可以帮助您解析堆栈帧,但不能帮助构建。另一方面,在装配中,这是非常可行的。

这不是操作系统/驱动程序方案。至少有两种技术--JNI和COM自动化 - 这是必须的。在自动化的情况下,我在谈论COM运行时使用类型库封送双接口的方式。

可以想出一个非常粗略的C替代装配,但它会像罪一样丑陋。无论如何,调用约会会妨碍你。

我一直只处理装配必要的情况。其他答案涵盖了手工优化性能。

编辑:想到了另外一个用例:崩溃/运行时错误报告。对于事后调试,您希望尽可能多地捕获崩溃点的程序状态(即所有CPU寄存器),并且汇编是比C更好的工具。

答案 1 :(得分:6)

有一些(尽管不是很多)可以使手工优化的汇编语言比C源代码的C编译器生成的汇编语言更有效地运行。此外,对于习惯于汇编语言的开发人员来说,在汇编程序中编写一些东西似乎更容易。

对于这些情况,许多C编译器允许内联汇编。

然而,随着C编译器变得越来越好并生成高效的代码,这种情况变得越来越少,并且大多数平台对某些低级软件设置了限制,这些软件通常是从编写中受益最多的软件类型在汇编程序中。

答案 2 :(得分:4)

一般来说,它是性能,但性能非常特殊。例如,处理器的SIMD并行指令可能不是由编译器生成的。通过利用处理器特定的数据格式,然后发出处理器特定的并行指令(例如ARM NEON或Intel SSE),可以在图形或信号处理问题上实现非常快的性能。即使这样,一些编译器也允许使用内部函数在C中表达它们。

虽然过去常常使用汇编语言插入来手动优化关键功能,但那些日子基本上已经完成。现代编译器非常好,现代处理器具有非常复杂的时序要求,因此手动优化的代码通常不如预期的优化。

答案 3 :(得分:3)

在C中编写内联汇编有多种原因。我们可以简单地将原因分类为必要不必要

由于不必要的原因,可能是:

  • 平台兼容性
  • 表现
  • 代码优化
  • 等。

我认为上面是不必要的,因为有时它们可​​以通过纯C丢弃或实现。例如,平台兼容性,您可以完全为每个平台实现特定版本,但是,使用内联汇编可能会减少工作量。在这里,我们不会过多谈论不必要的原因。

出于必要的原因,他们可能是:

  • 标准库的内容不足以
  • 编译器不支持某些指令集
  • 对象代码生成错误
  • 编写堆栈敏感代码
  • 等。

这些原因被认为是必要的,因为它们几乎不可能用纯C语言完成。例如,在旧版DOS中,软件中断INT21 无法重入。如果要编写 Virtual Dirve ,请完全使用编译器支持的INT21,这是不可能的。在这种情况下,您需要挂钩原始INT21,并使其可重入。但是,编译后的代码会使用prolog / epilog 包装您的每个调用。因此,您永远不会破坏某些限制,或者您只是破坏了代码。您可以通过使用C语言的纯语言来尝试任何技巧;但即使你能成功找到一个技巧,这意味着你找到了一个特定的订单,编译器会生成机器代码;这意味着:您试图让编译器将代码编译为精确的机器代码。那么,为什么不直接编写内联汇编?

除了instruction set not supported之外,这个例子解释了上述所有必要的原因,但我认为这很容易考虑。 事实上,编写内联汇编有更多的理由,但现在你对它们有一些想法,等等。

答案 4 :(得分:0)

我宁愿将其视为为特定平台编写特定代码的一种方法,但优化虽然仍然很常见,但现在使用较少。 C语言中的装配知识和使用也是全彩色的帽子。

答案 5 :(得分:0)

就像好奇心一样,我在这里添加了一个具体的例子,说明你只能在汇编中做一些不那么低级的事情。我在大学时代的一本装配书中读到了这本书,用来展示C / C ++的固有局限性,以及如何用装配来克服它。

问题是如果仅在运行时知道参数的确切数量,我如何调用函数?事实上,在C / C ++中,您可以轻松定义一个函数,该函数采用可变数量的参数,如printf。但是当涉及到调用该函数时,编译器想要确切地知道必须传递多少参数。你可以传递超过要求的更多的麻烦,这不会造成任何伤害。但是,如果数字意外增加到100或1000个参数,并且必须从数组中挑选出来怎么办? 解决方案当然是使用程序集,您可以在其中动态创建适当大小的堆栈帧,复制堆栈上的参数,调用函数,最后重置堆栈。

在实践中,这几乎不是一个限制(除非您使用的库真的很糟糕)。在C中使用汇编的人有更好的理由这样做,就像其他人在答案中指出的那样。不过,我认为可能是一个有趣的事实。