当前位置: 首页 > 知识库问答 >
问题:

如何使用Clang 11、英特尔语法和替换变量内联汇编

乌骏
2023-03-14

我费了很大的劲才让它运转起来:

我尝试了以下方法:

 uint32_t reverseBits(volatile uint32_t n) {
        uint32_t i = n;
    __asm__ (".intel_syntax\n"
            "xor eax, eax \n" 
            "inc eax \n"
       "myloop: \n"
            "shr %0, 1 \n"
            "adc eax, eax \n"
            "jnc short myloop \n"
            "mov %1, %0  \n"
            : [i] "=r"(i),  [n] "=r"(n));;

        return n;
    }

我会得到:

Line 11: Char 14: error: unknown token in expression
            "shr %0, 1 \n"
             ^
<inline asm>:5:5: note: instantiated into assembly here
shr %edx, 1
    ^

显然,编译器将< code>%0替换为< code>%register,但仍然保留< code>'%'...

因此,我决定将 %0 替换为 edx,将 %1 替换为 ecx

 uint32_t reverseBits(volatile uint32_t n) {
        uint32_t i = n;
    __asm__ (".intel_syntax\n"
            "xor eax, eax \n" 
            "inc eax \n"
       "myloop: \n"
            "shr edx, 1 \n"
            "adc eax, eax \n"
            "jnc short myloop \n"
            "mov ecx, edx  \n"
            : [i] "=r"(i),  [n] "=r"(n));;

        return n;
    }

并得到结果错误:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==31==ERROR: AddressSanitizer: SEGV on unknown address 0x0001405746c8 (pc 0x00000034214d bp 0x7fff1363ed90 sp 0x7fff1363ea20 T0)
==31==The signal is caused by a READ memory access.
    #1 0x7f61ff3970b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
AddressSanitizer can not provide additional info.
==31==ABORTING

我怀疑编译器优化了东西并内联了被调用的函数(所以没有雷特),但仍然不知道我该怎么做。

注意:我不能把编译器从clang改成gcc,因为用clang 11的不是我而是一个远程服务器。我也已经看过这个链接,但它已经很旧了(2013年),如果从那以后事情没有改变,我会感到惊讶。

编辑:在彼得·科德斯的出色回答之后,我能够让它工作得更好一点:

uint32_t reverseBits(volatile uint32_t n) {
        uint32_t i = n;

    __asm__ (".intel_syntax noprefix\n"
            "xor rax,rax \n" 
            "inc rax \n"

       "myloop: \n"
            "shr %V0, 1 \n"
            "adc eax, eax \n"
            "jnc short myloop \n"
            "mov %V0, rax \n"
   
             ".att_syntax"
            : [i] "=r"(i));;
    
        return i;
    }

然而有两件事:

1/我不得不将eax更改为rax,因为 =64位( ),这很奇怪,因为 I

2/我没有得到所需的输出:

input is :             00000010100101000001111010011100
output is:   93330624 (00000101100100000001110011000000)
expected:   964176192 (00111001011110000010100101000000)

注意:我测试了< code >“mov % v 0,1 \ n”并正确地得到了< code>1作为输出,这证明了替换以某种方式工作。

共有1个答案

颜新
2023-03-14

我不知道有什么好的方法来做到这一点,我建议在

(更新:clang 14更改了以下内容:如何将gcc或clang设置为在内联asm()语句中永久使用英特尔语法?)

如何在英特尔语法中生成带有clang的汇编代码?是关于<code>-S</code>输出所使用的语法,与GCC不同,它没有连接到编译器的内联asm输入语法。--x86 asm syntax=intel的行为没有改变:它仍然以英特尔语法输出,对内联asm没有帮助。

您可以滥用%V0%V[i](而不是%0%[i])来打印模板https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#x86Operandmodifiers中的“裸”完整寄存器名称,但这很糟糕,因为它只打印完整寄存器名称。即使对于选择EAX的32位int,它也会打印RAX而不是EAX。

(对于< code >“m”内存操作数来说,获取< code>dword ptr [rsp 16]或任何编译器选择的寻址模式也不起作用,但总比没有好。虽然在我看来,这并不比仅仅使用AT更好

或者您可以选择像"=a"(var)这样的硬寄存器,然后显式使用EAX而不是%0。但这更糟糕,并且破坏了约束系统的一些优化优势。

模板中仍然需要“.intel_syntax noprefix\n”,并且应该以“.att_syntax”结束模板,以将汇编程序切换回 AT

显然,告诉编译器它可以使用< code>"=r"选择任何寄存器,然后实际使用您自己的硬编码选择,当编译器选择不同的寄存器时,将会产生未定义的行为。您将踩在编译器的脚趾上,破坏它以后想要使用的值,并让它从错误的寄存器中获取垃圾作为输出。IDK,你为什么费事在你的问题中包括这一点;这对at来说是完全一样的

 类似资料:
  • 我正在使用Intel Ivy Bridge CPU,希望使用RDRAND操作码(https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide)在C#中。 如何通过C#调用此CPU指令?我在这里看到了一个从c#执行汇编代码的示例:C#

  • 如这个问题所示,使用g,我可以< code > g-S-masm = Intel test . CPP 。另外,使用clang,我可以执行< code>clang -S test.cpp,但是clang不支持< code>-masm=intel(编译期间未使用的< code >警告参数:-masm=intel)。我如何用clang得到intel语法?

  • 问题内容: 每次与Hotspot一起使用时,都不得不烦恼我,不得不阅读可怕的AT&T语法。 有没有办法告诉它使用英特尔语法? 问题答案: 您所需要做的就是将一些选项解析到dis-asm.h和binutils代码上 对于Intel Asm(我也更喜欢),只需添加以下内容 如果您需要组合选项,请像这样用逗号分隔 任何未被识别为hsdis选项的内容都将被提供给反汇编程序,这些选项与您从中看到的选项相同

  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 8年前关闭。 对我来说,英特尔语法更容易阅读。如果我只关注Intel语法来遍历汇编林,我会错过任何事情吗?我有什么理由要切换到AT&T(除了能够读取其他人的AT&T程序集之外

  • 如何使用Java中的Intel AVX矢量指令集?这是一个简单的问题,但答案似乎很难找到。

  • 我需要从英特尔处理器中的随机生成器(英特尔酷睿i3)获取随机数。我不想使用任何图书馆。我想在C中使用汇编程序粘贴,但我不知道应该使用哪些寄存器和指令。