- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在学习如何使用 __asm__ volatile
在 GCC 中遇到了一个问题。我想实现一个执行原子比较和交换并返回先前存储在目标中的值的函数。
为什么 "=a"(expected)
输出约束起作用,而 "=r"(expected)
约束让编译器生成的代码不起作用工作?
案例 1.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
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 <inttypes.h>
#include <stdint.h>
#include <stdio.h>
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
}
我检查了生成的程序集并注意到以下几点:
我。在这两种情况下,功能代码都是相同的,看起来像
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
问题: 为什么将 rax
(a
) 替换为任意寄存器 (r
) 产生错误的结果?我希望它在这两种情况下都有效?
更新。我使用以下标志编译 -Wl,-z,lazy -Warray-bounds -Wextra -Wall -g3 -O3
最佳答案
cmpxchg
指令总是将结果放入rax
寄存器。所以你需要使用 a
约束来告诉 GCC 从那个寄存器中移动。在情况 2 中,您通过使用 r
告诉 GCC 使用任意寄存器,但您没有在该寄存器中放置任何内容。
如果你想使用r
,你必须添加一个mov
指令来将结果从rax
移动到那个寄存器( movq %%rax, %0
).您还必须告诉 GCC rax 寄存器已被指令更改,例如将其添加到 asm
语句的“clobbers”部分。对于您的情况,没有理由以这种方式使事情复杂化。
关于c - 为什么我的 "=r"(var) 输出没有选择与 "a"(var) 输入相同的寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58238986/
我正在使用 Gunicorn 为 Django 应用程序提供服务,它工作正常,直到我将其超时时间从 30 秒更改为 900000 秒,我不得不这样做,因为我有一个用例需要上传和处理一个巨大的文件(过程
我有一个带有非常基本的管道的Jenkinsfile,它可以旋转docker容器: pipeline { agent { dockerfile { args '-u root' } } stag
在学习 MEAN 堆栈的过程中,我遇到了一个问题。每当我尝试使用 Passport 验证方法时,它都不会返回任何响应。我总是收到“localhost没有发送任何数据。ERR_EMPTY_RESPONS
在当今的大多数企业堆栈中,数据库是我们存储所有秘密的地方。它是安全屋,是待命室,也是用于存储可能非常私密或极具价值的物品的集散地。对于依赖它的数据库管理员、程序员和DevOps团队来说,保护它免受所
是否可以创建像图片上那样的边框?只需使用 css 边框属性。最终结果将是没 Angular 盒子。我不想添加额外的 html 元素。我只想为每个 li 元素添加 css 边框信息。 假设这是一个 ul
我是一名优秀的程序员,十分优秀!