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

为何int 0x80调用会使rsi寄存器的整数取值变更而字符取值不变?

汇编行读取代码的调试问题分析与修复

问题代码

lp:
save
mov rax, 3
mov rbx, 2
mov rcx, rsi
mov rdx, 1 
int 80h
load

cmp [rsi], byte 0xa
je done
inc rsi
jmp lp
done:

其中save和load是用于push/pop rax、rbx、rcx、rdx寄存器的宏。

问题现象

代码可正常读取整行内容,但第二次迭代时,GDB中观察到[rsi]的整数取值发生变化,但其字符取值保持不变,调试输出如下:

13: $rdi = 4206592
14: $rsi = 4206593
15: *(int*)($rdi) = 14391
16: *(int*)($rdi+1) = 56
17: *(char*)($rdi) = 55 '7'
18: *(char*)($rdi+1) = 56 '8'

问题根源分析

  1. 32位/64位调用规范混用:你使用rax、rbx等64位寄存器,但int 80h是32位Linux系统调用接口,它仅处理寄存器的低32位,高32位数据会被破坏。这导致你用*(int*)查看内存时,会包含被破坏的高字节数据,而*(char*)只读取低8位,因此字符显示正常。
  2. 系统调用参数错误:32位read调用的文件描述符参数中,你用了2(标准错误流)而非0(标准输入),这意味着你实际读取的不是用户输入;同时64位环境下混用32位调用规范,会导致寄存器状态混乱。
  3. 缺少返回值检查:read调用的返回值存储在rax中,你未判断是否读取失败或到达EOF,可能导致后续循环访问非法内存。

修复方案(64位环境适配)

改用64位Linux系统调用规范(syscall指令),修正参数与调用逻辑:

lp:
save
mov rax, 0          ; 64位read系统调用号为0
mov rdi, 0          ; 标准输入文件描述符为0
mov rdx, 1          ; 每次读取1字节
syscall             ; 64位系统调用指令
load

cmp rax, 0          ; 检查是否读取到EOF或调用失败
jle done

cmp byte [rsi], 0xa ; 判断是否为换行符
je done

inc rsi
jmp lp
done:

关键修改说明

  • 替换int 80h为syscall,遵循64位系统调用规范,避免寄存器高32位被破坏
  • 修正read的系统调用号与文件描述符,确保读取的是标准输入流
  • 添加返回值检查,避免读取失败后继续循环
  • 规范寄存器使用逻辑,消除寄存器状态混乱导致的内存地址异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:11:05