atomic.CompareAndSwapInt64

atomic.CompareAndSwapInt64

汇编

image

这段代码稍微有些复杂, 我们来慢慢的分析

MOVQ $0x1, 0(AX)

这一步是为了给i​赋值

MOVQ AX, CX

i​的地址传入了CX​寄存器

MOVL $0x2, AX

将 立即数2​ 存入AX​寄存器, AX在后面还会用到

MOVL $0x3, DX

将 立即数3 存入DX寄存器

LOCK CMPXCHGQ DX, 0(CX)

这部分我们需要详细的解释, 虽然看起来这里只用了DX, CX两个寄存器, 但是实际上还用到了AX寄存器

XCHG

XCHG​ 是x86架构汇编语言中的一条指令,它的全称是“Exchange Register/Memory with Register”,即“用寄存器交换寄存器/内存中的内容”。这条指令用于交换两个操作数的值。这两个操作数可以是寄存器或其中一个是内存地址。

举例来说,在x86汇编中:

XCHG AX, BX

这条指令将交换 AX​ 和 BX​ 两个寄存器中的值。

或者与内存地址交换:

XCHG AX, [MEM_ADDR]

这将交换 AX​ 寄存器和内存地址 MEM_ADDR​ 指向的值。

XCHG​ 指令在多线程编程和同步机制中尤其有用,因为该指令在单个操作中执行读取、写入以及交换操作,能够原子性地进行,避免了多线程中的竞态条件。在现代CPU中,使用XCHG指令通常会隐含地锁定总线,以防止其他处理器或缓存同时访问相同的内存地址,确保操作的原子性。但是这会带来性能的开销,因此在多核处理器上要谨慎使用。

在现代编程中,通常不需要直接使用XCHG指令。编程语言和它们的库通常会提供更高层次的抽象来处理多线程同步的问题,例如互斥锁(Mutexes)和条件变量(Condition Variables)。然而,操作系统和某些底层系统库可能会在它们的实现中使用这类指令。

SETE CL

用于根据前一条算术或逻辑指令的结果设置目标寄存器的值。具体来说,SETE​ 指令的作用是将操作数设置为 1 或 0,这取决于前一条指令执行后 EFLAGS 寄存器(标志寄存器)中的零标志(Zero Flag,ZF)是否被设置。

指令细节

  • SETE​ 是 "Set if Equal" 的缩写,也就是 "如果相等则设置" 的意思。这条指令通常在比较指令 CMP​ 之后使用。
  • CL​ 是 x86 架构中寄存器 ECX​ 的低 8 位的别名。

工作原理

SETE​ 指令执行时,CPU 会查看 EFLAGS 寄存器中的零标志(ZF):

  • 如果 ZF 标志被设置(即 ZF=1),这意味着前一条指令的结果为零(例如两个比较值相等),则 SETE​ 指令会将 CL​ 寄存器的值设置为 1。
  • 如果 ZF 标志没有被设置(即 ZF=0),这意味着前一条指令的结果非零(例如两个比较值不相等),则 SETE​ 指令会将 CL​ 寄存器的值设置为 0。

示例

假设我们有以下汇编代码:

CMP AL, BL  ; 比较 AL 和 BL 寄存器的值
SETE CL     ; 如果 AL 和 BL 寄存器的值相等,将 CL 设置为 1;否则设置为 0

这里的 CMP AL, BL​ 指令会比较 AL​ 和 BL​ 寄存器的值,并根据比较结果更新 EFLAGS 寄存器的相关标志位。如果 AL​ 和 BL​ 相等,零标志 ZF 将被设置。接下来 SETE CL​ 指令会检查 ZF:

  • 如果 AL​ 和 BL​ 相等(ZF=1),则 CL​ 被设置为 1。
  • 如果 AL​ 和 BL​ 不相等(ZF=0),则 CL​ 被设置为 0。

MOVB CL, 0x17(SP)

在上一步我们已经将比较的结果从ZF​(零标志) 转入了 CL​, 需要注意的是CL只有8个bit

这里的0x17(SP)​就是栈帧优化后, 返回值的位置.

posted @ 2024-03-30 15:34  pDJJq  阅读(27)  评论(0)    收藏  举报