汇编程序浮点运算

时间:2012-07-15 00:05:01

标签: linux assembly floating-point

我在Linux下使用带有AT& t语法的汇编程序。 我需要划分和乘以3个数字(a,b,c)。 操作可能是a / b * c,我尝试过使用idiv和imul istruction,但当然这些都适用于整数,所以我得到的结果总是不准确。 我也尝试使用fidiv和fimul istruction在计算中使用float但是我得到了完全错误的结果。所以我可能正在错误的寄存器上进行操作。 有人可以给我一个关于如何在AT& T下使用fidiv / fimul的例子吗?哪些寄存器可以使用?

提前致谢。

1 个答案:

答案 0 :(得分:0)

由于AT& T是gas(GNU Assembler)的输出语法,所以你不应该想太久。只需在C中写入它并使用-S开关生成汇编器输出。

例:

如果在源文件abc.c中键入以下程序

main(){
    int a = 7;
    int b = 3;
    int c = 2;
    return (double)a/(double)b*(double)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),执行除法(警告:你按{{1}编写a/b结果进入第二个寄存器)。等等。显而易见的是编译器不打算使用旧的FPU 8087指令集,因为现在有更简单的方法来执行浮点计算而无需使用FPU堆栈。由于问题没有在目标系统上说什么,我将按照我的编译器来执行此类计算。

由于某些人可能仍不清楚(我的回答被低估),我对gcc输出进行了一些重新排序(以避免无用的移动)并添加注释。唯一可能的陷阱是div的参数顺序。在哪个寄存器中放置数据并获得结果取决于读者。

div b, a

在Linux上,您可以编译执行并显示结果(截断为int并截断为256,因为它是处理结果),只需执行以下操作:

    .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

为了使答案更加完整,你可以使用旧的FPU轻松编写一个等效的程序(它没有设置FPU的截断模式,所以你可以得到5而不是4它截断到最接近的整数):

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