【问题标题】:CMPXCHG8B example using Nasm Assembler使用 Nasm 汇编器的 CMPXCHG8B 示例
【发布时间】:2017-03-22 15:30:24
【问题描述】:

谁能给我一个非常简单的例子,说明如何在 NASM 汇编器中使用 x86 CMPXCHG8B 指令?

【问题讨论】:

  • 当然...cmpxchg8b [offset]
  • @DavidHoelzer :当然,但你能想到为什么 qword 不允许作为 NASM 中的大小说明符(在此指令中)的原因吗?只有一种形式 - 当然,但是明确说明尺寸会有什么问题? YASM 会很高兴地组装它。如果您将 DWORD 放在 YASM 中,它会很好地告诉您大小不匹配。我不明白 NASM 不允许这样做的原因。
  • @MichaelPetch 需要有人报告/询问 nasm 开发人员(甚至制作补丁),不幸的是我不是开发人员之一,我只是喜欢使用它。
  • 它的优先级可能很低,不值得更改。
  • 指令 CMPXCHG16B 也会出现同样的问题,如果我将它与操作数大小说明符 oword 一起使用,如下所示:cmpxchg8b oword [值],我收到以下错误:错误:操作数大小不匹配

标签: assembly x86 nasm intel


【解决方案1】:

一切都应该用cmets、标签和代码结构来解释,只是注意lock前缀。虽然它是原子的,但它也很慢,因为所有内核都必须在此时同步并确保内存访问没有冲突。

再说一次,通常没有合理的理由在没有lock 的情况下使用类似cmpxchg 的指令,因为并行进程的原子同步是唯一优于许多其他解决方案的用法。

对于内存内容的真正简单的非原子“交换”,一组经典的 mov 指令很可能会胜过任何 xchg,尤其是如果您计划提前交换并以适当的延迟读取/写入所有值以不阻塞内存带宽访问。

如果您希望这里有一些关于并行编程同步的教程,那么只需谷歌搜索一些书籍/等,这不是“一个答案”主题,而更像是“一本书”主题。

section .text
    global _start       ;must be declared for using gcc
_start:                 ;tell linker entry point

    ; fail example (memory contains different than expected value)

    ; edx:eax = old value (to compare with memory)
    mov eax,'BAD '
    mov edx,'val.'
    ; ecx:ebx = new value to set
    mov ebx,'NEW '
    mov ecx,`val\n`
    ; CMPXCHG8B should fail, old value is different
    lock cmpxchg8b [value]  ; "lock" makes it atomic for multi-core
    ; here edx:eax == `OLD val\n` (the unexpected content of [value])

    call displayValue

    ; pass example (memory value as expected)

    ; edx:eax = old value (to compare with memory)
    mov eax,'OLD '
    mov edx,`val\n`
    ; ecx:ebx = new value to set
    mov ebx,'NEW '
    mov ecx,`val\n`
    ; CMPXCHG8B should pass, setting up new value
    lock cmpxchg8b [value]  ; "lock" makes it atomic for multi-core

    call displayValue

    ;system call number (sys_exit)
    mov eax, 1
    int 0x80

displayValue:
    mov edx, 8      ;message length
    mov ecx, value  ;message to write
    mov ebx, 1      ;file descriptor (stdout)
    mov eax, 4      ;system call number (sys_write)
    int 0x80        ;call kernel
    ret

section .data

value  db   `OLD val\n`     ; 8 bytes long memory

要构建和运行,请将其另存为“cmpxchg8b.asm”:

nasm -f elf32 cmpxchg8b.asm
ld -m elf_i386 -s -o cmpxchg8b cmpxchg8b.o
./cmpxchg8b

预期输出(当然是在 linux 机器上):

$ ./cmpxchg8bdemo
OLD val                                                                  
NEW val

【讨论】:

  • 非常感谢,但让我很感兴趣的是,与 NASM 中的其他指令不同,cmpxchg8b 的操作数在 [value] 之前没有使用 dword 或 qword,这很不寻常。
  • @MaykelJakson:我不明白,你查看英特尔参考指南中的指令定义了吗?它只有“m64”变体(实际上它是以指令的名称编码的,末尾的“8B”表示“8字节宽的参数”)。所以不需要指定参数大小,它由定义固定。现在我希望 nasm 默默地吃掉cmpxchg8b qword [value],但实际上它无法编译,很奇怪。好的,这也让我感到困惑,我希望它能够默默地将 qword 说明符与 qword 定义匹配并忽略它(当然,其他大小说明符也会失败)。
  • 这就是我要说的,cmpxchg8b qword [value] 对我不起作用,我总是在 NASM 中使用大小说明符。所以我的代码没有编译,这就是我寻求帮助的原因。
  • @Ped7g :我要指出的是,我认为 NASM 在那里不支持 qword 是一个错误。 YASM 没有抱怨。
  • @Ped7g 实际上,一个完整的示例可能对其未来的其他人也有帮助。
猜你喜欢
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 2015-07-08
相关资源
最近更新 更多