64位换出64位寄存器
- Displacement,单独的位移表示对操作数的直接(未计算的)偏移。因为位移是在指令中编码的,这种形式的地址有时被称为绝对或静态地址。它通常用于访问静态分配的标量操作数。(全局变量或静态变量)
- Base,单独的基址代表操作数的间接偏移。由于基址寄存器中的值可以变化,它可以用于变量和数据结构的动态存储。(指针获取对应变量的值时)
- Base Displacement,基址寄存器加位移可以一起用于一下目的:
1、当元素大小不是2、4或8字节时,作为一个数组的索引(位移组件编码到数组开始的静态偏移)基址寄存器保存了计算的结果来确定数组中某个特定元素的偏移量。
2、要访问一个记录的某个字段:基址寄存器持有记录的起始地址,而位移是该字段的静态偏移。
3、这种组合的一个重要特例是对程序函数中的参数的访问。在这里,EBP寄存器是基址寄存器的最佳选择。
- (Index ∗ Scale) Displacement,当元素大小为2、4或8字节时,这种地址模式提供了一种有效的方法来索引静态数组。位移定位到数组的开始,索引寄存器保存所需数组元素的下标,处理器通过应用缩放系数自动将下标转换为索引。
- Base Index Displacement,同时使用两个寄存器可以支持二维数组(位移保存数组开头的地址)或记录数组的多个实例之一
- Base (Index ∗ Scale) Displacement,当数组的元素大小为2、4或8字节时,使用所有寻址组件可以对二维数组进行有效的索引。
- rip相对寻址(64位独有的),rip 的名称来自于(instruction pointer register,指令指针寄存器)。rip其实就是程序计数器(Program Counter, PC), 存放着下一条指令的地址 。不可以直接修改rip。即rip displacement的用法。
mov [rip 0x202a62],rdi //48 89 3D 62 2A 20 00
I/O端口:
每个外设都是通过读写其寄存器来控制的。外设寄存器也称为I/O端口,通常包括:控制寄存器、状态寄存器和数据寄存器三大类。
寄存器参与内存统一编址,访问寄存器就像访问一般的内存一样,所以,这种CPU没有专门用于设备I/O的指令。这就是所谓的“I/O内存”方式。另一类CPU,将外设的寄存器看成一个独立的地址空间,所以访问内存的指令不能用来访问这些寄存器,而要为对外设寄存器的读/写设置专用指令,如IN和OUT指令。这就是所谓的“ I/O端口”方式。
Intel支持以上两种方式。
// I/O端口
out 0x70, al
in al,0x70
MOV指令举例
在线汇编
//mov r/m8, r8
mov al, bh //88 F8
mov byte ptr [eBX], al //67 88 03
//move r/m16, r16
mov bx, cx
mov word ptr [ebx], cx //67 66 89 0B
//selects MOV r/m64, imm32
mov qword ptr [rsp 08h], 0 //48 C7 44 24 08 00 00 00 00
mov rax,1122334455667788H //48 B8 88 77 66 55 44 33 22 11
//selects MOV r/m32, imm32
mov dword ptr [rsp 08h], 0 //C7 44 24 08 00 00 00 00
mov eax,11223344H //B8 44 33 22 11
mov rax, [1122334455667788H] //48 A1 88 77 66 55 44 33 22 11
//mov moffs32*, eax
mov [11223344h],eax //A3 44 33 22 11 00 00 00 00
mov DS:[11223344h],eax //A3 44 33 22 11 00 00 00 00
//mov eax, moffs32*
mov eax, [11223344h] //A1 44 33 22 11 00 00 00 00
mov eax, DS:[11223344h] //A1 44 33 22 11 00 00 00 00
mov eax,[1122334455667788H] //A1 88 77 66 55 44 33 22 11
//mov rax, moffs64*
//Direct Memory-Offset MOVs
mov rax,[1122334455667788H] //48 A1 88 77 66 55 44 33 22 11
符号缩写说明:
- Op/En(Operand Encoding)
- r/m (register or memory)
- Sreg(segment register)
- moffs(Direct Memory-Offset)
Opcode列:
cb, cw, cd, cp, co, ct | 操作码后面的1字节(cb)、2字节(cw)、4字节(cd)、6字节(cp)、8字节(co)或10字节(ct)值。此值用于指定代码偏移量,也可能为代码段寄存器指定一个新值。 |
ib, iw, id, io | 一个1字节(ib)、2字节(iw)、4字节(id)或8字节(io)的立即操作数,用于操作码、ModR/M字节或标度索引字节之后的指令。操作码决定了操作数是否为有符号的值。所有字、双字和四字都以小端字节序为先。 |
rb, rw, rd, ro | 表示操作码字节的低3位用于编码没有modR/M字节的寄存器操作数。 该指令列出了操作码字节低3位的相应十六进制值为000b。在非64位模式下,一个寄存器代码,从0到7,被添加到操作码字节的十六进制值中。在64位模式下,表示REX.b的4位字段和opcode[2:0]字段编码指令的寄存器操作数。" ro "只适用于64位模式。 |
/r | 表示指令的ModR/M字节包含一个寄存器操作数和一个r/m操作数。 |
/digit | 0到7之间的数字表示指令的ModR/M字节只使用r/m(寄存器或内存)操作数。reg字段包含了为指令的操作码提供扩展的数字。 |
i | 当操作数之一是FPU寄存器堆的ST(i)时,浮点指令中使用的数字。数字i(范围从0到7)与加号左边给出的十六进制字节相加,形成一个操作码字节。 |
REX.W | 表示使用了影响操作数或指令语义的REX前缀。请注意,将传统指令提升到64位行为的REX前缀并没有在操作码栏中明确列出。 |
NP | 表示不允许使用66/F2/F3的前缀(超出指令操作码的一部分)。允许使用该指令。这样的使用将导致无效的操作码异常(#UD)或导致编码为不同的指令。 |
Instruction列:
rel8 | rel8 — 从指令结束前的128字节到指令结束后的127字节范围内的一个相对地址。 |
rel16, rel32 | 与指令装配在同一代码段内的相对地址。rel16 符号适用于操作数属性为16位的指令;rel32符号适用于操作数属性为32位的指令。 |
ptr16:16, ptr16:32 | 一个远指针,通常指向与指令不同的代码段。符号16:16表示指针的值有两部分。冒号左边的值是一个16位的选择器或用于代码段寄存器的值。右边的值对应于目标段内的偏移。当指令的操作数属性为16位时使用ptr16:16符号;当操作数属性为32位时使用ptr16:32符号。 |
r8 | 单字节通用寄存器中的一个。AL、CL、DL、BL、AH、CH、DH、BH、BPL、SPL、DIL和SIL;或者使用REX.R和64位模式时可用的一个字节寄存器(R8L - R15L)。 |
r16 | 字通用寄存器中的一个。AX、CX、DX、BX、SP、BP、SI、DI;或使用REX.R和64位模式时可用的一个字寄存器(R8-R15)。 |
r32 | 双字通用寄存器中的一个。EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI;或在64位模式下使用REX.R时可用的一个双字寄存器(R8D - R15D)。 |
r64 | 四字的通用寄存器之一。RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8-R15。这些在使用REX.R和64位模式时可用。 |
imm8 | 一个立即字节值。imm8符号是一个介于-128和 127之间的有符号数字。对于imm8与字或双字操作数结合的指令,立即值被代符号扩展为字或双字。字的上一个字节被填入立即值的最上面的位。 |
imm16 | 用于操作数属性为16位的指令的立即字值。这是一个介于-32,768和 32,767之间的数字。 |
imm32 | 用于操作数属性为32位的指令的立即双字值。它允许使用 2,147,483,647和-2,147,483,648之间的数字。 |
imm64 | 用于操作数属性为64位的指令的一个立即四字值。该值允许使用 9,223,372,036,854,775,807和-9,223,372,036,854,775,808之间的数字。 |
m | 内存中的一个16位、32位或64位操作数。 |
m8 | 内存中的一个字节操作数,通常表示为一个变量或数组名称,但由DS:(E)SI或ES:(E)DI寄存器指向。在64位模式下,它由RSI或RDI寄存器指向。 |
m16 | 内存中的一个字操作数,通常表示为一个变量或数组名称,但由DS:(E)SI或ES:(E)DI寄存器指向。这个命名法只用于字符串指令。 |
m32 | 内存中的一个双字操作数,通常表示为一个变量或数组名称,但由DS:(E)SI或ES:(E)DI寄存器来指出。这个命名法只用于字符串指令。 |
m64 | 在内存中的一个内存四字操作数。 |
m128 | 在内存中的一个双四字操作数。 |
m16:16, m16:32, m16:64 | 一个内存操作数,包含一个由两个数字组成的远指针。冒号左边的数字对应于指针的段选择器。右边的数字与它的偏移量相对应。 |
m16&32, m16&16, m32&32, m16&64 | 一个由数据项对组成的内存操作数,其大小在&符号的左边和右边表示。所有的内存寻址模式都被允许。m16&16和m32&32操作数被BOUND指令使用,提供一个包含数组索引的上下限的操作数。m16&32操作数被LIDT和LGDT用来提供一个字,用来加载极限字段,以及一个双字,用来加载相应的GDTR和IDTR寄存器的基字段。LIDT和LGDT在64位模式下使用m16&64操作数,以提供一个字来加载极限字段,以及一个四字来加载相应GDTR和IDTR寄存器的基字段。 |
moffs8, moffs16, moffs32, moffs64 | 一个简单的内存变量(内存偏移),类型为字节、字或双字,用于MOV指令的一些变体。实际地址是由相对于段基的简单偏移量给出的。该指令中没有使用ModR/M字节。显示的moffs数字表示其大小,由指令的地址大小属性决定。 |
Sreg | 一个分段寄存器。段寄存器的位分配是ES=0,CS=1,SS=2,DS=3,FS=4,GS=5。 |
m32fp, m64fp, m80fp | 内存中的单精度、双精度和双扩展精度(分别)浮点操作数。这些符号指定浮点值,作为x87 FPU浮点指令的操作数。 |
m16int, m32int, m64int | 内存中的一个字,双字和四字整数(分别)操作数。这些符号指定整数,作为x87 FPU整数指令的操作数。 |
ST or ST(0) | FPU寄存器堆栈的顶端元素。 |
ST(i) | 从FPU寄存器堆栈的顶部开始的第i个元素(i ← 0到7)。 |
r/m8, r/m16, r/m32, r/m64 | 寄存器或这内存。 |
- 《Intel® 64 and IA-32 Architectures Software Developer’s Manual》