内容简介:3. 汇编编程基础3.1. 可用的汇编器X86指令集有几个汇编器可用,但目前它们没有一个好到被一致推荐。汇编程序员处在x86汇编没有统一语法的不幸境地之中。不同的汇编器使用不同的语法变体。最常用的汇编器有如下。
3. 汇编编程基础
3.1. 可用的汇编器
X86指令集有几个汇编器可用,但目前它们没有一个好到被一致推荐。汇编 程序员 处在x86汇编没有统一语法的不幸境地之中。不同的汇编器使用不同的语法变体。最常用的汇编器有如下。
MASM
这个Microsoft汇编器包括在Microsoft C++编译器中。有时可以通过下载Microsoft Windows驱动套装(WDK),或平台软件开发套装(SDK),或作为免费Visual C++精简版的扩展,获得免费版本。在Windows世界里,MASM已经成为事实上的标准许多年,大多数Windows编译器的汇编输出使用MASM语法。MASM有许多先进的语言特性。由于继承自用于8086处理器的最早期汇编器,语法有点凌乱且不一致。Microsoft仍然在维护MASM,以对Windows提供一套完整的开发工具,但这显然无利可图,MASM的维护被保持在最低限度。新指令集仍然被定期添加,但64位版本有几个缺陷。更新的版本仅在安装了编译器时可以运行,且仅在Windows XP或更新系统上。版本6与更早的版本可以运行在任何系统上,包括使用Windows模拟器的Linux。这样的版本在网上流传。
GAS
Gnu汇编器是包括在大多数Linux,BSD及Mac OS X发布的Gnu Binutils包的部分。Gnu编译器产生的汇编输出,在链接前经过Gnu汇编器。传统上,Gnu汇编器使用对机器生成代码工作良好的AT&T语法,但它产生的汇编对人非常不方便。AT&T语法中操作数的次序,与所有其他x86汇编器,以及Intel与AMD公布的指令文档给出的,都不一样。它使用各种前缀,像%与$来说明操作数类型。Gnu汇编器对所有x86平台都可用。
幸运地,更新版本的Gnu汇编器有一个使用Intel语法的选项。Gnu-Intel语法几乎与MASM语法完全相同。Gnu-Intel语法仅定义了指令代码的语法,没有指示、函数、宏等。指示仍然使用旧的Gnu-AT&T语法。指定.intel_syntax noprefix来使用Intel语法。在离开C或C++代码中的内联汇编时,指定.att_syntax prefix返回AT&T语法。
NASM
NASM是一个免费、开源的汇编器,支持多个平台与目标文件格式。相比MASM语法,其语法更清晰、更一贯。NASM定期更新指令集。NASM比MASM有更少的高级特性,但对大多数目的,它已足够。我将推荐NASM作为一个非常好的多平台汇编器。
YASM
YASM非常类似于NASM,使用完全相同的语法。在某些时期,YASM是第一个支持新指令集的,在其他时期是NASM。YASM与NASM可互换使用。
FASM
FASM汇编器是另一个开源的多平台汇编器。其语法不与其他汇编器兼容。FASM本身以汇编写就——一个诱人的想法,但不幸的是,这使得它的开发与维护不那么有效率。
WASM
WASM汇编器包含在Open Watcom C++编译器中。其语法类似MASM,但有些不同。没有紧跟时代。
JWASM
JWASM是WASM的进一步开发。它完全与MASM语法兼容,包括先进的宏与高级指示。如果要求MASM语法,JWASM是一个好的选择。JWASM可用一个称为Easy Code的集成开发环境(IDE)。
TASM
Borland Turbo汇编器包含在CodeGear C++ Builder里。它与MASM语法兼容,除了一些较新的语法补充。TASM不再维护,但仍然可用。它过时了,不支持当前的指令集。
GOASM
GoAsm是用于32与64位Windows的免费汇编器,包括资源编译器,链接器与调试器。其语法类似于MASM,但不完全兼容。目前,它没有支持最新的指令集。一个称为Easy Code的集成开发环境(IDE)也是可用的。
HLA
High Level Assembler实际上是一个支持类似汇编语句,产生汇编输出的高级语言编译器。在发明它的时候,这可能是一个好主意,但今天最好的C++编译器都支持固有函数,我相信不再需要HLA。
内联汇编
Microsoft与Intel C++编译器支持使用MASM语法子集的内联汇编。只要在汇编代码中插入名字,访问C++变量、函数及标签是可能的。这很容易,但不支持C++寄存器变量。参考第29页。
Gnu编译器支持可访问所有指令以及Gnu汇编器Intel与AT&T语法形式指示的内联汇编。从汇编访问C++变量,使用相当复杂的方法。
用于 Linux 与Mac系统的Intel编译器支持Microsoft与Gnu形式的内联汇编。
C++ 中的固有函数
这是组合低级代码与高级代码最新以及最便利的方式。固有函数是机器指令的高级语言表示。例如,可以通过调用等效于向量加法汇编指令的固有函数,在C++中进行一个向量加法。另外,定义一个带有重载+操作符的向量类,使只要通过写+就能进行向量加法,是可能的。Microsoft,Intel,Gnu与Clang编译器都支持固有函数。参考第27页与手册1《优化C++软件》。
选择哪个汇编器?
在大多数情形里,最简单的解决方案是在C++代码中使用固有函数。编译器可以负责大部分优化,使程序员可以集中精力在选择最好的算法,并把数据组织为向量。系统程序员可以通过使用固有函数访问系统指令,无需使用汇编语言。
在真正需要低级编程时,比如在高度优化的函数库或设备驱动中,你可以使用汇编器。
最好使用一个与你使用的C++编译器兼容的汇编器。这使你可以使用这个编译器把C++翻译为汇编,进一步优化汇编代码,然后汇编之。如果汇编器与编译器产生的语法不兼容,那么可以通过这个编译器产生一个目标文件,把目标文件反汇编为你需要的汇编语法。Objconv反汇编器支持几个不同的语法方言。
对许多用途,NASM汇编器都是好的选择,因为它支持许多平台与目标文件格式,它有良好的维护,经常更新到最新的指令集。
本手册中的例子使用MASM语法,除非另外指出。MASM语法在msdn.microsoft.com上的《Microsoft Macro Assembler Reference》中描述。
各种语法手册、编程手册与论坛的链接,参考 www.agner.org/optimize 。
-
- 寄存器集与基本指令
16 位模式中的寄存器
通用与整数寄存器
完整寄存器比特 0 - 15 |
部分寄存器比特 8 - 15 |
部分寄存器比特 0 - 7 |
|
AX |
AH |
AL |
|
BX |
BH |
BL |
|
CX |
CH |
CL |
|
DX |
DH |
DL |
|
SI |
||
|
DI |
||
|
BP |
||
|
SP |
||
|
Flags |
||
|
IP |
表3.1. 16位模式中的通用寄存器
如果微处理器与操作系统支持,在16位模式中,32位寄存器也可用。不应该使用ESP的高位字,因为在中断期间,它不会被保存。
浮点寄存器
|
完整寄存器,比特 0 - 79 |
|
ST(0) |
|
ST(1) |
|
ST(2) |
|
ST(3) |
|
ST(4) |
|
ST(5) |
|
ST(6) |
|
ST(7) |
表3.2. 浮点栈寄存器
如果微处理器支持,MMX寄存器可能可用。如果微处理器与操作系统支持,XMM寄存器可能可用。
段寄存器
|
完整寄存器,比特 0 - 15 |
|
CS |
|
DS |
|
ES |
|
SS |
表3.3. 16位模式中的段寄存器
寄存器FS与GS可能可用。
32 位模式中的寄存器
通用与整数寄存器
完整寄存器比特 0 - 31 |
部分寄存器比特 0 - 15 |
部分寄存器比特 8 - 15 |
部分寄存器比特 0 - 7 |
|
EAX |
AX |
AH |
AL |
|
EBX |
BX |
BH |
BL |
|
ECX |
CX |
CH |
CL |
|
EDX |
DX |
DH |
DL |
|
ESI |
SI |
||
|
EDI |
DI |
||
|
EBP |
BP |
||
|
ESP |
SP |
||
|
EFlags |
Flags |
||
|
EIP |
IP |
表3.4. 32位模式中的通用寄存器
浮点与64 位向量寄存器
|
完整寄存器,比特 0 - 79 |
部分寄存器,比特 0 - 63 |
|
ST(0) |
MM0 |
|
ST(1) |
MM1 |
|
ST(2) |
MM2 |
|
ST(3) |
MM3 |
|
ST(4) |
MM4 |
|
ST(5) |
MM5 |
|
ST(6) |
MM6 |
|
ST(7) |
MM7 |
表3.5. 浮点与MMX寄存器
如果微处理器支持,MMX寄存器才可用。ST与MMX寄存器不能用在代码的同一部分。使用MMX寄存器的代码部分,与使用ST寄存器的后续部分,必须通过EMMS指令隔开。
128 与256 位整数与浮点向量寄存器
|
完整或部分寄存器 比特 0 - 127 |
完整或部分寄存器 比特 0 - 255 |
完整 比特 0 - 511 |
|
XMM0 |
YMM0 |
ZMM0 |
|
XMM1 |
YMM1 |
ZMM1 |
|
XMM2 |
YMM2 |
ZMM2 |
|
XMM3 |
YMM3 |
ZMM3 |
|
XMM4 |
YMM4 |
ZMM4 |
|
XMM5 |
YMM5 |
ZMM5 |
|
XMM6 |
YMM6 |
ZMM6 |
|
XMM7 |
YMM7 |
ZMM7 |
表3.6. 32位模式中的XMM,YMM与ZMM寄存器
仅在微处理器与操作系统都支持,XMM才可用。对单精度或双精度,标量浮点指令分别仅使用XMM寄存器的32或64位。仅在处理器与操作系统都支持AVX指令集时,YMM寄存器才可用。仅处理器支持AVX-521指令集时,ZMM寄存器可用。
段寄存器
|
完整寄存器,比特 0 - 15 |
|
CS |
|
DS |
|
ES |
|
FS |
|
GS |
|
SS |
表3.7. 32位模式中的段寄存器
64 位模式中的寄存器
通用与整数寄存器
|
完整寄存器 比特 0 - 63 |
部分寄存器 比特 0 - 31 |
部分寄存器 比特 0 - 15 |
部分寄存器 比特 8 - 15 |
部分寄存器 比特 0 - 7 |
|
RAX |
EAX |
AX |
AH |
AL |
|
RBX |
EBX |
BX |
BH |
BL |
|
RCX |
ECX |
CX |
CH |
CL |
|
RDX |
EDX |
DX |
DH |
DL |
|
RSI |
ESI |
SI |
SIL |
|
|
RDI |
EDI |
DI |
DIL |
|
|
RBP |
EBP |
BP |
BPL |
|
|
RSP |
ESP |
SP |
SPL |
|
|
R8 |
R8D |
R8W |
R8B |
|
|
R9 |
R9D |
R9W |
R9B |
|
|
R10 |
R10D |
R10W |
R10B |
|
|
R11 |
R11D |
R11W |
R11B |
|
|
R12 |
R12D |
R12W |
R12B |
|
|
R13 |
R13D |
R13W |
R13B |
|
|
R14 |
R14D |
R14W |
R14B |
|
|
R15 |
R15D |
R15W |
R15B |
|
|
RFlags |
Flags |
|||
|
RIP |
表3.8. 64位模式中的寄存器
高8位寄存器AH,BH,CH,DH仅可以用在没有REX前缀的指令中。注意修改一个32位部分寄存器将寄存器余下部分(比特32 ~ 63)置零,但修改一个8位或16位部分寄存器不会影响该寄存器余下部分。这可由以下序列来展示:
; Example 3.1. 8, 16, 32 and 64 bit registers
mov rax, 1111111111111111H ; rax = 1111111111111111H
mov eax, 22222222H ; rax = 0000000022222222H
mov ax, 3333H ; rax = 0000000022223333H
mov al, 44H ; rax = 0000000022223344H
这个不一致有一个很好的理由。将寄存器不使用的部分置零,比不改变它更高效,因为这消除了对之前值的一个假依赖。但重置寄存器未使用部分的原则不能扩展到16位及8位部分寄存器,因为这将破坏与32位及16位模式的前向兼容。
唯一可以有64位立即数的指令是MOV。其他整数指令仅能有32位符号扩展操作数,例如:
; Example 3.2. Immediate operands, full and sign extended
mov rax, 1111111111111111H ; Full 64 bit immediate operand
mov rax, -1 ; 32 bit sign-extended operand
mov eax, 0ffffffffH ; 32 bit zero-extended operand
add rax, 1 ; 8 bit sign-extended operand
add rax, 100H ; 32 bit sign-extended operand
add eax, 100H ; 32 bit operand. result is zero-extended
mov rbx, 100000000H ; 64 bit immediate operand
add rax, rbx ; Use an extra register if big operand
使用16位符号扩展操作数是不可能的。如果需要向一个64位寄存器加一个立即数,如果这个值太大,不能放入32位符号扩展操作数,必须首先将这个值移入另一个寄存器。
浮点与64 位向量寄存器
|
完整寄存器,比特 0 - 79 |
部分寄存器,比特 0 - 63 |
|
ST(0) |
MM0 |
|
ST(1) |
MM1 |
|
ST(2) |
MM2 |
|
ST(3) |
MM3 |
|
ST(4) |
MM4 |
|
ST(5) |
MM5 |
|
ST(6) |
MM6 |
|
ST(7) |
MM7 |
表3.9. 浮点与MMX寄存器
ST与MMX寄存器不能用在代码的同一个部分。使用MMX寄存器的代码部分必须通过一条EMMS指令与使用ST寄存器的后续部分隔开。对64位Windows,ST与MMX寄存器不能用在设备驱动中。
128 位与256 位整数与浮点向量寄存器
|
完整或部分寄存器 比特 0 - 127 |
完整或部分寄存器 比特 0 - 255 |
完整寄存器 比特 0 - 511 |
|
XMM0 |
YMM0 |
ZMM0 |
|
XMM1 |
YMM1 |
ZMM1 |
|
XMM2 |
YMM2 |
ZMM2 |
|
XMM3 |
YMM3 |
ZMM3 |
|
XMM4 |
YMM4 |
ZMM4 |
|
XMM5 |
YMM5 |
ZMM5 |
|
XMM6 |
YMM6 |
ZMM6 |
|
XMM7 |
YMM7 |
ZMM7 |
|
XMM8 |
YMM8 |
ZMM8 |
|
XMM9 |
YMM9 |
ZMM9 |
|
XMM10 |
YMM10 |
ZMM10 |
|
XMM11 |
YMM11 |
ZMM11 |
|
XMM12 |
YMM12 |
ZMM12 |
|
XMM13 |
YMM13 |
ZMM13 |
|
XMM14 |
YMM14 |
ZMM14 |
|
XMM15 |
YMM15 |
ZMM15 |
|
ZMM16 |
||
|
ZMM17 |
||
|
ZMM18 |
||
|
ZMM19 |
||
|
ZMM20 |
||
|
ZMM21 |
||
|
ZMM22 |
||
|
ZMM23 |
||
|
ZMM24 |
||
|
ZMM25 |
||
|
ZMM26 |
||
|
ZMM27 |
||
|
ZMM28 |
||
|
ZMM29 |
||
|
ZMM30 |
||
|
ZMM31 |
表3.10. 64位模式中的XMM,YMM与ZMM寄存器
对单精度或双精度,标量浮点指令仅分别使用XMM寄存器的32或64位。仅当处理器与操作系统支持AVX指令集时,YMM寄存器才可用。仅当处理器支持AVX512指令集时,ZMM寄存器才可用。在处理器与汇编器都支持AVX512时,才可能使用XMM16-31与YMM16-32。
段寄存器
|
完整寄存器,比特 0 - 15 |
|
CS |
|
FS |
|
GS |
表3.11. 64位模式中的段寄存器
段寄存器仅用于特殊目的。
以上所述就是小编给大家介绍的《[译]优化汇编例程(2)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- iOS汇编入门教程(一)ARM64汇编基础
- iOS 汇编入门教程(一):ARM64 汇编基础
- iOS汇编入门教程(三)汇编中的 Section 与数据存取
- iOS汇编入门教程(二)在Xcode工程中嵌入汇编代码
- 汇编语言8086笔记
- python编程(反汇编)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP for the World Wide Web, Second Edition (Visual QuickStart Gu
Larry Ullman / Peachpit Press / 2004-02-02 / USD 29.99
So you know HTML, even JavaScript, but the idea of learning an actual programming language like PHP terrifies you? Well, stop quaking and get going with this easy task-based guide! Aimed at beginning ......一起来看看 《PHP for the World Wide Web, Second Edition (Visual QuickStart Gu》 这本书的介绍吧!