如何在现代使用汇编(例如使用C / C ++)?

时间:2010-10-04 12:07:09

标签: c++ c assembly

我理解计算机是如何工作的基本原理,例如,程序可以用“高级”语言编写,如C#,C然后将其分解为目标代码然后二进制供处理器理解。但是,我真的想学习装配,以及它如何在现代应用中使用。

我知道处理器在基本x86指令集之上有不同的指令集。所有汇编语言都支持所有指令集吗?

有多少汇编语言?有多少与其他语言配合良好?

如何在程序集中编写例程,然后将其编译为对象/二进制代码?

有人会如何从C或C ++等语言引用该汇编代码中的函数/例程?

我们如何知道我们在汇编中编写的代码可能是最快的?

是否有关于汇编语言的推荐书籍/将它们与现代程序一起使用?

对于问题的数量感到抱歉,我希望它们足够通用,对其他人有用,并且足够简单,让其他人回答!

6 个答案:

答案 0 :(得分:16)

但是,我真的想学习装配,以及它如何在现代应用中使用。

在“普通”PC上,它仅用于对时间要求严格的处理,我认为实时多媒体处理仍然可以从手工锻造装配中获益。在嵌入式系统上,马力较少,可能会有更多的使用范围。

然而,请记住,它不仅仅是“嘿,这段代码很慢,我会在汇编中重写它,它会通过魔法来快速完成”:它必须仔细编写汇编,写成知道< / em>什么是快速的,它在你的特定架构上是慢的,并牢记现代处理器的所有复杂性(分支错误预测,乱序执行......)。通常,由初学者到中型程序集编程器编写的程序集将比由优秀的现代优化编译器生成的最终机器代码更慢。 x86上的性能通常非常复杂,应该留给那些知道他们做什么的人=&gt;其中大多数是编译器编写者。 :)例如,看一下this

我知道处理器在基本x86指令集之上有不同的指令集。所有汇编语言都支持所有指令集吗?

我认为你在这里混淆了一些事情。许多(=所有现代)x86处理器支持在定义原始x86指令集之后引入的附加指令和指令集。实际上,现在几乎所有的x86软件都被编译为利用后奔腾功能;您可以使用CPUID指令查询处理器以查看它是否支持某些功能。显然,如果你想使用助记符进行一些较新的指令集指令,你的汇编程序(即在实际机器代码中翻译助记符的软件)必须知道它们。

相反,如果您正在讨论其他系列处理器的其他(非x86)指令集,那么每个汇编器应该支持目标处理器可以运行的指令。并非汇编语言的所有指令都可以直接替换其他语言,并且通常将汇编代码从架构移植到另一个架构代码通常是一项艰巨而艰巨的工作。

有多少汇编语言?

理论上,每个处理器系列至少有一种方言。请记住,同一汇编语言也有不同的表示法;例如,以下两条指令是用AT&amp; T和Intel表示法编写的相同的x86内容:

mov $4, %eax          // AT&T notation

mov eax, 4            // Intel notation
如何在程序集中编写例程,然后将其编译为对象/二进制代码?

如果要在使用其他语言编写的应用程序中嵌入例程,则应使用该语言提供的工具,在C / C ++中使用asm块。

如果你想要在汇编中编写一个完整的应用程序,你必须按照你想要使用的汇编程序的语法规则在汇编中编写。

我们如何知道我们在汇编中编写的代码是最快的?

理论上,因为它是最接近裸机的,所以你可以让机器完全按照你想要的那样做,而不需要编译器考虑到在某些特定情况下无关紧要的语言功能。在实践中,由于机器通常比汇编语言暴露的复杂得多,正如我所说的那样,汇编语言通常比编译器生成的机器代码慢,这需要考虑到普通程序员不知道的许多细微之处。


附录

我忘记了:知道阅读汇编,至少有一点点,可以非常用于调试优化器损坏/仅在发布版本中/你的奇怪问题必须处理heisenbugs /当源级调试不可用或其他类似的事情;看一下评论here

答案 1 :(得分:7)

答案 2 :(得分:3)

您需要从硬件的角度来看待它,汇编语言是根据CPU可以执行的操作创建的。每次创建CPU中的新功能时,都会创建适当的汇编指令,以便可以使用它。

因此,汇编非常依赖于CPU,像C ++这样的高级语言提供了抽象,使我们不必考虑CPU指令等细节以及编译器生成优化的汇编代码。

编辑:

  

有多少汇编语言?   有多少与其他人合作   语言

尽可能多的CPU类型。第二个问题我不明白。程序集本身不与任何其他语言交互,输出,机器代码是。

  

有人会如何写作   程序中的常规,然后   将其编译为object / binary   码?`

原理类似于使用任何其他编译语言编写,使用汇编指令创建文本文件,使用汇编程序将其编译为机器代码。然后将其与最终的运行时库链接。

  

然后有人会如何引用其中的函数/例程   来自C语言的汇编代码   还是C ++?

C ++和C提供内联汇编,因此不需要链接,但是如果要链接,则需要按照与宿主语言相同/相似的调用约定创建汇编对象。例如,某些语言在调用函数时会按特定顺序将参数推送到堆栈上的函数,因此您必须执行相同的操作。

  

我们如何知道我们编写的代码   在装配中它是最快的   可以吗?

因为它最接近实际硬件。当您处理更高级别的语言时,您不知道编译器将对您的for循环执行什么操作。然而,他们往往比人类更好地优化代码(当然,在非常特殊的情况下,你可能会得到更好的结果)。

答案 3 :(得分:1)

那里有许多不同的汇编语言。通常每个处理器指令集至少有一个,这意味着每个处理器类型都有一个。您还应该记住的一件事是,即使对于单个处理器,也可能存在可能使用不同语法的若干不同汇编程序,这些语法从正式视图构成不同的语言。 (对于x86,有masm,nasm,yasm,AT&amp; T(默认使用GNU汇编程序的* nix汇编程序),可能还有更多)

对于x86,有许多不同的指令集,因为多年来架构发生了很多变化。其中一些更改可能主要被视为附加指令,因此它们是前一个程序集的超级集合。其他更改实际上可能会删除指令(x86没有人想到,但我听说过其他处理器上的一些)。其他变化为处理器增加了操作模式,使事情变得更加复杂。

还有其他处理器具有完全不同的指令。

要学习汇编,您需要先选择要使用的目标处理器和汇编器。我将假设您将使用x86,因此您需要决定是否要从16位分段,32位或64位开始。许多书籍和在线教程都是你编写DOS程序的16位路线。如果您想要在汇编中编写C程序的一部分,那么您可能希望使用32位或64位路径。

我所做的大多数汇编编程都是在C中内联,以优化某些东西,使用编译器不知道的指令,或者当我需要控制所使用的指令时。在汇编中编写大量代码很困难,所以我让C编译器完成大部分工作。

有许多地方仍然由人们编写集会。这在嵌入式引导加载程序(bios,u-boot,...)和操作系统代码中尤为常见,尽管这些代码中的许多开发人员从不直接编写任何程序集。此代码可能是启动代码,必须在堆栈指针设置为可用值之前运行(或RAM由于某些其他原因尚未使用),因为它们需要适合小空间,和/或因为它们需要以C或其他更高级语言不直接支持的方式与硬件通信。在OS中使用程序集的其他地方是写锁(自旋锁,关键部分,互斥锁和信号量)和上下文切换(从一个执行线程切换到另一个执行线程)。

通常编写程序集的其他地方是某些库代码的实现。像strcpy这样的函数通常在汇编中针对不同的体系结构实现,因为通常有几种方法可以使用特定于处理器的操作来优化它们,而C实现可能使用更通用的循环。这些功能也经常被重复使用,从长远来看,手工优化它们通常是值得的。

编写大量汇编的另一个相关的地方是编译器。编译器必须知道如何实现事物,并且其中许多产生汇编,因此它们内置了汇编模板(或类似的东西),用于生成输出代码。

即使您从未编写任何程序集,知道目标系统的指令和寄存器通常也很有用。它们可以帮助调试,但它们也可以帮助编写代码。了解目标处理器可以帮助您为其编写更好(更小和/或更快)的代码(即使是更高级别的语言),熟悉一些不同的处理器将帮助您编写对许多处理器有益的代码,因为你会普遍了解CPU是如何工作的。

答案 4 :(得分:0)

我们在实时工作中做了相当多的工作(比我们应该做的更多)。当您与硬件通信并且需要执行特定的机器指令时,一点点组装也非常有用(例如:所有写入必须是16位写入,或者您将使附近的寄存器软管化)。

我今天倾向于看到更高级语言代码中的程序集插入。如何完成这取决于您的语言,有时还有编译器。

答案 5 :(得分:0)

  

我知道处理器有所不同   指令集基本上是x86   指令系统。做所有组装   语言支持所有指令   套?

“汇编语言”是一种用词不当,至少在你使用它的方式。汇编程序不是一种语言(CS毕业生可能会反对)和更多的转换器工具,它采用文本表示并从中生成二进制图像,文本元素(memnonics,标签和数字)与二进制文件之间的关系接近1:1元素。汇编语言的元素背后没有更深层次的逻辑,因为它们被引用和重定向的可能性主要在第1级结束;例如,你可以一次只在一条指令中使用EAX - 在下一条指令中下一次使用EAX与之前的使用没有关系,除了程序员想到的未写入的逻辑连接外 - 这就是为什么在汇编程序中创建错误非常容易。

  

有人会如何写作   程序中的常规,然后   将其编译为对象/二进制代码?

需要确定指令集的最低公分母,并将函数编码为代码要运行的预期体系结构的时间。如果您没有为编写本文时定义的某个硬件平台编写代码(例如游戏机,嵌入式主板),则不再使用此功能。

  

有人会如何引用   其中的功能/例程   来自C语言的汇编代码   还是C ++?

您需要在HLL中声明它们 - 请参阅编译器手册。

  

我们如何知道我们编写的代码   在装配中它是最快的   可以吗?

没有办法知道。对此感到高兴和代码。