XYZCODE123
XYZCODE123

Reputation: 372

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

I'm working in Microsoft Visual Studio 2010, and I'm trying to support 64-bit build for my project. And from what I can tell 64-bit architecture is not support __asm keyword.

So here is how it worked when project only supported 32-bit build.

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);
}

I can use preprocessor directives to make above function depend on building type.

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.
}

I must somehow get rid of those lines

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

I have never encounter assembly code before, but from what I can tell

__asm mov edx, [ebp+4]

is moving data between registers, [ebp+4] is some local variable defined inside function calling Class1::Class2::operator new(size_t size) stored on stack. The second line is simply moving data between register and memory.

How can I replace assembly code with C/C++? Is this even possible?

Upvotes: 1

Views: 1020

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 365332

Assuming that EBP is set up as a legacy frame-pointer (which MSVC inline asm forces, I think),
[ebp+4] holds the return address. This code is just setting void *pCaller = return_address.

This code is just saving the address of the call-site that's allocating the memory. (Or at least passing it to doSomething, along with the address of the memory block).

This may be stopping this operator new from inlining into callers, so removing that would be nice.


If you don't need this (e.g. it's just debugging infrastructure), simply remove that part and just do the malloc to implement operator new. Commenters suggest that modern debugging tools can do this for you, making manual instrumentation obsolete.

Or remove the overloads of new and delete entirely to let them use the default C++ new / delete.

Or apparently MSVC has a _ReturnAddress() intrinsic in intrin.h for the return address, so you can use that for both 32 and 64-bit code instead of inline asm if you really want to keep doing this.


Note that on MSVC, new and delete aren't compatible with malloc/free. They're separate allocators with separate free-lists and/or bookkeeping formats.

So if other code still wants to use free() on these pointers, you do need to keep the overloaded new/delete for this class even if it doesn't call doSomething. And you need to keep using malloc instead of using some other way of calling the default new.

But if the only thing that was calling free is the corresponding delete operator, you only have one place in your source to change / remove.

Upvotes: 5

Related Questions