That MASM code is dumb, 64-bit mode doesn't need call
to read its own address.
You should replace it with a RIP-relative LEA.
It's also not safe to push/pop in inline asm for x86-64 (unless you offset RSP by 128 first to skip over the red-zone); that would step on the red-zone below RSP in the x86-64 System V ABI, and there's no way to declare a clobber on that. Avoiding call
avoids pushing anything.
Also since you don't want to make this a function, you can let the compiler choose the register. You're already using "=r"
, so use %0
in the template string to expand to the compiler's choice of register. Hard-coding RAX only happens to work if the compiler picks RAX for the "=r"
output, otherwise disaster.
void *current_RIP;
// assuming the default -masm=att, not -masm=intel
asm( "lea 0(%%rip), %0" : "=r"(current_RIP) ); // no inputs, no clobbers
(Your GNU C inline asm attempt was broken in other ways, too, e.g. ret %rax
isn't a valid instruction. It makes no sense to put an operand on ret
. And since this is inline asm, and you already popped the return address, you shouldn't use a ret
instruction at all. The MASM code needed it because it's a function that returns to its caller, instead of falling out the end of an inline asm statement.)
Avoid inline asm
Or avoid inline asm entirely and just take a code address. Either of the function itself, like (void*)_get_addr
, or of a goto label. (https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html)
static inline get_addr() {
PVOID pointer = &&label;
label:
return pointer;
}
Note that _names
are reserved at global scope for the implementation's own use. Unless this code is part of a GCC or clang header, that's a poor choice of name.
Godbolt shows how they compile with gcc -O2
with / without -fPIE
. The label-value one will use mov eax, imm32
absolute addressing in a non-PIE Linux executable, because addresses are link-time constants with no ASLR. But if ASLR is possible (PIE), it will use RIP-relative LEA like the asm would.
The one weird thing is that since the label pointer is never dereferenced, the compiler just puts it somewhere in the function its inlined into. In this case at the top, even if there's other code in the function before taking the current address.
It's obviously not safe to jump to that address, so IDK what exactly you plan to do with the pointer, and how exact it needs to be.
As David Wohlferd pointed out in comments, the original stand-alone asm function always returns the same address (inside itself) to every caller. A function that can inline (or even is forced to inline) will return an address inside that function.
Or even inside a higher parent function if an optimizing compiler chooses to inline further. This requires compile-time inlining, unlike if you'd use __builtin_return_address(0)
, so at least it will always be an address in the same executable or library as the actual call site in the C source.