2016-11-19 76 views
0

我對彙編語言非常陌生,我正在編寫一個程序來計算GCD,但我遇到了麻煩。輸入兩個數字時,它不會返回正確的答案。有什麼建議麼?我認爲這個問題是在gcd功能,但我不知道。裝配在ARM中的GCD函數不能正常工作

.text 
.global main 


    // Usage of the function: gcd(x,y), with the gcd returned in R0. 
    // Parameters: Register R0 must contain x, and register R1 must contain y. 
gcd: 
    bal mod 
    cmp r0, #0 
    bne gcd 
    // end of gcd function 

    // Utility modulus function for you to use in your gcd function: 
    // Usage: mod(x,y), returns the modulus of x and y in register R0. 
    // Parameters: Register R0 must contain x, and register R1 must contain y. 
mod: push {LR} 
    mov R3, R1 
    mov R1, #0 
    mov R2, #1 
    //Shift the denominator left until greater than numerator, then shift back 
_shift_left: 
     //R3<<=1; //Denominator shift left 
    mov r3, r3, asl #1 
     //R2<<=1; //Division shift left 
    mov r2, r2, asl #1 
     //if(R0>R3)goto _shift_left;//Shift Left until Decrement/Division Greater than Numerator 
    cmp r0, r3 // compare r0 to r3 
    bgt _shift_left // branch if greater than to _shift_left label 
     //R3>>=1; //Shift Denominator right 
    mov r3, r3, asr #1 
     //R2>>=1; //Shift Division right 
    mov r2, r2, asr #1 
     //Loop and keep subtracting off the shifted Denominator 
_subtract: //if(R0<R3)goto _done; 
    cmp r0, r3 // compare r0 to r3 
    blt _done // branch if less than to _done 
     //R1+=R2; //Increment division by the increment 
    adds r1, r2 
     //R0-=R3; //Subtract shifted Denominator with remainder of Numerator 
    subs r0, r3 //Shift right until denominator is less than numerator 
_shift_right: 
     //if(R2==1) goto _subtract; 
    cmp r2, #1 // compare r2 to #1 
    beq _subtract // branch if equal to _subtract 
     //if(R3<=R0)goto _subtract; 
    cmp r3, r0 // compare r3 to r0 
    ble _subtract // branch if less than or equal to _subtract 
     //R2>>=1; //Shift Increment left 
    mov r2, r2, asr #1 
     //R3>>=1; //Shift Denominator left 
    mov r3, r3, asr #1 
     //goto _shift_right; //Shift Denominator until less than Numerator 
    bal _shift_right 
     //goto _subtract; //Keep Looping until the division is complete 
    bal _subtract 
_done: pop {PC} 
// end of mod function 

main: 
    push {LR} 
    ldr R0, =welcome 
    bl printf 

    ldr R0, =prompt_a 
    bl printf 

    ldr R0, =scan_pat 
    ldr R1, =a 
    bl scanf 

    ldr r0, =prompt_b 
    bl printf 

    ldr r0, =scan_pat 
    ldr r1, =b 
    bl scanf 

    ldr r0, =a 
    ldr r0, [r0] 
    ldr r1, =b 
    ldr r1, [r1] 
    bl gcd 
    ldr r1, =gcd_result 
    str r0, [r1] 

    ldr r0, =gcd_msg 
    ldr r1, =a 
    ldr r1, [r1] 
    ldr r2, =b 
    ldr r2, [r2] 
    ldr r3, =gcd_result 
    ldr r3, [r3] 
    bl printf 

    mov r0, #0 
    pop {PC} 
// end of main function 

.data 
welcome: .asciz "Welcome to the GCD Program!\n" 
prompt_a: .asciz "Enter a value for A: " 
prompt_b: .asciz "Enter a value for B: " 
gcd_msg: .asciz "gcd(%d,%d) = %d\n" 
scan_pat: .asciz "%d" 

a: .word 0 
b: .word 0 
gcd_result: .word 0 
+0

我建議用更高級的語言編寫函數,然後只將*函數轉換爲程序集。 C是一種易於編譯爲手動組裝的語言。另外,學習使用調試器。另外,我建議學習並堅持平臺調用約定。 – EOF

回答

1

下面是一個ARMv7 GCD宏。您應該能夠將其編寫爲函數並忽略.macro指令等。我正在使用GCC指令。

我沒有在一段時間內測試過代碼,所以它可能包含一些錯誤,並且在某些情況下它可能不是有效的;儘管如此,它應該可以幫助你。

 1:                                        

     cmp  r1, r2   // r1 - r2 set cpsr                              
     subgt r1, r1, r2  // sub if r1 > r2 and put result in r1                         
     mov r0, r1                                      
     sublt r2, r2, r1  // else sub if r2 < r1 and put result in r2                        

     bne 1b                                       
+1

爲什麼不使用宏的寄存器參數作爲算法的臨時寄存器?如果主叫方想要保存原件,他們可以這樣做,但如果您不需要按下/彈出部分,這種方式可以阻止您有效使用原件。 (即你可能從C編譯器獲得比使用宏這種方式更好的結果)。 –

+0

@PeterCordes - 對不起,我不明白你的意見。我的帖子並不打算向查詢者展示如何編寫宏;只是寫一些GCD大會的一種方式。請澄清。 – InfinitelyManic

+1

您的宏包含'push {r1-r2}'和一個匹配的彈出窗口。它還包含兩條MOV指令,將參數放在'r1'和'r2'中。這些也是浪費指令,與在你的宏中出現r1的地方使用'\ n1'等相比(同樣,如果你使用它作爲'gcd r2,r1',你的宏會中斷,因爲第一個mov將會破壞第二個arg)。如果您只是記錄宏對其輸入進行破壞並在第三個寄存器arg中生成輸出(而不是對r0進行硬編碼),則最終會得到更好的代碼。 –