Direct C function call using GCC's inline assembly
Solution 1
I got the answer from GCC's mailing list:
asm("call %P0" : : "i"(callee)); // FIXME: missing clobbers
Now I just need to find out what %P0
actually means because it seems to be an undocumented feature...
Edit: After looking at the GCC source code, it's not exactly clear what the code P
in front of a constraint means. But, among other things, it prevents GCC from putting a $
in front of constant values. Which is exactly what I need in this case.
For this to be safe, you need to tell the compiler about all registers that the function call might modify, e.g. : "eax", "ecx", "edx", "xmm0", "xmm1", ..., "st(0)", "st(1)", ...
.
See Calling printf in extended inline ASM for a full x86-64 example of correctly and safely making a function call from inline asm.
Solution 2
Maybe I am missing something here, but
extern "C" void callee(void)
{
}
void caller(void)
{
asm("call callee\n");
}
should work fine. You need extern "C" so that the name won't be decorated based on C++ naming mangling rules.
Related videos on Youtube
mtvec
Updated on April 30, 2022Comments
-
mtvec about 2 years
If you want to call a C/C++ function from inline assembly, you can do something like this:
void callee() {} void caller() { asm("call *%0" : : "r"(callee)); }
GCC will then emit code which looks like this:
movl $callee, %eax call *%eax
This can be problematic since the indirect call will destroy the pipeline on older CPUs.
Since the address of
callee
is eventually a constant, one can imagine that it would be possible to use thei
constraint. Quoting from the GCC online docs:`i'
An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time or later.
If I try to use it like this:
asm("call %0" : : "i"(callee));
I get the following error from the assembler:
Error: suffix or operands invalid for `call'
This is because GCC emits the code
call $callee
Instead of
call callee
So my question is whether it is possible to make GCC output the correct
call
.-
R.. GitHub STOP HELPING ICE almost 14 yearsAre you sure the indirect call destroys the pipeline? Have you benchmarked? My understanding was that in the old days on x86 (pre-i686), indirect calls were very bad (I recall them being a good 10-100 times slower on my K6), but nowadays cpus are smarter and can deal with them just fine. So do some testing before you jump to conclusions!
-
-
Nordic Mainframe almost 14 yearsNo, this doesn't work at all. First, the '$' is totally wrong for call, second he does not want "my_function" in the asm string, but the mangled name that C++ generates.
-
nategoose almost 14 yearsI did not see that this was for C++ too. In that case it is likely that this won't work if the function name is overloaded without lots of hoops. I just copied the "$" from another post since I didn't remember off hand the x86 asm syntax. Fixing that...
-
Peter Cordes almost 7 yearsSee also stackoverflow.com/questions/37639993/… for the dangers of using
call
from inline asm. It's basically impossible to do reliably for x86-64 System V (Linux), because you can't tell the compiler you want to clobber the red-zone. It's generally a bad idea. See stackoverflow.com/questions/7984209/…. -
Ciro Santilli OurBigBook.com almost 5 years@PeterCordes this seems to be the most upvoted question for "how to do function call from inline assembly", I recommend that we centralize the pitfall answer here.
-
Peter Cordes almost 5 years@CiroSantilli新疆改造中心996ICU六四事件: Maybe an edit to this answer to include a big fat warning and links to more details would be appropriate. And to include a
"memory"
clobber unless the function you're calling is known not to have any side-effects visible to this function. -
Ciro Santilli OurBigBook.com almost 5 years@PeterCordes that would help. My favorite answer so far is Michael's concrete attempt at it: stackoverflow.com/questions/37502841/…
-
Peter Cordes almost 5 yearsAnd BTW, update:
%P
is documented now, to print symbol names without decoration. Or to printfoo@plt
if needed/appropriate. gcc.gnu.org/onlinedocs/gcc/… -
Peter Cordes about 2 yearsThis is extremely unsafe. Don't use GNU C basic asm inside a function (unless it's
__attribute__((naked))
). Yourcaller
can inline into other functions, but its asm statement doesn't declare any clobbers even though it trashes all of the call-clobbered registers (including ZMM0-31, k0-7, mm0-7, st0-7), and the red-zone. It's a huge pain to safely make a function call from inside anasm
statement: Calling printf in extended inline ASM