MIPS(汇编) - 二进制搜索问题 - 中间数组元素的地址未对齐?

发布于 2025-01-26 05:40:52 字数 1581 浏览 3 评论 0原文

        .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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小红帽 2025-02-02 05:40:52

看来您正在使用字节偏移而不是单词索引。这很好且良好(而不是每次使用地址时重做左移动),但这意味着正确的偏移不会截断为单词偏移,而是可以转移到该字节的字节中的一部分地址,低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 in check_lower中掉落函数的底部:返回。您要么需要重新加载$ ra并在这些路径中返回,要么在重新加载后将尾巴呼叫到j b b $ ra ,不是jal/reload $ ra/jr $ ra

jalcheck_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 because andi 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 the 0x0000000e you tried to deref wasn't also a separate bug of getting adding a small offset to a NULL pointer), you could andi with 0x0000fffc 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 extra li right before you want to and. (addiu can materialize a -4 in one instruction, unlike ori.)


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 in check_lower: returns. You either need to reload $ra and return in those paths, or optimize the tail-call into a j or b after reloading $ra, not jal / reload $ra / jr $ra.

Same for the jal in check_higher:; you don't want to fall through into check_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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文