我理解计算机如何在基本原理上工作,例如,程序可以用C#,C等"高级"语言编写,然后将其分解为目标代码,然后分解为处理器才能理解.但是,我真的想学习装配,以及它如何在现代应用中使用.
我知道处理器在基本x86指令集之上有不同的指令集.所有汇编语言都支持所有指令集吗?
有多少汇编语言?有多少与其他语言一起使用?
如何在程序集中编写例程,然后将其编译为对象/二进制代码?
那么有人会如何用C或C++这样的语言引用汇编代码中的函数/例程?
我们怎么知道我们在汇编中编写的代码可能是最快的?
是否有关于汇编语言的推荐书籍/将它们与现代程序一起使用?
对于问题的数量感到抱歉,我希望它们足够通用,对其他人有用,并且足够简单,让其他人回答!
Mat*_*lia 16
但是,我真的想学习装配,以及它如何在现代应用中使用.
在"普通"PC上,它仅用于时间关键处理,我认为实时多媒体处理仍然可以从手工组装中获益.在嵌入式系统中,马力较少,可能会有更多的使用领域.
但是,请记住,这不仅仅是"嘿,这段代码很慢,我会在汇编中重写它,它会通过魔法来快速完成":它必须仔细编写汇编,写入知道它的速度快而它的速度慢在您的特定架构上,并牢记现代处理器的所有复杂性(分支错误预测,乱序执行,......).通常,由初学者到中型程序集编程器编写的程序集将比由优秀的现代优化编译器生成的最终机器代码慢.x86上的性能通常非常复杂,应该留给那些知道他们做什么的人=>并且大多数都是编译器编写者.:) 例如,看看这个.
我知道处理器在基本x86指令集之上有不同的指令集.所有汇编语言都支持所有指令集吗?
我觉得你在这里混淆了一些东西.许多(=所有现代)x86处理器都支持x86在定义原始指令集之后引入的附加指令和指令集.实际上,现在几乎所有的x86软件都被编译为利用后奔腾功能; 您可以使用CPUID指令查询处理器以查看它是否支持某些功能.显然,如果你想使用助记符来进行一些较新的指令集指令,你的汇编程序(即在实际机器代码中翻译助记符的软件)必须要注意它们.
相反,如果您正在讨论其他系列处理器的其他(非x86)指令集,那么每个汇编器应该支持目标处理器可以运行的指令.并非所有汇编语言的指令都可以直接替换其他语言,并且通常将汇编代码从架构移植到另一个架构代码通常是一项艰巨而艰巨的工作.
有多少汇编语言?
从理论上讲,每个处理器系列至少有一种方言.请记住,同一汇编语言也有不同的表示法; 例如,以下两条指令是用AT&T和Intel表示法编写的相同x86内容:
mov $4, %eax // AT&T notation
mov eax, 4 // Intel notation
Run Code Online (Sandbox Code Playgroud)
如何在程序集中编写例程,然后将其编译为对象/二进制代码?
如果要在使用其他语言编写的应用程序中嵌入例程,则应使用该语言提供的工具,在C/C++中使用asm块.
相反,如果你想在程序集中编写一个完整的应用程序,那么你必须按照你想要使用的汇编程序的语法规则来编写程序集.
我们怎么知道我们在汇编中编写的代码可能是最快的?
从理论上讲,因为它是最接近裸机的,所以你可以使机器完全符合你的要求,而不需要编译器考虑到在某些特定情况下无关紧要的语言特性.在实践中,由于机器通常比汇编语言暴露的复杂得多,正如我所说的那样,汇编语言通常比编译器生成的机器代码慢,这考虑了普通程序员不知道的许多细微之处.
我忘记了:知道阅读汇编,至少一点点,在调试优化器坏了/只在发布版本中出现的奇怪问题时非常有用/你必须处理heisenbugs /当源 -级别调试不可用或其他类似的东西; 看看这里的评论.
英特尔和x86在反向兼容性方面都很重要,这肯定帮助了他们,但同时又大大受伤.8088/8086到286到386,到486,pentium,pentium pro等的内部每次都有一些重新设计.早期为操作系统添加保护机制,以保护应用程序彼此和内核,然后通过添加执行单元,超标量和随附的所有内容,多核处理器等来保护性能.过去是真正的单一AX在原始处理器中注册变成谁知道现代处理器中有多少不同的东西.最初你的程序是按照写的顺序执行的,今天,它被切割和切片并且以这样的方式并行执行,使得所呈现的指令的意图得到尊重,但是执行可以是不正常的并且是并行的.在表面上埋藏的许多新技巧似乎是一个非常古老的指令集.
指令集从8/16位根变为32位,变为64位,因此汇编语言也必须改变.例如,将EAX添加到AX,AH和AL.偶尔会添加其他说明.但原始的加载,存储,添加,减去和/或等指令都在那里.我很长时间没有完成x86,并且看到语法已经改变和/或特定的汇编程序搞砸了x86语法而感到震惊.有很多工具,所以如果一个人与您正在使用的书籍或网页不匹配,那么就会有一个.
因此,考虑到这个系列的汇编语言是对与错,汇编语言可能已经改变了语法并且不一定是反向兼容的,但是指令集或机器语言或其他类似术语(汇编代表的操作码/位)将说现代x86处理器仍然支持大部分原始指令集.286特定的细微差别可能不会像特定代的其他新功能那样起作用,但核心指令,加载,存储,添加,减去,推送,弹出等等仍然可以工作并将继续工作.我觉得"沿着车道中心行驶"更好,不要进入芯片或工具特定的酥油机功能,使用基本的无聊,从语言的时间语法开始就一直工作.
因为家族中的每一代都在尝试某些功能,通常是性能,各个指令分发给各个执行单元的方式改变......每一代...为了手动调整汇编程序的性能,试图用 - 编译器,充其量是困难的.您需要有关正在调整的特定处理器的详细信息.从早期的x86天到现在,不幸的是,使代码在一个芯片上执行得更快的原因往往会导致下一代运行速度变慢.也许这是伪装的营销工具,不确定,"购买热门的新处理器,其成本是现在的两倍,宣传时钟速度的两倍,但运行相同的Windows副本的速度要慢30%.这样做的另一个副作用是,此时您不能使用一个C程序并创建一个在所有x86处理器上快速运行的二进制文件,因为您需要调整特定处理器的性能,这意味着您至少需要告诉编译器优化和优化家庭.就像窗户或办公室,或者你作为二进制文件分发的东西,你可能不会或不想以某种方式将同一程序的几个不同调整的副本埋在一个包或一个二进制文件中...沿着道路中心行驶.这样做的另一个副作用是,此时您不能使用一个C程序并创建一个在所有x86处理器上快速运行的二进制文件,因为您需要调整特定处理器的性能,这意味着您至少需要告诉编译器优化和优化家庭.就像窗户或办公室,或者你作为二进制文件分发的东西,你可能不会或不想以某种方式将同一程序的几个不同调整的副本埋在一个包或一个二进制文件中...沿着道路中心行驶.
作为所有硬件改进的结果,最好不要尝试将编译器输出或手动汇编器调整到任何一个芯片.平均而言,硬件改进将弥补编译器调优的不足,同样的程序希望每一代运行速度更快一些.其中一家芯片供应商过去的目标是让今天流行的编译二进制文件明天运行得更快,另一家供应商改进了内部组件,如果你重新编译今天新内部的源代码,你明天就可以跑得更快.供应商之间的那些活动并不一定会持续下去,每一代今天的二进制文件运行速度较慢,但明天重新编译源代码的速度相同或更慢.它将运行明天重写程序更快,有时与相同的编译器有时你需要明天编译器.
那么我们如何才能知道特定的编译或手工编译程序是否尽可能快?我们不,实际上对于x86你可以保证它不是,在家庭中的一个芯片上运行它很慢,在另一个上运行它可能是快速的.x86与否,除了你在微控制器上找到的非常短的程序或非常确定的程序之外,你不能肯定地说这是最快的解决方案.例如,高速缓存非常难以调整,以及它背后的内存,特别是在PC上,用户可以选择各种大小,速度,等级,库等,并调整BIOS设置以更改更多设置,真的无法告诉编译器为此调整.因此,即使在同一台计算机上,同一个处理器使用相同的编译二进制文件,您也可以转动某些旋钮并使该程序运行得更快或更慢.改变处理器系列,更换芯片组,主板等等.没有办法调整这么多变量.x86 pc业务的性质变得太混乱了.
其他芯片系列几乎没有问题.有些可能但不是全部.所以这些不是一般性陈述,而是针对x86芯片系列.x86系列不是例外.可能是您想要学习的最后一个汇编器/指令集.
关于这个主题有大量的网站和书籍,不能说一个比另一个好.我从英特尔的原始8088/86书籍中学到了经验,然后是386和486本书,之后没有找到英特尔书籍(或任何其他嘘声).您将需要一个指令集引用,以及一个像nasm或gas这样的汇编程序(gnu汇编程序,是大多数基于gcc的编译器工具链附带的binutils的一部分).至于C到/来自汇编程序接口你可以通过实验没有其他任何结果,编写一个带有一些小C函数的小C程序,反汇编或编译到汇编程序,并查看什么寄存器和/或堆栈如何用于在函数之间传递参数.保持您的功能简单,只使用几个参数,您的汇编程序可能会正常工作.如果没有查看调用代码的函数的汇编程序并找出参数的位置.在某个地方都有很好的记录,这些日子可能比旧的好得多.在8088/86早期,您拥有小型,小型,中型,大型和大型编译器模型,并且调用约定可能各不相同.除了下一个编译器之外,watcom(以前的zortech和其他名字)通过寄存器传递,borland和microsoft在堆栈上传递,如果不相同则非常接近.现在有32位和64位平面存储空间和标准,你可以使用一个模型而不必记住所有的细微差别(只有一组细微差别).内联汇编是一个选项,但从C编译器到C编译器不等,让它正常有效地工作比在自己的文件中编写汇编程序更困难.gcc和其他编译器可能允许你将汇编程序文件放在C编译器命令行上,就像它只是另一个C文件一样,它会找出你给它的内容并将它传递给汇编程序.也就是说,如果您不想自己调用汇编程序并将对象放在C编译器命令行上.
如果没有别的东西反汇编很多简单的函数,添加一些参数并返回它们等.更改编译器优化设置,看看它如何改变所使用的指令,通常是戏剧性的.从调试和性能的角度来看,即使你无法从头开始编写汇编程序也能读取它是非常有价值的.
并非所有处理器的编译器都是好的.例如Gcc是一种适合所有人的尺寸,就像一个袜子或球帽,一个尺寸并不适合任何人.对大多数目标都有好处,但不是很好.所以很可能比使用手动调整汇编程序的编译器做得更好,但平均而言,很多代码都不会赢.这适用于大多数处理器,它们更具确定性,而不仅仅是x86系列.它不是关于更少的指令,更少的指令不一定等于更快,甚至比普通的编译器更好,从长远来看你必须了解缓存,获取,解码,执行状态机,存储器接口,存储器本身等.编译器优化关闭它很容易生成比编译器更快的代码,所以你应该只使用优化器,但也要明白这会增加编译器犯错误的风险.您需要非常了解该工具,这可以追溯到经常解压缩,以了解您的C代码和您今天使用的编译器如何相互交互.没有编译器是完全符合标准的,因为标准本身是模糊的,使得语言的某些特性由编译器自行决定(在中间行驶并且不使用该语言的那些部分).
从问题本质的底线来看,我建议用一些小函数编写一堆小函数或程序,编译成汇编程序或编译成一个对象并反汇编以查看编译器的作用.务必在每个程序上使用不同的优化设置.获得有关指令集的工作阅读知识(授予编译器或反汇编程序的asm输出,有很多额外的漏洞妨碍了可读性,你必须看过去,如果你想要你几乎不需要它写汇编程序).如果这是您的目标,那么在您可以期望定期超越编译器之前,请给自己5到20年的学习和实验.到那时你会了解到,特别是对于这个芯片系列来说,这是徒劳的努力,你赢得了一些,但大多数都输了...... 将相同的代码编译(汇编)到其他芯片系列(例如arm和mips)是有益的,并且总体上感觉C代码编译得很好,C代码编译得不好,并使你的C编译编程更好,而不是试图使汇编程序更好.还可以尝试其他编译器,如llvm.Gcc有很多怪癖,很多人认为是C语言标准,但它们是特定编译器的细微差别或问题.能够阅读和分析编译器的组件输出及其选项将提供这方面的知识.因此,我建议您学习指令集的阅读知识,而不必学习从头开始编写.什么C代码编译得不好,并使你的C编程更好,而不是试图使汇编程序更好.还可以尝试其他编译器,如llvm.Gcc有很多怪癖,很多人认为是C语言标准,但它们是特定编译器的细微差别或问题.能够阅读和分析编译器的组件输出及其选项将提供这方面的知识.因此,我建议您学习指令集的阅读知识,而不必学习从头开始编写.什么C代码编译得不好,并使你的C编程更好,而不是试图使汇编程序更好.还可以尝试其他编译器,如llvm.Gcc有很多怪癖,很多人认为是C语言标准,但它们是特定编译器的细微差别或问题.能够阅读和分析编译器的组件输出及其选项将提供这方面的知识.因此,我建议您学习指令集的阅读知识,而不必学习从头开始编写.能够阅读和分析编译器的组件输出及其选项将提供这方面的知识.因此,我建议您学习指令集的阅读知识,而不必学习从头开始编写.能够阅读和分析编译器的组件输出及其选项将提供这方面的知识.因此,我建议您学习指令集的阅读知识,而不必学习从头开始编写.
你需要从硬件的角度来看待它,汇编语言是根据CPU可以做什么而创建的。每次在 CPU 中创建新功能时,都会创建适当的汇编指令以便可以使用它。
因此,汇编非常依赖于 CPU,C++ 等高级语言提供了对此的抽象,使我们不必考虑 CPU 指令等细节,编译器也会生成优化的汇编代码。
编辑:
汇编语言有多少种?有多少可以与其他语言兼容?
有多少种不同类型的CPU。第二个问题我没听懂。汇编本身不与任何其他语言交互,输出是机器代码。
有人如何用汇编语言编写例程,然后将其编译为对象/二进制代码?
其原理与使用任何其他编译语言编写类似,您使用汇编指令创建一个文本文件,使用汇编器将其编译为机器代码。然后将其与最终的运行时库链接。
然后,人们如何从 C 或 C++ 等语言引用该汇编代码中的函数/例程?
C++ 和 C 提供内联汇编,因此无需链接,但如果要链接,则需要遵循与宿主语言相同/相似的调用约定来创建汇编对象。例如,某些语言在调用函数时将参数按一定顺序推送到堆栈上的函数,因此您也必须执行相同的操作。
我们如何知道用汇编语言编写的代码是最快的?
因为它最接近实际的硬件。当您处理高级语言时,您不知道编译器将如何处理您的 for 循环。然而,他们在优化代码方面往往比人类做得更好(当然,在非常特殊的情况下,你可能会得到更好的结果)。
| 归档时间: |
|
| 查看次数: |
14233 次 |
| 最近记录: |