在 GCC 内联汇编中包装 CMPXCHG8B 的正确方法,32 位

2024-01-01

我正在尝试为 ia32 的 CMPXCHG8B 编写 GCC 内联汇编。不,我不能使用__sync_bool_compare_and_swap。它必须在有或没有 -fPIC 的情况下工作。

到目前为止我最好的(EDIT:毕竟不起作用,请参阅下面我自己的答案以了解详细信息)是

register int32 ebx_val asm("ebx")= set & 0xFFFFFFFF;
asm ("lock; cmpxchg8b %0;"
     "setz %1;"
     : "+m" (*a), "=q" (ret), "+A" (*cmp)
     : "r" (ebx_val), "c" ((int32)(set >> 32))
     : "flags")

但我不确定这实际上是否正确。

我不能做"b" ((int32)(set & 0xFFFFFFFF))对于 ebx_val 由于 PIC,但显然register asm("ebx")变量被编译器接受。

BONUS: ret 变量用于分支,因此代码最终如下所示:

cmpxchg8b [edi];
setz cl;
cmp cl, 0;
je foo;

知道如何描述输出操作数,使其变为:

cmpxchg8b [edi]
jz foo

?

谢谢。


下面的怎么样,这在一个小测试中似乎对我有用:

int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
    int changed = 0;
    __asm__ (
        "push %%ebx\n\t" // -fPIC uses ebx, so save it
        "mov %5, %%ebx\n\t" // load ebx with needed value
        "lock\n\t"
        "cmpxchg8b %0\n\t" // perform CAS operation
        "setz %%al\n\t" // eax potentially modified anyway
        "movzx %%al, %1\n\t" // store result of comparison in 'changed'
        "pop %%ebx\n\t" // restore ebx
        : "+m" (*ptr), "=r" (changed)
        : "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "r" ((uint32_t)(newval & 0xffffffff))
        : "flags", "memory"
        );
    return changed;
}

如果这也被错误编译,您能否添加一个触发此行为的小片段?

关于奖金问题,我认为不可能使用来自的条件代码在汇编器块之后进行分支cmpxchg8b说明(除非您使用asm goto或类似的功能)。从GNU C 语言扩展 http://tigcc.ticalc.org/doc/gnuexts.html#SEC94:

寻找一种方法来访问汇编指令留下的条件代码是一个很自然的想法。然而,当我们尝试实现这一点时,我们发现没有办法让它可靠地工作。问题是输出操作数可能需要重新加载,这将导致额外的后续“存储”指令。在大多数机器上,这些指令会在有时间测试之前更改条件代码。对于普通的“测试”和“比较”指令,不会出现此问题,因为它们没有任何输出操作数。

编辑:我找不到任何指定一种方式或另一种方式是否可以在使用时修改堆栈的来源%N输入值(This http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html古老的链接说“你甚至可以将寄存器压入堆栈,使用它们,然后将它们放回去。”但该示例没有输入)。

但应该可以通过将值固定到其他寄存器来做到这一点:

int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
    int changed = 0;
    __asm__ (
        "push %%ebx\n\t" // -fPIC uses ebx
        "mov %%edi, %%ebx\n\t" // load ebx with needed value
        "lock\n\t"
        "cmpxchg8b (%%esi)\n\t"
        "setz %%al\n\t" // eax potentially modified anyway
        "movzx %%al, %1\n\t"
        "pop %%ebx\n\t"
        : "+S" (ptr), "=a" (changed)
        : "0" (ptr), "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "D" ((uint32_t)(newval & 0xffffffff))
        : "flags", "memory"
        );
    return changed;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 GCC 内联汇编中包装 CMPXCHG8B 的正确方法,32 位 的相关文章

  • 难以理解汇编命令“加载有效地址”[重复]

    这个问题在这里已经有答案了 可能的重复 LEA 指令的目的是什么 https stackoverflow com questions 1658294 whats the purpose of the lea instruction LEA指
  • 64 位 Windows 汇编器

    我想对 64 位 Windows 程序集进行编程 最好使用 NASM 我在 google 上查了一下 但似乎找不到 64 位 Windows 编译器 有些网站提到了ml64 但它似乎不再包含在VC 中 我尝试过 32 位程序集 但显然它在我
  • 具有自定义值类型的 map::emplace()

    我使用时遇到问题map emplace 谁能帮我找出正确的语法来使用 我实际上正在尝试做同样的事情这个例子 http www cplusplus com reference map map emplace 这是我的版本 include
  • 使用 gcc 理解共享库

    我试图理解 C 中共享库的以下行为 机器一 cat one c include
  • 使用 ACPI 在 MS-DOS 中关闭计算机

    我在基于 Pentium 的计算机上运行 MS DOS 6 22 主板支持 ACPI 并且想知道是否有一个可以用来关闭计算机的汇编语言例程 或者它是否比那个更难 即主板 具体的 基本上 我想创建一个小程序来从命令行关闭计算机 这是专门为此编
  • 将 XMM 寄存器压入堆栈

    有没有办法将打包双字整数从 XMM 寄存器推送到堆栈 然后在需要时将其弹出 理想情况下 我正在寻找通用寄存器的 PUSH 或 POP 之类的东西 我已经检查了英特尔手册 但我要么错过了命令 要么没有 或者我是否必须将值解压到通用寄存器然后推
  • 为什么 g++ 在编译的二进制文件中存储类名?

    我注意到如果我跑strings在我编译的程序上g 输出包含它使用的各种类的名称 该程序是用 O3并且没有 g or p 并且当我剥离二进制文件时 类名仍然存在 我想知道为什么有必要g 将此信息存储在二进制文件中 出现的类名似乎都是使用虚函数
  • intfmt: db "%d", 10, 0 在汇编中的含义

    我最近在我的一个汇编文件的顶部看到了这个 并意识到我在打印整数的过程中花了很长时间使用它 而没有真正意识到它最初来自哪里 在我的基本汇编模板中使用 或 10 0 是什么结尾的意思是 section data intfmt db d 10 0
  • gcc 的 std::bind 在源代码中的哪个位置将参数复制到数据结构中?

    在试图了解在什么情况下std bind分配内存 我看了这个答案 https stackoverflow com a 25403584 391161 这给出了一些直觉 但我想要更详细的理解 所以我去查看了源代码gcc 我正在检查以下源代码 h
  • 如何构建gcc multilib工具链?

    我正在尝试在新安装的 ubuntu 14 04 的 AMD64 版本上构建 gcc multilib 工具链 它只有 x86 64 gcc 和 g 安装 没有 multilib 支持 我的配置行是 configure disable che
  • INT 13h 无法读取超出特定扇区的数据

    我正在为我的操作系统编写内核 在将磁盘扇区加载到内存时遇到问题 以下是从磁盘加载扇区的函数代码部分 mov ax 0x3000 mov es ax mov ax 0x0201 mov bx word ptr bp 6 bx 0x000 0x
  • 如何在汇编中使用 ReadString?

    mov edx offset Prompt1 call WriteString mov ecx 32 mov edx offset String1 call ReadString 现在 我该如何访问String1 如何将其移入寄存器以便对其
  • 致命错误:Python.h:没有这样的文件或目录,python-Levenshtein 安装

    首先 我正在使用 Python 3 7 开发 Amazon EC2 实例 Amazon linux 版本 2 AMI 我正在尝试使用以下命令安装 python Levenshtein 包 pip3 install python Levens
  • 如何使 gcc 为 -fpatchable-function-entry 发出多字节 NOP?

    gcc确实有能力使用多字节用于对齐循环和函数的 NOP 然而当我尝试 fpatchable function entry option https gcc gnu org onlinedocs gcc Instrumentation Opt
  • GCC 详细模式输出解释

    我是 Linux 新手 谁能向我解释一下我的 hello world 程序的以下详细模式输出 另外 这些文件是做什么用的crt1 o crti o crtend o crtbegin o and crtn o and lc and lgcc
  • Gnu C++ 何时会在没有明确要求的情况下支持 C++11?

    目前 使用 g 4 8 1 您必须通过以下方式在 C 11 模式下编译文件 g std c 11 o prog x prog cpp 当我只能说的时候有计划吗 g o prog x prog cpp 编译prog cpp Maybe pro
  • python gcc编译错误

    我知道 gcc 上有很多线程 特别是 command gcc failed with exit status 1 我已经查看了所有线程 但仍然无法解决此问题 我只会使用 gcc 或 mingw32 来执行与 python 相关的任务 例如使
  • GCC C++ pow 精度

    所以我在参加一个计算竞赛时 我注意到一个奇怪的错误 pow 26 2 总是返回 675 有时返回 674 即使正确答案是 676 pow 26 3 pow 26 4 等也会出现此类错误 经过比赛后的一些调试 我相信答案与 int 向下舍入的
  • mfence 和 asm 易失性 ("" : : : "内存") 的区别

    据我了解 mfence是硬件内存屏障 而asm volatile memory 是编译器障碍 但是 可以asm volatile memory 用来代替 mfence 我感到困惑的原因是这个链接 http gcc gnu org ml gc
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为

随机推荐