QTSPIM中整数转字符串循环的sb指令报错,求技术排查帮助
解决QTSPIM中整数转字符串的非法地址错误
你遇到的Bad address in data/stack read: 0x0000003f错误,根源是地址处理逻辑错误,把ASCII字符值当成了内存地址使用,以下是具体问题和修复方案:
核心问题与修复
1. 非法地址初始化
在update_and_store_red段中,move $t4, $t2是致命错误:此时$t2是从read_red读取的ASCII字符(比如空格的ASCII码32),你把这个字符值当作buffer的地址使用,后续addi $t2, $t2, 31得到32+31=63(0x3f),这显然不是buffer的合法内存地址,导致存储时触发非法访问。
修复代码:
update_and_store_red: move $t0, $t8 # Copy the integer to convert la $t4, buffer # 加载buffer的基地址到$t4 addi $t2, $t4, 31 # 指向buffer的第32个字节(索引31),用来存字符串终止符 sb $zero, ($t2) # 写入字符串终止符 addi $t2, $t2, -1 # 移动指针到前一个位置,准备存储数字字符 jal int_to_string li $v0, 15 # System call code for writing a byte move $a0, $s1 # File descriptor move $a1, $t4 # 从buffer基地址开始写入 li $a2, 32 # 写入32字节(buffer的前32位,可根据实际调整) syscall # ... 其他代码保持不变
2. max_val取值错误
prep_to_read_pixels中的la $t6, max_val是加载max_val的内存地址,而非它的实际数值,后续ble $t8, $t6是拿整数和地址比较,逻辑完全错误。
修复:
prep_to_read_pixels: # ... 其他初始化代码 lw $t6, max_val # 加载max_val的实际数值(255),而非地址 # ... 其他代码
3. int_to_string中的冗余代码
int_to_string开头的addi $t7, $t7, 1完全多余,$t7在此函数中没有作用,还会破坏寄存器原有值,直接删除即可。
修复后的int_to_string:
int_to_string: div $t0, $t0, 10 # Divide $t0 by 10 (quotient in $t0, remainder in $t3) mflo $t0 # 更新$t0为商 mfhi $t3 # 获取余数到$t3 addi $t3, $t3, 48 # 转换为ASCII字符 sb $t3, 0($t2) # Store the ASCII character in the buffer addi $t2, $t2, -1 # 左移指针,准备存储下一个字符 bnez $t0, int_to_string # 商不为0则继续循环 done: jr $ra
4. 系统调用参数错误
la $a2, 64是尝试加载地址64,而系统调用15(文件写入)需要的是写入的字节数,应该用li指令加载数值:
li $a2, 32 # 替换原有的la $a2,64,这里用32是因为我们用了buffer的32字节区域
修复后的完整代码
.data header_buffer: .asciiz "123 " width: .word 0 # Integer to store width of file height: .word 0 # Integer to store height of file max_val: .word 0 # Integer to store maximum value of a pixel num_pixels: .word 0 # Integer to store number of pixels in file buffer: .space 128 filename: .asciiz "input.ppm" output_filename: .asciiz "output.ppm" .text .globl main main: li $t0, 64 sw $t0, width sw $t0, height li $t0, 255 sw $t0, max_val li $t0, 12288 sw $t0, num_pixels # Open the output file for writing open_output: li $v0, 13 # System call code for opening a file (write mode) la $a0, output_filename li $a1, 1 # File mode (write) li $a2, 0 syscall move $s1, $v0 # Save the file descriptor in $s1 # Initialise registers prep_to_read_pixels: li $s2, 0 # Sum of R values li $s3, 0 # Sum of G values li $s4, 0 # Sum of B values li $t5, 0 # Pixel counter lw $t6, max_val # 修复:加载max_val的数值而非地址 li $t8, 0 # Int value of pixel la $t1, header_buffer li $t0, 0 read_red: lb $t2, 0($t1) # Load the read character move $t7, $t2 # Copy read char to $t7 addi $t1, $t1, 1 # Move pointer addi $t0, $t0, 1 #track num digits in number addi $t9, $t9, 1 # Increment - change position of the end of header to the current end beq $t2, 32, incr_red # Check if char is whitespace beq $t2, 10, incr_red # Check if char is new line jal loop_to_convert j read_red incr_red: addi $t5, $t5, 1 add $s2, $s2, $t8 addi $t8, $t8, 10 ble $t8, $t6, update_and_store_red jal clamp j update_and_store_red update_and_store_red: move $t0, $t8 # Copy the integer to convert la $t4, buffer # 修复:加载buffer基地址 addi $t2, $t4, 31 # 修复:指向buffer的第32字节位置 sb $zero, ($t2) # 写入字符串终止符 addi $t2, $t2, -1 # 移动指针到前一位 jal int_to_string li $v0, 15 # System call code for writing a byte move $a0, $s1 # File descriptor move $a1, $t4 # 从buffer基地址开始写入 li $a2, 32 # 修复:用li加载数值而非la加载地址 syscall li $t2, 0 li $t0, 0 beq $t5, 1, exit j read_red exit: # Close the file li $v0, 16 # Close syscall code move $a0, $s1 # File descriptor syscall # Exit the program li $v0, 10 # Exit syscall code syscall loop_to_convert: addi $t7, $t7, -48 # Convert ascii char to digit equivalent by subtracting "0" (ascii code 48) mul $t8, $t8, 10 # Multiply the running total by 10 add $t8, $t8, $t7 # Add new digit to running total jr $ra # Jump back clamp: li $t8, 255 # Clamp value to 255 jr $ra int_to_string: div $t0, $t0, 10 # Divide $t0 by 10 (get quotient in $t0, remainder in $t3) mflo $t0 # Quotient mfhi $t3 # Remainder addi $t3, $t3, 48 # Convert to ASCII sb $t3, 0($t2) # Store the ASCII character in the buffer addi $t2, $t2, -1 # Move the pointer to the left in the buffer bnez $t0, int_to_string # Repeat until $t0 becomes zero done: jr $ra
内容的提问来源于stack exchange,提问作者studentinneed
相关产品推荐
相关产品推荐

