MIPS(汇编) - 二进制搜索问题 - 中间数组元素的地址未对齐?
.text
j main
binary_search:
slt $t0, $a2, $a1 # if last < first, $t0 = 1
beq $t0, $zero, check_mid # if first > last, proceed to return -1
addi $v0, $zero, -1
jr $ra # exit with returned argument
check_mid:
# saving address to stack
addi $sp, $sp, -4
sw $ra, 4($sp)
sub $t1, $a2, $a1 # last - first
srl $t1, $t1, 1 # (last - first) /2
add $t2, $a1, $t1 # $t2 is referrencing the mid index of the array
lw $t3, 0($t2) # $t3 is the mid element of the array
bne $t3, $a0, check_higher
add $v0, $t2, $zero # $v0 is the index of the wanted element
lw $ra, 4($sp)
addi $sp, $sp, 4
jr $ra # exit with returned argument
check_higher:
slt $t0, $t3, $a0 # if arr[mid] < x, $t0 is 1
bne $t0, $zero, check_lower
addi $t1, $t1, -4 # mid = mid - 4
jal binary_search # recursion call
check_lower:
addi $t1, $t1, 4 # mid = mid + 4
jal binary_search # recursion call
main:
addi $a0, $zero, 64
addi $a1, $zero, 0
addi $a2, $zero, 28
jal binary_search
所以这是我到目前为止的代码。据我所知,我对代码几乎完成了,除非我不太照顾堆栈中保存/加载返回地址,但这不是我现在的主要关注点。
我想弄清楚的是,如何达到数组的中间偏移/元素?因为执行此代码会给我带来错误:“行39:运行时异常在0x00400028:未在Word Boundare 0x0000000e上对齐的地址”(第39行是此行:lw $ t3,0($ t2)#$ T3是数组的中元
)
.text
j main
binary_search:
slt $t0, $a2, $a1 # if last < first, $t0 = 1
beq $t0, $zero, check_mid # if first > last, proceed to return -1
addi $v0, $zero, -1
jr $ra # exit with returned argument
check_mid:
# saving address to stack
addi $sp, $sp, -4
sw $ra, 4($sp)
sub $t1, $a2, $a1 # last - first
srl $t1, $t1, 1 # (last - first) /2
add $t2, $a1, $t1 # $t2 is referrencing the mid index of the array
lw $t3, 0($t2) # $t3 is the mid element of the array
bne $t3, $a0, check_higher
add $v0, $t2, $zero # $v0 is the index of the wanted element
lw $ra, 4($sp)
addi $sp, $sp, 4
jr $ra # exit with returned argument
check_higher:
slt $t0, $t3, $a0 # if arr[mid] < x, $t0 is 1
bne $t0, $zero, check_lower
addi $t1, $t1, -4 # mid = mid - 4
jal binary_search # recursion call
check_lower:
addi $t1, $t1, 4 # mid = mid + 4
jal binary_search # recursion call
main:
addi $a0, $zero, 64
addi $a1, $zero, 0
addi $a2, $zero, 28
jal binary_search
So this is my code so far. as far as I can see it I'm pretty much done with the code, unless I didn't take care well enough of saving/loading returning addresses from the stack, but that's not my main concern right now.
What I'm trying to figure out, is how do I reach the middle offset/element of the array? because executing this code will bring me the error: "line 39: Runtime exception at 0x00400028: fetch address not aligned on word boundary 0x0000000e" (line 39 is this line: lw $t3, 0($t2) # $t3 is the mid element of the array
)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看来您正在使用字节偏移而不是单词索引。这很好且良好(而不是每次使用地址时重做左移动),但这意味着正确的偏移不会截断为单词偏移,而是可以转移到该字节的字节中的一部分地址,低2个字节。与C不同,如果您做了
MID =(HI-LO)&gt; 1;
,它只会将值的底部移出。srl $ t1,$ t1,1
因此可以产生一个奇怪的半词地址,而不是将其截断为对齐的单词地址。您可以使用
和
使用-4
,即0xfffffffc
在移动后清除那些地址位,但是MIPS无法在一个指令中这样做,因为<代码> andi 零扩展其即时。如果您的数组真的很小于64KIB,并且在非常低的地址接近零(因此0x0000000e
您尝试deref也不是将小偏移添加到一个的单独错误null指针),您可以使用0x0000fffc
来截断地址。或者,如果您要使用偏移而不是实际指针,请在将其添加到实际地址之前,然后将其添加到实际地址。
当然,您可以在循环之前一次
li $ t9,-4
一次使用,但是您使用的是递归而不是更有效的循环。因此,我想您无论如何都不在乎效率,并且可以在要和
之前就可以做一个额外的li
。 (addiu
可以在一个指令中实现-4
,不同于ori
。)或另一种方法是正确地移动您想要的位将所有路程都从寄存器中删除,然后左右移动,将数据带回您想要的位置。
mid =((Hi-lo)&gt;&gt; 3)&lt;&lt;&lt; 1;
也有其他错误,例如在
JAL BINARY_SERACH
incheck_lower中掉落函数的底部:
返回。您要么需要重新加载$ ra
并在这些路径中返回,要么在重新加载后将尾巴呼叫到
b $ ra ,不是j
bjal
/reload$ ra
/jr $ ra
。jal
在check_higher中相同:
;您不想陷入check_lower
,最终会检查两侧的总运行时,而不是O(log n)。但是,这些都是您应该通过调试器单步步进行调试的所有事情,并与有趣的右移问题分开,在使用单词地址或字节偏移的ASM中进行二进制搜索时,可以创建一个奇怪的halfword地址。
It looks like you're working with byte offsets instead of indexes for words. That's fine and good (instead of redoing left-shifting every time you use the address), but it means that a right shift won't truncate to a word offset, it can shift a bit into the byte-within-word part of the address, the low 2 bytes. Unlike in C if you did
mid = (hi-lo)>>1;
which would simply shift a bit out the bottom of the value.srl $t1, $t1, 1
can thus produce an odd halfword address, instead of truncating down to an aligned word address.You could
and
with-4
, i.e.0xfffffffc
to clear those address bits after shifting, but MIPS can't do that in one instruction becauseandi
zero-extends its immediate. If your array really is known to be smaller than 64KiB and at a very low address close to zero (so the0x0000000e
you tried to deref wasn't also a separate bug of getting adding a small offset to a NULL pointer), you couldandi
with0x0000fffc
to truncate an address. Or do that on an offset before adding it to an actual address if you're working with offsets instead of actual pointers.Of course you could just
li $t9, -4
once before your loop and use that, but you're using recursion instead of a more efficient loop. So I guess you don't care about efficiency anyway and could just do an extrali
right before you want toand
. (addiu
can materialize a-4
in one instruction, unlikeori
.)Or the other way would be to right shift the bits you want to discard all the way out of the register, and then to a left shift to bring you data back to where you want it.
mid = ((hi-lo)>>3) << 1;
Also you have other bugs, like falling off the bottom of your function after the
jal binary_search
incheck_lower:
returns. You either need to reload$ra
and return in those paths, or optimize the tail-call into aj
orb
after reloading$ra
, notjal
/ reload$ra
/jr $ra
.Same for the
jal
incheck_higher:
; you don't want to fall through intocheck_lower
, that would end up checking both sides for O(N) total runtime, not O(log N).But those are all things you should debug by single-stepping with a debugger, and separate from the interesting indexing problem of right-shift creating an odd-halfword address when doing binary search in asm with word addresses or byte offsets.