如何用lw/lb读取内存字符?MIPS补码转换地址越界问题排查
问题分析与解决
地址越界的核心原因
lb $t4, ($t1)触发地址越界,本质是$t1寄存器存储的内存地址不合法,常见场景:
- 未初始化地址:
$t1没有被赋值为合法的内存区域(比如直接使用未赋值的寄存器,或者指向了系统保留/只读内存) - 缓冲区溢出:循环读取时没有控制边界,导致
$t1超出了你定义的二进制串内存范围 - 非法地址赋值:错误地将数值(不是内存地址)加载到
$t1中
快速排查与修复
1. 确保$t1指向合法内存
先在.data段定义足够大小的缓冲区,然后用la指令加载地址:
.data bin_buffer: .space 33 # 32位二进制ASCII + 1字节结束符,足够存储补码 .text la $t1, bin_buffer # 初始化$t1为缓冲区起始地址
2. 循环时添加边界控制
处理32位补码时,循环次数不能超过32次,避免指针越界:
li $t0, 0 # 循环计数器,从0到31 loop_start: bge $t0, 32, loop_end # 超过32次就退出 lb $t4, ($t1) # 现在$t1不会越界 # 你的翻转逻辑... addi $t1, $t1, 1 # 指针后移 addi $t0, $t0, 1 # 计数器+1 j loop_start loop_end:
需求实现细节
1. ASCII位翻转('0'↔'1')
读取到的$t4是ASCII码('0'=0x30,'1'=0x31),直接通过条件判断或异或翻转:
# 读取ASCII字符到$t4后 beq $t4, 0x30, write_1 beq $t4, 0x31, write_0 # 可选:处理非法字符 write_1: li $t4, 0x31 j flip_done write_0: li $t4, 0x30 flip_done: sb $t4, ($t1) # 写回内存
2. 负数补码加1操作
补码加1要在**所有位翻转(取反)**之后执行,从最低位开始处理进位:
# 假设$t1指向二进制串的最低位(缓冲区最后一个有效字符) li $t2, 1 # 初始进位为1 li $t0, 0 # 计数器 addi $t1, $t1, 31 # 指向32位串的最后一位(索引31) add_one_loop: lb $t4, ($t1) sub $t4, $t4, 0x30 # 转成数值0/1 add $t4, $t4, $t2 # 加进位 beq $t4, 2, carry beq $t4, 1, set_1 # 结果为0,进位清零 li $t4, 0x30 li $t2, 0 sb $t4, ($t1) j next_bit carry: li $t4, 0x30 li $t2, 1 sb $t4, ($t1) j next_bit set_1: li $t4, 0x31 li $t2, 0 sb $t4, ($t1) next_bit: addi $t1, $t1, -1 # 指针左移一位 addi $t0, $t0, 1 bne $t0, 32, add_one_loop
内容的提问来源于stack exchange,提问作者Maverick Steelbleu
相关产品推荐
相关产品推荐

