热门标签 | HotTags
当前位置:  开发笔记 > 小程序 > 正文

为什么我的“=r”(var)输出没有选择与“a”(var)输入相同的寄存器?

如何解决《为什么我的“=r”(var)输出没有选择与“a”(var)输入相同的寄存器?》经验,为你挑选了1个好方法。

我正在学习如何__asm__ volatile在GCC中使用,并提出了一个问题。我想实现一个执行原子比较和交换并返回先前存储在目标中的值的函数。

为什么"=a"(expected)输出约束起作用,但是"=r"(expected)约束使编译器生成不起作用的代码?

情况1。

#include 
#include 
#include 

uint64_t atomic_cas(uint64_t * destination, uint64_t expected, uint64_t value){
    __asm__ volatile (
        "lock cmpxchgq %3, %1":
        "=a" (expected) :
        "m" (*destination), "a" (expected), "r" (value) :
        "memory"
    );

    return expected;
}

int main(void){
    uint64_t v1 = 10;
    uint64_t result = atomic_cas(&v1, 10, 5);
    printf("%" PRIu64 "\n", result);           //prints 10, the value before, OK
    printf("%" PRIu64 "\n", v1);               //prints 5, the new value, OK
}

它按预期工作。现在考虑以下情况:

情况2

#include 
#include 
#include 

uint64_t atomic_cas(uint64_t * destination, uint64_t expected, uint64_t value){
    __asm__ volatile (
        "lock cmpxchgq %3, %1":
        "=r" (expected) ://<----- I changed a with r and expected GCC understood it from the inputs 
        "m" (*destination), "a" (expected), "r" (value) :
        "memory"
    );

    return expected;
}

int main(void){
    uint64_t v1 = 10;
    uint64_t result = atomic_cas(&v1, 10, 5);
    printf("%" PRIu64 "\n", result);            //prints 5, wrong
    printf("%" PRIu64 "\n", v1);                //prints 5, the new value, OK 
}

我检查了生成的程序集并注意到以下内容:

I.在两种情况下,功能代码都是相同的,看起来像

   0x0000555555554760 <+0>:     mov    rax,rsi
   0x0000555555554763 <+3>:     lock cmpxchg QWORD PTR [rdi],rdx
   0x0000555555554768 <+8>:     ret 

二。GCC内联时出现了问题,atomic_cas因此在以后的情况下,正确的值没有传递给printf函数。这是有关的片段disas main

0x00000000000005f6 <+38>:    lock cmpxchg QWORD PTR [rsp],rdx
0x00000000000005fc <+44>:    lea    rsi,[rip+0x1f1]        # 0x7f4
0x0000000000000603 <+51>:    mov    rdx,rax ;  <-----This instruction is absent in the Case 2.
0x0000000000000606 <+54>:    mov    edi,0x1
0x000000000000060b <+59>:    xor    eax,eax

问:为什么会出现替代raxa用任意寄存器() r)产生错误的结果?我希望这在两种情况下都能奏效?

UPD。我用以下标志编译-Wl,-z,lazy -Warray-bounds -Wextra -Wall -g3 -O3



1> interjay..:

cmpxchg指令总是把结果在rax寄存器中。因此,您需要使用a约束条件来告知GCC从该寄存器中移出。在情况2中,您通过使用告诉GCC使用任意寄存器,而不是r在该寄存器中放置任何内容。

如果要使用r,则必须添加一条mov指令以将结果从rax移至该寄存器(movq %%rax, %0)。您还必须告诉GCC指令更改了rax寄存器,例如,将其添加到asm语句的“ clobbers”部分。对于您的情况,没有理由以这种方式使事情复杂化。


推荐阅读
author-avatar
蛋狗酱_972
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有