我必须做64位堆栈。为了让我对malloc感到满意,我设法将两个整数(32位)写入内存并从那里读取:
但是,当我尝试用64位执行此操作时:
答案 0 :(得分:0)
第一段代码完美无缺。正如Jester建议的那样,您正在以两个独立的(32位)半部分写入64位值。这是您在32位架构上执行此操作的方式。您没有可用的64位寄存器,并且您无法一次写入64位内存块。但你似乎已经知道了,所以我不会讨论它。
在第二段代码中,您尝试使用64位体系结构(x86-64)。 现在,您不再需要在两个32位半部分中写入64位值,因为64位体系结构本身支持64位整数。您可以使用64位宽的寄存器,并且可以直接将64位块写入存储器。利用它来简化(并加速)代码。
64位寄存器为Rxx
而不是Exx
。使用QWORD PTR
时,您需要使用Rxx
;当您使用DWORD PTR
时,您需要使用Exx
。两者在64位代码中都是合法的,但在32位代码中只有32位DWORD是合法的。
还有其他几点需要注意:
虽然使用MOV xxx, 0
,it is smaller and faster to use XOR eax, eax
清除寄存器是完全有效的,但这通常是您应该编写的内容。这是一个非常古老的技巧,任何汇编语言程序员都应该知道,如果你曾尝试阅读其他人的汇编程序,你需要熟悉这个成语。 (但实际上,在您编写的代码中,您根本不需要这样做。因此,请参阅第2点。)
在64位模式all instructions implicitly zero the upper 32 bits when writing the lower 32 bits中,您只需编写XOR eax, eax
而不是XOR rax, rax
。这又是更小更快的。
64位程序的调用约定与32位程序中使用的约定不同。调用约定的确切规范将根据您使用的操作系统而有所不同。正如Peter Cordes评论的那样,x86 tag wiki中有相关信息。 两者 Windows和Linux x64调用约定至少传递寄存器中的前4个整数参数(而不是像x86-32调用约定那样在堆栈上),但是哪些寄存器是实际使用的是不同的。此外,64位调用约定与32位调用约定的要求不同,因为在调用函数之前必须如何设置堆栈。
(由于您的屏幕截图说明了“MASM”,我假设您在下面的示例代码中使用了Windows。)
; Set up the stack, as required by the Windows x64 calling convention.
; (Note that we use the 64-bit form of the instruction, with the RSP register,
; to support stack pointers larger than 32 bits.)
sub rsp, 40
; Dynamically allocate 8 bytes of memory by calling malloc().
; (Note that the x64 calling convention passes the parameter in a register, rather
; than via the stack. On Windows, the first parameter is passed in RCX.)
; (Also note that we use the 32-bit form of the instruction here, storing the
; value into ECX, which is safe because it implicitly zeros the upper 32 bits.)
mov ecx, 8
call malloc
; Write a single 64-bit value into memory.
; (The pointer to the memory block allocated by malloc() is returned in RAX.)
mov qword ptr [rax], 1
; ... do whatever
; Clean up the stack space that we allocated at the top of the function.
add rsp, 40
如果您想以32位的方式执行此操作,即使在64位架构上也是如此,您当然可以。这看起来如下:
sub rsp, 40 ; set up stack
mov ecx, 8 ; request 8 bytes
call malloc ; allocate memory
mov dword ptr [eax], 1 ; write "1" into low 32 bits
mov dword ptr [eax+4], 2 ; write "2" into high 32 bits
; ... do whatever
add rsp, 40 ; clean up stack
请注意,最后两条MOV
指令与您在32位版本的代码中编写的内容相同。这是有道理的,因为你正在做完全同样的事情。
您最初编写的代码不起作用的原因是因为EAX
不包含QWORD PTR
,它包含DWORD PTR
。因此,汇编程序生成“无效指令操作数”错误,因为存在不匹配。这与您没有偏移8的原因相同,因为DWORD PTR
只有4个字节。 QWORD PTR
确实是8个字节,但您在EAX
中没有其中一个。
或者,如果你想写16个字节:
sub rsp, 40 ; set up stack
mov ecx, 16 ; request 16 bytes
call malloc ; allocate memory
mov qword ptr [rax], 1 ; write "1" into low 64 bits
mov qword ptr [rax+8], 2 ; write "2" into high 64 bits
; ... do whatever
add rsp, 40 ; clean up stack
比较这三段代码,并确保您了解它们之间的差异和原因!