使用读取 [ebp+4] 的 MSVC 内联 asm 移植到 64 位

Porting to 64-bit with MSVC inline asm that reads [ebp+4]

我在 Microsoft Visual Studio 2010 工作,我正在尝试为我的项目支持 64 位构建。据我所知,64 位架构不支持 __asm 关键字。

下面是项目仅支持 32 位构建时的工作原理。

void* 
Class1::Class2::operator new(size_t size) 
{ 
void *pCaller;
__asm mov edx, [ebp+4] 
__asm mov pCaller, edx 
char *pMem = (char *) malloc (sizeof(Class2) + size);
doSomething(pMem, pCaller);
void *ptr = (void *) (pMem + sizeof(Class2)); 
return(ptr);
}

我可以使用预处理器指令使上述功能取决于建筑类型。

void* 
Class1::Class2::operator new(size_t size) 
{
#ifndef _WIN64  
void *pCaller;
__asm mov edx, [ebp+4] 
__asm mov pCaller, edx 
char *pMem = (char *) malloc (sizeof(Class2) + size);
doSomething(pMem, pCaller);
void *ptr = (void *) (pMem + sizeof(Class2)); 
return(ptr);
#elseif
// Accptable code for 64-bit project.
}

我必须以某种方式摆脱那些线条

__asm mov edx, [ebp+4] 
__asm mov pCaller, edx 

我以前从未遇到过汇编代码,但据我所知

__asm mov edx, [ebp+4]

是在寄存器之间移动数据,[ebp+4] 是函数调用 Class1::Class2::operator new(size_t size) 中定义的一些局部变量,存储在堆栈中。第二行只是在寄存器和内存之间移动数据。

如何用C/C++替换汇编代码?这甚至可能吗?

假设 EBP 设置为遗留帧指针(我认为 MSVC 内联 asm 强制),
[ebp+4] 持有 return 地址。 这段代码只是设置 void *pCaller = return_address

此代码只是保存分配内存的调用站点的地址。 (或者至少将其与内存块的地址一起传递给 doSomething)。

这可能会阻止这个 operator new 内联到调用者中,所以删除它会很好。


如果您不需要这个(例如它只是调试基础设施),只需删除该部分并执行 malloc 来实现 operator new .评论者建议现代调试工具可以为您完成此操作,从而使手动检测变得过时。

或者完全删除 newdelete 的重载 让它们使用默认的 C++ new / delete .

或者显然 MSVC 有一个 _ReturnAddress() intrinsic in intrin.h 用于 return 地址,所以如果你真的想继续这样做,你可以将它用于 32 位和 64 位代码而不是内联 asm。


请注意,在 MSVC 上,newdeletemalloc/free 不兼容。 他们'使用单独的空闲列表 and/or 簿记格式重新分隔分配器。

因此,如果其他代码仍想在这些指针上使用 free(),您确实需要为这个 class 保留重载的 new/delete,即使它不调用 doSomething。并且您需要继续使用 malloc 而不是使用其他方式调用默认 new.

但是如果唯一调用 free 的是相应的删除运算符,那么您的源代码中只有一个地方可以更改/删除。