1.简介
本手册详细介绍了如何编写高度优化的汇编代码,重点介绍奔腾®系列微处理器
这里的所有信息都是基于我的研究,许多人为本手册提供了有用的信息和错误更正,我在获得任何新的重要信息后进行更新,因此,本手册比其他类似来源更准确、详细、准确和易于理解,它还包含许多其他地方找不到的详细描述。这些信息使您能够使用各种方法精确计算一小段代码所花费的时钟周期数。然而,我不能保证手册中的所有信息都是准确的:有些时间测试很难或不可能精确测量,我看不到《英特尔手册》作者的内部技术文档
本手册讨论奔腾处理器的以下版本:
缩写词
名称
普兰
普通老式奔腾(不含MMX)
PMMX
带MMX的奔腾
PPro公司
奔腾Pro
PII公司
奔腾II(包括赛扬和至强)
PIII
奔腾III(包括一些等效CPU)
本手册使用MASM的汇编语法没有正式的x86汇编语言,但这是您可以接受的最接近的汇编语言,因为几乎所有汇编程序都有MASM的兼容模式(但是,我不建议使用MASM的5.10版本,因为它在32位模式下有严重的错误。最好使用TASM或后续版本的MASM)
手册中的一些评论似乎是对英特尔的批评,但这并不意味着其他产品会更好奔腾系列微处理器可以在评估分数中获得更好的比较值,有更好的文档和更多可测试的功能出于这些原因,我或其他人不会对类似产品进行比较测试
汇编语言编程比使用高级语言复杂得多,使bug变得容易,但我现在提醒你,找到bug很难!我假设读者有汇编编程的经验如果没有,请阅读一些编译书籍并编写一些代码,以获得一些编译经验,然后再进行复杂的优化
pplain和pmmx芯片的硬件设计具有许多专为某些常见指令或指令对设计的功能,而不是使用那些通用优化模块。因此,用于此设计的软件优化规则很复杂8位复杂指令集cpu设计,也有许多例外,但这样做可能会带来巨大的好处PPro、PII和PIII处理器具有非常不同的设计。他们将使用无序执行来进行大量优化工作,但这些处理器设计带来了许多潜在的瓶颈。因此,对这些处理器进行手动优化将获得许多好处,奔腾4处理器也使用了另一种设计。奔腾4的优化指南与以前版本的指南有很大不同本手册不包括奔腾4-请参阅英特尔手册
在将代码转换为汇编之前,请确保您的算法得到了足够的优化。通常,您可以对算法进行优化,以提高代码的效率,而不是通过转换为汇编获得的效率
其次,您必须找到程序最关键的部分通常99%的CPU时间都花在程序的最内部循环中。在这种情况下,您只需优化循环并用高级语言编写其他所有内容。一些汇编程序在程序的错误部分上花费了大量精力。他们努力的唯一结果是程序变得更难调试和维护
如果程序的关键部分不太明显,如果发现瓶颈在于磁盘操作,可以使用profile来查找,然后可以尝试修改程序,使磁盘操作集中且连续,提高磁盘缓冲区的命中率,如果瓶颈是图像输出,则不必使用汇编编写代码,您可以尝试找到一种方法来减少对映像函数的调用次数一些高级语言编译器为指定的处理器提供了相对较好的优化,但手动优化效果更好
请不要把你的编程问题发给我我不会帮你做作业的
祝你在下面的阅读中好运
文学作品
英特尔的WWW、打印文本或CD-ROM上有许多有用的文档和教程,我建议您研究这些文档,以了解微处理器的结构。然而,英特尔的文档并不总是正确的,尤其是那些有很多错误的教程(很明显,英特尔没有测试他们的示例)
我不会在这里给出URL,因为文件的位置经常更改,您可以使用开发人员intel。使用上的链接上的搜索工具查找所需的文档。Com或
有些文档是Pdf格式的如果您没有显示或打印Pdf的工具,可以下载acrobat file reader
使用MMX和XMM(SIMD)指令优化特殊程序在多个手册中进行了描述各种手册和教程描述了它们的指令集
VTune是英特尔用来优化代码的软件工具。我没有测试,所以这里不是评估用的
在新闻组comp land中,有比Intel更多的有用信息。asm。这些资源列在x86常见问题解答中。Internet上的其他资源也有以下链接
用汇编语言调用
您可以使用联机汇编或在汇编中编写整个子例程,然后连接到您的项目如果您选择后者,建议您使用可以直接将高级语言编译成程序集的编译器。通过这种方式,您可以获得所有C++编译器都可以做到的函数的正确调用原型
传递参数的方法取决于调用形式:
呼叫模式
堆栈中参数的顺序
谁将删除参数
_cdecl公司
第一个参数位于低位地址
呼叫者
_stdcall公司
第一个参数位于低位地址
子例程
_快速呼叫
编译器分配
子例程
_帕斯卡
第一个参数位于高位地址
子例程
编译器命名的函数调用原型和函数名可能非常复杂。有许多不同的调用转换规则,如果从C++调用汇编语言子例程8位复杂指令集cpu设计,则不同的编译器彼此不兼容,最好的方法是使用extern“C”和\ucdel定义兼容性和一致性汇编代码的函数名前面必须有下划线(),并且在外部编译期间添加区分大小写的选项(选项MX),例如:
; extern "C" int _cdecl square (int x); _square PROC NEAR ; 整型平方函数 PUBLIC _square MOV EAX, [ESP+4] IMUL EAX RET _square ENDP
如果需要重载函数、重载运算符、方法和其他特定于C++的东西,您必须首先用C++编写代码,然后由编译器将其编译成汇编代码,以获得正确的连接信息和调用模型。这些信息因编译器而异,如果您希望汇编函数使用其他调用原型而不是外部“C”,则很少有文档记录,并且不同的编译器可以调用\Cdecl,因此,您需要为每个编译器编写一个名称,例如,重载一个平方函数:
; int square (int x); SQUARE_I PROC NEAR ; 整数 square 函数 @square$qi LABEL NEAR ; Borland 编译器的连接名字 ?square@@YAHH@Z LABEL NEAR ; Microsoft 编译器的连接名字 _square__Fi LABEL NEAR ; Gnu 编译器的连接名字 PUBLIC @square$qi, ?square@@YAHH@Z, _square__Fi MOV EAX, [ESP+4] IMUL EAX RET SQUARE_I ENDP ; double square (double x); SQUARE_D PROC NEAR ; 双精度浮点 square 函数 @square$qd LABEL NEAR ; Borland 编译器的连接名字 ?square@@YANN@Z LABEL NEAR ; Microsoft 编译器的连接名字 _square__Fd LABEL NEAR ; Gnu 编译器的连接名字 PUBLIC @square$qd, ?square@@YANN@Z, _square__Fd FLD QWORD PTR [ESP+4] FMUL ST(0), ST(0) RET SQUARE_D ENDP
此方法之所以有效,是因为所有这些编译器在默认情况下都使用重载函数\uCDECL调用。但是,对于不同的编译器,方法(成员函数)甚至调用模式都不同(Borland和GNU编译器使用#Cdecl模式,';此';指针是第一个参数,而Microsoft使用#stdcall模式和';此';指针放在ECX中)
通常,当您使用以下项时,不要期望不同的编译器在对象文件级别兼容:长双精度、成员指针、虚拟机制、新建、删除、异常、系统函数调用或标准库函数
16位模式dos和windows、C或C++寄存器使用:
Ax是一个16位的返回值,DX:Ax是一个32位的返回值,st(0)是一个浮点返回值。寄存器Ax、BX、CX、DX和ES的数学标记可以由进程更改;其他寄存器必须保存和还原。如果不更改Si、Di、BP、DS和SS,一个进程不会影响另一个进程
在32位模式windows、C++和其他编程语言中注册使用情况:
整数返回值放在eax中,浮点返回值放在St(0))中。进程可以修改寄存器eax、ECX、EDX(无ebx);必须保留并还原其他寄存器。段寄存器不能更改,即使临时CS、DS、ES和SS所有指向当前段组的点FS都由操作系统使用,GS不使用,但它是保留的。进程可以在以下限制下更改标志位:方向标志默认为0.可以临时修改方向标志,但必须在任何调用或返回之前清除中断标志。必须清除中断标志。浮点寄存器堆栈在程序入口为空,在返回时也应为空,st除外(0)除非用于返回值。MMX寄存器可以更改,但在返回或调用可能使用浮点运算的进程之前,必须先用EMMS清除。所有XMM寄存器都可以由进程修改。XMM寄存器中传输参数和返回值的描述在Intel的应用程序文档AP 58中更改而不更改ebx、ESI、EDI、EBP和所有段寄存器另一个过程调用
调试和验证
正如您所发现的,调试汇编代码是非常困难和令人沮丧的,我建议您首先用高级语言编写一小段需要优化的代码的子例程,然后编写一小段
请登录后发表评论
注册
社交帐号登录