You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

汇编cmp指令与寻址疑问:strlen函数中不同cmp写法的异常原因解析

搞懂x86-64汇编里的寄存器、内存寻址和字符串判断

嘿,作为汇编新手碰到这些寄存器和内存的差异太正常了,我来帮你逐个拆解清楚每个问题的本质!

首先先确认你的正确代码逻辑:

.loop:
    inc rax
    inc rbx
    cmp [rbx], byte 0
    jne .loop
ret

这段代码能正常工作,是因为[rbx]表示取出rbx寄存器里存储的地址所指向的内存中的1个字节,和字符串末尾的byte 0(null终止符)比较,判断是否循环结束。这里的核心是你在访问内存里的字符串内容。

接下来逐个分析你的疑问:

1. 为什么cmp bl, 0会得到错误的长度?

bl是rbx寄存器的低8位部分,它存储的是指针本身的低8位数值,而不是指针指向的内存里的字符。

你的代码里rbx是字符串的指针,每次inc rbx是让指针往高地址移动(比如从0x12345678变成0x12345679),而bl只是这个地址的最后两位(比如0x78、0x79)。拿bl和0比较,完全不是在判断字符串的null终止符,自然会算出错误的长度。

2. 为什么cmp [bl], 0会报「invalid effective address」错误?

x86-64架构的汇编规则里,内存寻址不能使用8位寄存器(比如bl、al、cl等)作为基址寄存器,必须用32位(如ebx)或64位(如rbx)的通用寄存器来做内存寻址的基址。所以[bl]这种写法是非法的,汇编器直接拒绝编译。

3. 为什么cmp rbx, 0永远无法停止?

你的猜测完全正确!rbx是字符串的指针,初始值是字符串的起始地址(肯定不是0,因为0地址在系统里是无效的空指针),每次inc rbx会让指针往更高的内存地址移动,数值只会越来越大,永远不可能等于0。所以jne .loop永远成立,循环会无限跑下去。

那为什么有些人能用cmp bl, 0?

他们的代码逻辑和你的不一样!正确使用cmp bl, 0的场景,是先把内存里的字符加载到bl寄存器中,再做比较,比如:

; 假设rax初始为0,rbx指向字符串首地址
.loop:
    mov bl, [rbx]   ; 把rbx指向的内存字节读到bl寄存器里
    cmp bl, 0       ; 现在bl里存的是字符串的当前字符,和null比较
    je .done        ; 是null就退出循环
    inc rax         ; 长度+1
    inc rbx         ; 指针后移
    jmp .loop
.done:
ret

这里bl里存的是字符串的字符内容,而不是指针的一部分,所以cmp bl, 0才能正确判断终止符。

总结一下核心区别:

  • [rbx]:访问rbx指向的内存内容
  • rbx/bl:使用寄存器本身存储的数值
  • 内存寻址只能用32/64位寄存器,不能用8位寄存器

内容的提问来源于stack exchange,提问作者cassepipe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:57:38