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

Ubuntu下x86-64汇编:如何逐位读取rdi传递的char*数字字符?

这是个很典型的x86-64汇编内存操作宽度的问题,我来帮你理清楚并解决它:

问题根源

你现在遇到的情况,核心是x86-64汇编里的内存读取操作是和寄存器宽度绑定的:

  • 当你用mov rbx, [rdi]时,因为rbx是64位寄存器,这条指令会从rdi指向的内存地址开始,一次性读取8个连续字节的数据加载到rbx里。
  • 对于你的示例字符串"87",内存里存储的是0x38('8'的ASCII值)和0x37('7'的ASCII值),后面跟着的是内存里的其他数据(可能是0或者随机垃圾)。由于x86是小端字节序,这些字节会被倒序存入rbx,所以你看到的是0x3738(后面的高字节是内存里的后续数据,只是你没注意到)。
  • 执行inc rdi后,rdi指向第二个字符的地址,此时mov rcx, [rdi]还是读取8个字节,所以低字节是0x37,剩下的7个字节是后续内存数据。

解决方法:读取单个字节的正确姿势

要只读取[rdi]指向的单个字符(1字节),你需要明确指定1字节宽度的内存操作,有几种常用方式:

1. 直接使用8位子寄存器

x86-64的通用寄存器都有对应的8位子寄存器(比如rbx的低8位是bl,rcx的低8位是cl),直接用这些子寄存器来接收单字节数据:

mov bl, [rdi]   ; 仅读取rdi指向的1字节,存入bl(rbx的低8位)
inc rdi
mov cl, [rdi]   ; 读取下一个1字节,存入cl(rcx的低8位)

这样bl里就只有0x38(对应'8'),cl里只有0x37(对应'7'),完全符合你要读取单个字符的需求。

2. 用movzx做零扩展(推荐用于后续数值计算)

如果你之后需要把字符的ASCII值扩展到64位寄存器做数值运算(比如转成数字),推荐用movzx(Move with Zero Extend)指令。它会把读取的单字节数据零扩展到32位或64位寄存器,避免符号扩展带来的问题(默认C里的char是有符号类型,若字符的最高位为1,普通mov会把它扩展成负数):

movzx rbx, byte [rdi]  ; 读取rdi指向的1字节,零扩展为64位存入rbx
inc rdi
movzx rcx, byte [rdi]  ; 读取下一个1字节,零扩展为64位存入rcx

执行后rbx的值是0x0000000000000038,rcx是0x0000000000000037,非常适合后续把ASCII字符转成数字(比如减去0x30得到对应的数值8和7)。

3. 显式指定内存操作宽度(不推荐,易踩坑)

你也可以在mov指令里显式指定读取1字节,但要注意符号扩展的问题:

mov rbx, byte [rdi]  ; 读取1字节,但会符号扩展到64位
; 若字符是0x80及以上,rbx会变成0xffffffffffffff80,这通常不是你想要的

所以除非你明确需要符号扩展,否则优先用前两种方法。

额外小技巧:ASCII字符转数字

拿到单个字符的ASCII值后,要转成对应的十进制数字,只需要减去字符'0'的ASCII值(0x30)即可:

movzx rbx, byte [rdi]
sub rbx, 0x30  ; 现在rbx里就是字符对应的数字(比如'8'转成8)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:28:47