如果要从内联汇编中调用C/C++函数,可以执行以下操作:
void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}
然后GCC将发出如下所示的代码:
movl $callee, %eax
call *%eax
这可能会有问题,因为间接调用会破坏旧CPU上的管道.
由于地址callee最终是常量,可以想象可以使用i约束.引自GCC在线文档:
'我"
允许使用立即整数操作数(具有常量值的操作数).这包括符号常量,其值仅在汇编时或以后知道.
如果我尝试这样使用它:
asm("call %0" : : "i"(callee));
我从汇编程序中收到以下错误:
错误:后缀或操作数对`call'无效
这是因为GCC会发出代码
call $callee
代替
call callee
所以我的问题是是否可以使GCC输出正确call.
考虑这样的内联汇编:
uint64_t flags;
asm ("pushf\n\tpop %0" : "=rm"(flags) : : /* ??? */);
尽管可能存在某种内在函数来获取 RFLAGS 的内容,但我如何向编译器表明我的内联汇编破坏了堆栈顶部的一个四字内存?
我试图在64位Linux上的GCC扩展内联ASM中输出相同的字符串两次.
int main()
{
    const char* test = "test\n";
    asm(
        "movq %[test], %%rdi\n"    // Debugger shows rdi = *address of string*  
        "movq $0, %%rax\n"
        "push %%rbp\n"
        "push %%rbx\n"
        "call printf\n"         
        "pop %%rbx\n"
        "pop %%rbp\n"
        "movq %[test], %%rdi\n" // Debugger shows rdi = 0
        "movq $0, %%rax\n"
        "push %%rbp\n"
        "push %%rbx\n"
        "call printf\n"     
        "pop %%rbx\n"
        "pop %%rbp\n"
        : 
        :  [test] "g" (test)
        : "rax", "rbx","rcx", "rdx", "rdi", "rsi", "rsp"
        );
    return 0;
}
现在,字符串只输出一次.我尝试了很多东西,但我想我错过了关于调用约定的一些注意事项.我甚至不确定clobber列表是否正确,或者我是否需要保存和恢复RBP和RBX.
为什么字符串不输出两次? …