文档详情

X64处理器架构简单介绍

豆浆
实名认证
店铺
DOC
94KB
约10页
文档ID:8196595
X64处理器架构简单介绍_第1页
1/10

X64 处理器架构X64 架构是一个向后兼容的扩展的 x86提供了和 x86 相同的 32 位模式和一个新的 64 位模式术语“x64”包括 AMD 64 和 Intel64,他们的指令集基本是相同的寄存器(Registers)X64 将 x86 的 8 个通用寄存器扩展为 64 位,并且增加 8 个新的 64 位寄存器64 位寄存器命名以“r”开始,例如: eax 扩展为 64 位就是 rax,8 个新的 64 位寄存器命名为 r8到 r15每个寄存器的低 32 位,16 位,8 位可以作为操作数直接寻址,这包括向esi 这样的寄存器,以前他的低 8 位不可以直接寻址下表说明了 64 位寄存器的地位部分在汇编语言中的命名64-bit register Lower 32 bits Lower 16 bits Lower 8 bitsrax eax ax al rbx ebx bx bl rcx ecx cx cl rdx edx dx 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 对一个 32 位寄存器操作会自动用零扩展填充整个 64 位寄存器。

对 8 位和 16 位寄存器的操作不会零扩展填充高位(这是和 x86 兼容的) ax,bx, cx 和 dx 的高 8 位 ah,bh,ch,dh 仍就是可以寻址的,但是不能用在所有类型的操作数指令指针寄存器 eip 和 flags 也被扩展到 64 位(分别为 rip 和 rflags) X64 处理器也提供几个浮点寄存器:·8 个 80 位的 x87 寄存器·8 个 64 位的 MMX 寄存器·以前的 8 个 128 位 SSE 寄存器增加到 16 个调用约定(Calling Conventions)跟 x86 不同,在 x64 下 c/c++编译器仅支持一种调用约定,这种调用约定利用了在 x64 下可用寄存器的增加·前四个整型值或指针参数传给寄存器 rcx,rdx,r8,和 r9调用函数在堆栈上保留空间为这些参数·前四个浮点参数传给前四个 SSE 寄存器 xmm0-xmm3.·调用函数在堆栈上保留空间为传递给寄存器的参数被调用函数利用这些空间将寄存器的内容存入堆栈·任何其他参数存入堆栈·一个整型或指针返回值存在 rax 寄存器中,如果返回值是浮点则返回在xmm0 中·rax,rcx,rdx,r8-r11 是要变化的·rbx, rbp, rdi, rsi, r12-r15 不变这个调用约定跟 c++是非常相似的:this 指针作为第一个隐含的参数被传递,后面三个参数传递给寄存器,剩下的存入堆栈。

寻址方式(Addressing Modes )在 64 位模式下的寻址方式类似于 x86 但是不是完全相同·指令涉及到 64 位寄存器会自动执行 64 位精度 (例如 mov rax,[rbx]是将 rbx 所指向的地址开始的 8 字节存入 rax)·一个特别的指令 mov 的立即数常量或常量地址已经增加为 64 位,对于其他的指令立即数常量或常量指针仍就是 32 位·x64 提供了一个新的 rip 相关的寻址模式如果指令涉及到常量地址以 rip 为偏移例如 mov rax,[addr]操作将地址 addr+rip 指向地址开始的 8 字节数存入 raxJmp,call,push 和 pop 指令涉及到的指令指针和堆栈指针都为 64 位在x64 中x64 指令集大多数 x86 指令在 x64 的 64 位模式下是有效的在 64 位模式下一些很少用到的指令不再支持例如:·BCD 码算术指令:AAA,AAD,AAM,AAS,DAA,DAS·BOUND·PUSHAD 和 POPAD·大多数的操作要处理段寄存器,例如 PUSH DS 和 POP DS对 FS 和 GS 段寄存器的操作仍然有效)X64 指令集包括最近增加的 x86 指令例如 SSE2,程序中可以自由的使用这些指令。

数据传送(Data Transfer)X64 提供新的 MOV 指令的变量来处理 64 位立即数常量或内存地址MOV r,#n r = #nMOV rax, m 传送 64 位地址处的内容到 rax.MOV m, rax 传送 rax 的内容到 64 位地址处X64 也提供一个新的指令符号扩展 32 位到 64 位MOVSXD r1, r/m 传送 DWORD 符号扩展到 QWORD.一般 MOV 操作 32 位子寄存器自动零扩展到 64 位,因此没有 MOVZXD 指令Ordinary MOV operations into 32-bit subregisters automatically zero extend to 64 bits, so there is no MOVZXD instruction.两个 SSE 指令可以用来传送 128 位值(例如 GUIDs)从内存到 xmmn 寄存器或相反Two SSE instructions can be used to move 128-bit values (such as GUIDs) from memory to an xmmn register or vice versa.MOVDQA r1/m, r2/mMove 128-bit aligned value to xmmn register, or vice versa.传送 128 位对齐值到 xmmn 寄存器,或相反MOVDQU r1/m, r2/mMove 128-bit value (not necessarily aligned) to register, or vice versa.传送 128 位值(不是必须对齐)到寄存器或相反数据转换(Data Conversion)CDQE 转换 dword (eax) 为 qword (rax).CQO 转换 qword (rax) 为 oword (rdx:rax).字符串操作(String Manipulation)MOVSQ Move qword from rsi to rdi.将 rsi 指向的字符串传送到 rdi 指向地址CMPSQ Compare qword at rsi with rdi.比较 rsi 和 rdi 所指向地址的字符串SCASQ 扫描 rdi 指向的地址的 qword 并与 rax 比较Scan qword at rdi. Compares qword at rdi to rax.LODSQ 将 rsi 指向的地址的 qword 传入 raxLoad qword from rsi into rax.STOSQ 将 rax 的值传入 rdi 指向的地址Store qword to rdi from rax.Annotated x64 Disassembly解释 x64 反汇编下面一个非常简单的函数来说明 x64 调用约定。

int Simple(int i, int j){return i*5 + j + 3;}编译后的代码是这样:01001080 lea eax,[rdx+rcx*4] ; eax = rdx+rcx*401001083 lea eax,[rcx+rax+0x3] ; eax = rcx+rax+301001087 reti 和 j 参数被传递给 ecx 和 edx 寄存器,由于这仅有两个参数这个函数根本没用堆栈这段生成的代码有三个地方值得注意,其中有一个事 x64 特有的:1. lea 指令被用来执行一系列的简单算术操作,第一个将 j+i*4 存入 eax,第二个操作加上 i+3 存入结果中,最后为 j+i*5+32. 许多操作例如加和乘,可以处理中用扩展精度,然后在舍入到正确精度在这个例子中代码用的是 64 位加和乘操作我们可以安全的缩短结果到 32 位3. 在 x64 中,任何输出到 32 位寄存器的操作会自动零扩展到 64 位,在这个例子中,输出到 eax 中有效的缩短到 32 位返回值被传送到 rax 寄存器,在这个例子中,结果已经在 rax 寄存器中,因此函数直接返回。

下面我们考虑一个更复杂的函数来说明典型的 x64 反汇编:HRESULT Meaningless(IDispatch *pdisp, DISPID dispid, BOOL fUnique, LPCWSTR pszExe){IQueryAssociations *pqa;HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (void**)&pqa);if (SUCCEEDED(hr)) {hr = pqa->Init(ASSOCF_INIT_BYEXENAME, pszExe, NULL, NULL);if (SUCCEEDED(hr)) {WCHAR wszName[MAX_PATH];DWORD cchName = MAX_PATH; hr = pqa->GetString(0, ASSOCSTR_FRIENDLYAPPNAME, NULL, wszName, &cchName);if (SUCCEEDED(hr)) {VARIANTARG rgvarg[2] = { 0 };V_VT(&rgvarg[0]) = VT_BSTR;V_BSTR(&rgvarg[0]) = SysAllocString(wszName);if (V_BSTR(&rgvarg[0])) {DISPPARAMS dp;LONG lUnique = InterlockedIncrement(&lCounter);V_VT(&rgvarg[1]) = VT_I4;V_I4(&rgvarg[1]) = fUnique ? lUnique : 0;dp.rgvarg = rgvarg;dp.cArgs = 2;dp.rgdispidNamedArgs = NULL;dp.cNamedArgs = 0;hr = pdisp->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, &dp, NULL, NULL,NULL);VariantClear(&rgvarg[0]);VariantClear(&rgvarg[1]);} else {hr = E_OUTOFMEMORY;}}}pqa->Release();}return hr;}我们将要进入这个函数并且对每行进行反汇编。

当进入的时候这个函数的参数被存储为下面这样: rcx = pdisp.  rdx = dispid.  r8 = fUnique.  r9 = pszExe.前四个参数被传入寄存器中,由于这个函数仅有四个参数,没有一个被存入堆栈中下面开始汇编代码:Meaningless:010010e0 push rbx ; save010010e1 push rsi ; save010010e2 push rdi ; save010010e3 push r12d ; save010010e5 push r13d 。

下载提示
相似文档
正为您匹配相似的精品文档