简体   繁体   English

“不支持mov”GCC内联汇编程序

[英]“unsupported for mov” GCC inline assembler

While playing around with GCC's inline assembler feature, I tried to make a function which immediately exited the process, akin to _Exit from the C standard library. 在使用GCC的内联汇编程序功能时,我尝试创建一个立即退出进程的函数,类似于C标准库中的_Exit

Here is the relevant piece of source code: 以下是相关的源代码:

void immediate_exit(int code)
{
#if defined(__x86_64__)
    asm (
            //Load exit code into %rdi
            "mov %0, %%rdi\n\t"
            //Load system call number (group_exit)
            "mov $231, %%rax\n\t"
            //Linux syscall, 64-bit version.
            "syscall\n\t"
            //No output operands, single unrestricted input register, no clobbered registers because we're about to exit.
            :: "" (code) :
    );
//Skip other architectures here, I'll fix these later.
#else
#   error "Architecture not supported."
#endif
}

This works fine for debug builds (with -O0 ), but as soon as I turn optimisation on at any level, I get the following error: 这适用于调试版本(使用-O0 ),但只要我在任何级别打开优化,我都会收到以下错误:

immediate_exit.c: Assembler messages:
immediate_exit.c:4: Error: unsupported for `mov'

So I looked at the assembler output for both builds (I've removed .cfi* directives and other things for clarity, I can add that in again if it's a problem). 所以我查看了两个版本的汇编程序输出(为了清楚起见,我删除了.cfi*指令和其他东西,如果这是一个问题,我可以再次添加它)。 The debug build: 调试版本:

immediate_exit:
.LFB0:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)

    mov -4(%rbp), %rdi
    mov $231, %rax
    syscall

    popq    %rbp
    ret

And the optimised version: 优化版本:

immediate_exit:
.LFB0:
    mov %edi, %rdi
    mov $231, %rax
    syscall

    ret

So the optimised version is trying to put a 32-bit register edi into a 64-bit register, rdi , rather than loading it from rbp , which I presume is what is causing the error. 因此,优化版本试图将32位寄存器edi放入64位寄存器rdi ,而不是从rbp加载它,我认为这是导致错误的原因。

Now, I can fix this by specifying 'm' as a register constraint for code , which causes GCC to load from rbp regardless of optimisation level. 现在,我可以通过将'm'指定为code的寄存器约束来解决这个问题,这会导致GCC无论优化级别如何都从rbp加载。 However, I'd rather not do that, because I think the compiler and its authors has a much better idea about where to put stuff than I do. 但是,我宁愿不这样做,因为我认为编译器及其作者对于放置东西比我更好。

So (finally!) my question is: how do I persuade GCC to use rdi rather than edi for the assembly output? 所以(最后!)我的问题是:我如何说服GCC使用rdi而不是edi来进行汇编输出?

Overall, you're much better off using constraints to get values into the right registers rather than explicit moves: 总的来说,使用约束将值放入正确的寄存器而不是显式移动会更好:

asm("syscall" :: "D" ((uint64_t)code), "a" ((uint64_t)231));

That lets compiler hoist the moves earlier in the code if useful, or even avoid the move altogether if the value can be arranged to already be in the correct register... 如果有用的话,编译器可以在代码中提前提升移动,如果值可以安排在正确的寄存器中,甚至可以完全避免移动...

Cast your variable into the appropriate length type. 将变量转换为适当的长度类型。

#include <stdint.h>

asm (
            //Load exit code into %rdi
            "mov %0, %%rdi\n\t"
            //Load system call number (group_exit)
            "mov $231, %%rax\n\t"
            //Linux syscall, 64-bit version.
            "syscall\n\t"
            //No output operands, single unrestricted input register, no clobbered registers because we're about to exit.
            :: "g" ((uint64_t)code)
    );

or better have your operand type straight away of the right size: 或者更好地将你的操作数类型改为正确的大小:

void immediate_exit(uint64_t code) { ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM