我在 linux 下使用带有 AT&t 语法的汇编程序。我需要除以和乘以 3 个数字(a,b,c)。该操作可能是 a/b*c,我尝试过使用 idiv 和 imul 指令,但当然这些适用于整数,所以我从它们那里得到完全不准确的结果。我还尝试使用 fidiv 和 fimul istruction 在计算中使用浮点数,但我得到了完全错误的结果。所以可能我在错误的寄存器上进行操作。有人可以给我一个关于如何在 AT&T 下使用 fidiv/fimul 的例子吗?这些指令使用哪些寄存器?
提前致谢。
我在 linux 下使用带有 AT&t 语法的汇编程序。我需要除以和乘以 3 个数字(a,b,c)。该操作可能是 a/b*c,我尝试过使用 idiv 和 imul 指令,但当然这些适用于整数,所以我从它们那里得到完全不准确的结果。我还尝试使用 fidiv 和 fimul istruction 在计算中使用浮点数,但我得到了完全错误的结果。所以可能我在错误的寄存器上进行操作。有人可以给我一个关于如何在 AT&T 下使用 fidiv/fimul 的例子吗?这些指令使用哪些寄存器?
提前致谢。
由于 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 保留空间,在其中存储常量值,将它们转换为双精度(cvtsi2sd),执行除法(注意:您a/b
按顺序写入div b, a
,结果进入第二个寄存器)。等等。显而易见的是,编译器不会费心使用旧的 FPU 8087 指令集,因为现在有更简单的方法来执行浮点计算,而无需使用 FPU 堆栈。由于问题没有在目标系统上说明任何内容,因此我将按照编译器的方式执行此类计算。
由于某些人可能仍不清楚(我的回答被否决),我对 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
在 Linux 上,您可以编译执行并显示结果(截断为 int 并截断为 256,因为它是进程结果)只需执行以下操作:
gcc abc.s ; ./a.out ; echo $?
为了使答案更完整,您可以使用旧的 FPU 轻松编写等效程序(它没有设置 FPU 的截断模式,因此您可能会得到 5 而不是 4 它截断到最接近的整数):
.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