assembly 如何让GCC在ah/bh/ch/dh中放入一个char?

eqqqjvef  于 4个月前  发布在  其他
关注(0)|答案(1)|浏览(36)

假设我有一个内联程序集,它需要ahbhchdh中的一个特定的char值。我如何告诉GCC把它放在那里?我没有看到这样做的相关约束,但是GCC手册说“如果你必须使用特定的寄存器,但是你的机器约束没有提供足够的控制来选择你想要的特定寄存器,局部寄存器变量可能会提供一个解决方案”,所以我尝试了:

void f(char x) {
    register char y __asm__("ah") = x;
    __asm__ __volatile__(
        "# my value ended up in %0" :: "a"(y)
    );
}

字符串
但它不起作用。它把它放在al中:

movb    4(%esp), %al
        # my value ended up in %al


特定于x86的Q约束看起来也很接近我想要的,所以我尝试用它来代替a,但结果是一样的。
有趣的是,当我使用Clang而不是GCC(无论是aQ还是r)编译时,我确实得到了想要的结果:

movb    4(%esp), %ah
        # my value ended up in %ah


我还尝试用bhchdh代替ah,它们的每一种组合都导致了类似的结果。
我也试着编译成64位而不是32位。在那里,GCC仍然做了基本上相同的错误事情:

movl    %edi, %eax
        # my value ended up in %al


Clang完全无法用Cannot encode high byte register in REX-prefixed instruction编译,除非我关闭了优化(我打开LLVM issue #45210时提到了这一点),在这种情况下,它最终在正确的位置获得了值:

movb    %dil, -1(%rsp)
        movb    -1(%rsp), %al
        movb    %al, -2(%rsp)
        movb    -2(%rsp), %ah
        # my value ended up in %ah


这是我应该报告的GCC中的一个bug,还是这是不应该工作的东西,只是偶然在Clang中工作?如果是后者,有没有一种方法可以做到我想要的,或者我必须在程序集内从其他地方自己解决mov
32-bit Godbolt link64-bit Godbolt link

cbeh67ev

cbeh67ev1#

显然,约束不允许选择嵌套寄存器,但你可以在指令引用中添加h修饰符。这在输入操作数的文档中有提到。例如,

void f(char x) {
    char a;
    __asm__ __volatile__(
        "mov  %0, %h1" :: "X"(x), "a"(a)
    );
}

字符串
产生

f:
        xorl    %eax, %eax
        mov  4(%esp), %ah
        ret


我无法摆脱清除eaxxor。我猜测代码生成器将“%h1”解释为设置了8位的32位字,而不是字符寄存器引用。例如:

char f(char x) {
    char a;
    __asm__ __volatile__(
        "movb  %0, %h1" :: "X"(x), "a"(a)
    );
    return a;
}


.编译为相同的代码,即使它返回\0,不是很直观。

相关问题