2016-11-19 1 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

매크로의 레지스터 args를 알 고의 스크래치 규정으로 사용하지 않는 이유는 무엇입니까? 발신자가 원본을 저장하려고하면 원본을 저장할 수 있지만 푸시/팝 파트가 필요하지 않은 경우이 방법을 사용하면 원본을 효율적으로 사용하지 못하게됩니다. (즉, 매크로를 사용하는 것보다 C 컴파일러에서 더 좋은 결과를 얻을 수 있습니다). –

+0

@PeterCordes - 죄송 합니다만, 귀하의 의견을 이해할 수 없습니다. 내 게시물은 인콰이어러에게 매크로 작성 방법을 보여주기위한 것이 아니 었습니다. GCD를위한 어셈블리를 작성하는 한 가지 방법. 명확히하십시오. – InfinitelyManic

+1

매크로는'push {r1-r2}'와 일치하는 pop을 포함합니다. args를'r1'과'r2'에 넣는 두 개의 MOV 명령어도 포함되어 있습니다. 그것들은 명령의 낭비이기도하다.'r1'이 나타나는 곳에서 매크로의 어디에서나'\ n1'을 사용하는 것과 비교하면, (또한,'gcd r2, r1'로 사용하면 매크로가 깨집니다. 왜냐하면 첫 번째 mov 두 번째 주장을 망칠 것이다). 마지막으로 더 좋은 코드를 얻는 대신 매크로 클로버 둘 다 입력 내용을 기록하고 (r0을 하드 코딩하는 대신) 세 번째 레지스터 arg에 출력을 생성하면됩니다. –

관련 문제