2012-07-15 11 views
0

linux에서 AT &t 구문의 어셈블러를 사용하고 있습니다. 3 개의 숫자 (a, b, c)를 나누고 곱해야합니다. 이 작업은/b * c 일 가능성이 높습니다. idiv 및 imul 명령을 사용하여 시도했지만 물론 정수 값에서 작동하므로 총 정확도가 떨어집니다. 또한 fidiv와 fimul istruction을 사용하여 float를 계산하려고했지만 완전히 잘못된 결과가 나타납니다. 아마도 잘못된 레지스터에서 연산을 수행하고 있습니다. 누군가 내가 AT & T에서 fidiv/fimul을 사용하는 방법에 대한 예를 들어 주시겠습니까? 등록 기관에서 그러한 사용법을 사용합니까?어셈블러 부동 소수점 연산

미리 감사드립니다.

+1

"나는 또한 노력을 fidi를 ​​사용하는 v와 fimul ... "그럼 우리가 보여 주신 것을 보여주십시오. –

답변

0

마찬가지로 AT & T는 gas (GNU Assembler)의 출력 구문이므로 너무 오래 생각하면 안됩니다. 그냥 C로 작성하고 -S 스위치를 사용하여 어셈블러 출력을 생성하십시오.

Exemple :

main(){ 
    int a = 7; 
    int b = 3; 
    int c = 2; 
    return (double)a/(double)b*(double)c; 
} 

abc.c 소스 파일에서 다음 프로그램을 입력 할 경우 다음 사용하여 컴파일

gcc -S abc.c 나는 다음과 같은 어셈블리 소스 코드를 얻을 :

.file "abc.c" 
.text 
.globl main 
.type main, @function 
main: 
.LFB0: 
.cfi_startproc 
pushq %rbp 
.cfi_def_cfa_offset 16 
.cfi_offset 6, -16 
movq %rsp, %rbp 
.cfi_def_cfa_register 6 
movl $7, -4(%rbp) 
movl $3, -8(%rbp) 
movl $2, -12(%rbp) 
cvtsi2sd -4(%rbp), %xmm0 
cvtsi2sd -8(%rbp), %xmm1 
movapd %xmm0, %xmm2 
divsd %xmm1, %xmm2 
movapd %xmm2, %xmm1 
cvtsi2sd -12(%rbp), %xmm0 
mulsd %xmm1, %xmm0 
cvttsd2si %xmm0, %eax 
popq %rbp 
.cfi_def_cfa 7, 8 
ret 
.cfi_endproc 
.LFE0: 
.size main, .-main 
.ident "GCC: (Debian 4.6.3-1) 4.6.3" 
.section .note.GNU-stack,"",@progbits 

무엇을해야할까요? 스택에 3 int를위한 공간을 제공하고, 상수 값을 저장하고, double (cvtsi2sd)로 변환하고, 나눗셈을 수행합니다 (주의 : 을 div b, a으로 작성하면 결과는 두 번째 레지스터에 저장됩니다). 등등. 명백한 것은 컴파일러가 FPU 스택을 사용하지 않고도 부동 소수점 컴퓨팅을 수행하는 더 간단한 방법이있는 것처럼 오래된 FPU 8087 명령어 세트를 사용하는 것을 귀찮게하지 않는다는 것입니다. 질문이 대상 시스템에서 아무 것도 말하지 않기 때문에 필자는 컴파일러가 그러한 컴퓨팅을 수행하도록 할 것입니다.

일부 사람들 (내 대답은 downvoted)에 대해 여전히 불분명 할 수 있으므로 gcc 출력에 대한 재주문을 수행하여 (쓸데없는 것들을 이동하지 않도록) 주석을 추가했습니다. 유일한 가능성있는 함정은 div에 대한 인수 순서입니다. 데이터를 입력하고 결과를 얻을 수있는 레지스터는 독자의 몫입니다.

리눅스에
.file "abc.c" 
    .text 
    .globl main 
    .type main, @function 
    main: 
    .LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 

    # Load integer 7 (variable a), convert it to double 
    movl $7, -4(%rbp) 
    cvtsi2sd -4(%rbp), %xmm0 

    # Load integer 3, (variable b) convert it to double 
    movl $3, -8(%rbp) 
    cvtsi2sd -8(%rbp), %xmm1 

    # Load integer 2, (variable c) convert it to double 
    movl $2, -12(%rbp) 
    cvtsi2sd -12(%rbp), %xmm2 

    # a/b -> written "div b, a" result goes in a (%xmm0) 
    divsd %xmm1, %xmm0 

    # b * c -> result goes in c (%xmm2) 
    mulsd %xmm0, %xmm2 

    # convert result back to integer 
    cvttsd2si %xmm2, %eax 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
    .LFE0: 
    .size main, .-main 
    .ident "GCC: (Debian 4.6.3-1) 4.6.3" 
    .section .note.GNU-stack,"",@progbits 

, 당신은 단순히 일을 실행하고 (이 과정의 결과로 int로 잘립니다 256립니다) 결과를 보여 컴파일 할 수

gcc abc.s ; ./a.out ; echo $? 

이 응답을 더 완벽하게하기 위해, 당신은 쉽게 (가 FPU의 절단 단계 모드를 설정 귀찮게하지 않았다, 그래서 당신은 5 대신에 그것의 가장 가까운 정수로 절단 4로 얻을 수 있음) 된 FPU를 사용하여 해당 프로그램을 작성할 수 있습니다 :

.file "abc.c" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 

    # Load integer 7 (variable a), convert it to double 
    movl $7, -4(%rbp) 

    # Load integer 3, (variable b) convert it to double 
    movl $3, -8(%rbp) 

    # Load integer 2, (variable c) convert it to double 
    movl $2, -12(%rbp) 

    fild -12(%rbp) 
    fild -8(%rbp) 
    fild -4(%rbp) 

    # a/b -> written "div b, a" result goes in a (%mm0) 
    fdivp %st(0), %st(1) 

    # b * c -> result goes in c (%mm2) 
    fmulp %st(0), %st(1) 

    # convert result back to integer 
    fist -4(%rbp) 
    movl -4(%rbp), %eax 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Debian 4.6.3-1) 4.6.3" 
    .section .note.GNU-stack,"",@progbits 
+0

고마워, 당신은 내게 많은 것들을 명확히했다. 나는 정수 레지스터에서 연산을하고 있었다. \ 어쨌든 64 비트 레지스터 인 것처럼 보이지만 그물에서 검색하면 rbp 레지스터를 사용하는 데 어려움이있다. (그것은 학교 프로젝트이므로 참조를 연결하거나 환경 변수를 수정하지 않고 컴파일해야합니다.) [이 코드] (http://pastebin.com/ArsiDWTx)를 이해하려고 시도했지만 " fmulp % st, % st (1) "어떤 아이디어입니까? 고마워요. – user1526262

+0

[이것은 내가 지금까지 얻는 것입니다] (http : // pastebin.com/KdSpaCEf)하지만 결과가 잘못되었습니다. X = -1 및 K1 = 5를 사용하면 -2.5 또는 -2/-3 대신에 65534가됩니다. (캐스트 용) – user1526262

+0

좋아,이 코드로 해결했습니다. http://pastebin.com/T029wpJd),i는 잘못된 ebp offset을 사용하고있었습니다. kriss에 대한 설명에 감사드립니다. 정말 유용했습니다 !! – user1526262

관련 문제