MIPS计算器开发遇运行时异常:地址未按字边界对齐
MIPS计算器开发中的字对齐异常问题
问题描述
开发MIPS计算器时,需读取用户输入的运算符号存入数据段,后续取出用于比较。但执行lw $t4, stopsign和lw $t5, addb时,始终触发运行时异常:
Runtime exception at 0x004000b8: fetch address not aligned on word boundary 0x1001005a
而lw $t3, mulb和lw $t6, subb无异常,怀疑是字符(!/+)导致问题,相关代码如下:
.data IfStart: .asciiz "Start Calculator? (0: no, 1: yes):" msg: .asciiz "Enter operation symbol (+, -, *) or ‘!’ to quit:" mulb: .asciiz "*" addb: .asciiz "+" subb: .asciiz "-" stopsign: .asciiz "!" newline: .asciiz "\n" pick1: .asciiz "Enter first number (A):" pick2: .asciiz "Enter second number (B):" badnumber: .asciiz "Bad input\n" bye: .asciiz "Good bye!" one: .word 1 result: .asciiz "The result is:" buffer: .space 20 .text main: li $v0,4 la $a0,IfStart syscall li $v0,5 #get number from user syscall move $t0,$v0 lw $t1, one beq $t1,$t0,if1 beq $zero,$t0,if0 li $v0,4 la $a0,badnumber syscall li $v0,4 la $a0,bye syscall li $v0,10 syscall if1: jal Calculator if0: li $v0,4 la $a0,bye syscall li $v0,10 syscall Calculator: li $v0,4 #print first message la $a0,msg syscall li $v0,8 #take in input la $a0, buffer #load byte space into address li $a1, 20 # allot the byte space for string move $t2,$a0 #save string t2 syscall li $v0,5 #Read int A syscall move $t0,$v0 #t0 is A li $v0,5 #Read int B syscall move $t1,$v0 #t1 is B lw $t3, mulb #mul sign lw $t6, subb #sub sign lw $t4, stopsign lw $t5, addb #add sign beq $t3,$a0,stop beq $t4,$a0,multp beq $t5,$a0,adds beq $t6,$a0,subbs multp: jal Multiply j print adds: jal Sum j print subbs: jal Substract print: li $v0,4 #print the result is: la $a0,result syscall #print result li $v0, 1 move $a0, $t3 syscall li $v0,4 #print new line la $a0,newline syscall jal Calculator stop: li $v0,10 syscall
问题原因
MIPS架构的lw(加载字)指令要求访问的内存地址必须是字对齐的(即地址值能被4整除)。而.asciiz定义的字符串会自动在末尾添加null终止符(\0),每个字符串占用2字节(字符+null)。数据段中变量按顺序存储,前几个字符串的地址排列刚好让mulb和subb的地址是4的倍数,而stopsign和addb的地址不满足对齐要求,因此执行lw时触发异常——这和字符本身无关,完全是地址对齐问题。
解决方案
改用字节加载指令:我们只需要单个字符的ASCII值,用
lb(加载字节)指令替代lw,lb不要求地址对齐,能正确读取单个字符:lb $t3, mulb #mul sign lb $t6, subb #sub sign lb $t4, stopsign lb $t5, addb #add sign强制地址对齐:在数据段中每个字符串前添加
.align 2指令,强制让变量地址按字对齐:.data IfStart: .asciiz "Start Calculator? (0: no, 1: yes):" msg: .asciiz "Enter operation symbol (+, -, *) or ‘!’ to quit:" .align 2 mulb: .asciiz "*" .align 2 addb: .asciiz "+" .align 2 subb: .asciiz "-" .align 2 stopsign: .asciiz "!"修正比较逻辑:当前代码中
beq $t3,$a0,stop的比较逻辑错误——$a0是buffer的内存地址,而$t3是字符的ASCII值,应该读取buffer中的第一个字符再和运算符号的ASCII值比较:# 在读取完运算符号输入后,添加以下代码 lb $t7, ($t2) # 从buffer中读取输入的第一个字符 # 修正比较指令 beq $t4,$t7,stop beq $t3,$t7,multp beq $t5,$t7,adds beq $t6,$t7,subbs
内容的提问来源于stack exchange,提问作者Shalev Levi Sagzan
相关产品推荐
相关产品推荐

