我在装配时遇到以下行为的麻烦。 我正在组装IA32。假设-4(%ebp)= x和-8(%ebp)= y并且我已经从用户获得它们(两个32位长)。 这是代码:
format1: .string "Multiply : %u * %u = %llu\n"
format2: .string "Divide : %u / %u = %u\n"
# operation multiply
movl -4(%ebp), %eax
mull -8(%ebp)
pushl %edx
pushl %eax
pushl -8(%ebp)
pushl -4(%ebp)
pushl $format1
call printf
# operation divide
movl -4(%ebp), %eax
divl -8(%ebp)
pushl %eax
pushl -8(%ebp)
pushl -4(%ebp)
pushl $format2
call printf
乘法结果在%llu中的原因是因为我希望能够将2个长数相乘并打印结果,即使它达到64个字节。 而且在%edx中,mull命令保存了64字节结果的“其他32个字节”,因此我需要将它推送到堆栈以及printf。 例如我想要这个输出:
Multiply : 4000000000 * 2 = 16000000000
另外,我希望3和4的除法运算返回X.YZ结果。 (尾数不超过2个数字,没有四舍五入) e.g。
Divide : 3 / 4 = 0.75
表示19和1000:
Divide : 19 / 1000 = 0.01
和8和2:
Divide : 8 / 2 = 4.00
我真的尝试过很多但没有成功。 非常感谢! :)
答案 0 :(得分:0)
mull
用于整数乘法,divl
用于整数除法。对于浮点数,您可以使用浮点指令fmul
和fdiv
。
另一种方法是像Jerry Coffin在他的评论中建议的那样,在每个整数乘法之前缩放因子,例如。 100,并将得到的整数视为100 * 100 = 10000倍太大。
答案 1 :(得分:0)
乘法should work as-is。 如何划分得到浮点结果我已经answered in your other question。 如果您只需要将它们打印成两位数,则可以使用相应的格式字符串。
更新:显示截断为两位数的工作代码:
.comm x,4,4
.comm y,4,4
.section .rodata
format1: .string "Div : %d / %d = %.2f\n"
format2: .string "Mod : %d %% %d = %d\n"
format3: .string "Multiply : %u * %u = %llu\n"
format4: .string "%d %d"
const100: .int 100
.text
.globl main
.type main, @function
main:
subl $32, %esp # allocate space, preserve alignment
movl $format4, (%esp)
movl $x, 4(%esp)
movl $y, 8(%esp)
call scanf
# operation divide
fildl x
fimul const100
fidivl y
# truncate to integer
# use this if current FPU rounding mode
# is known to be truncate
# frndint
# otherwise use this
fnclex
fnstcw (%esp) # save a copy to modify
fnstcw 2(%esp) # and a copy to preserve
orw $0x0c00, (%esp) # rounding mode = truncate
fldcw (%esp) # activate
frndint # do the truncate
fldcw 2(%esp) # restore original
# end of truncate code
fidiv const100
fstpl 12(%esp) # x / y
movl $format1, (%esp)
movl x, %eax
movl %eax, 4(%esp)
movl y, %eax
movl %eax, 8(%esp)
call printf
# operation modulo
movl x, %eax
cltd
idivl y
movl $format2, (%esp)
movl x, %eax
movl %eax, 4(%esp)
movl y, %eax
movl %eax, 8(%esp)
movl %edx, 12(%esp)
call printf
# operation multiply
movl x, %eax
mull y
movl $format3, (%esp)
movl x, %ecx
movl %ecx, 4(%esp)
movl y, %ecx
movl %ecx, 8(%esp)
movl %eax, 12(%esp)
movl %edx, 16(%esp)
call printf
addl $32, %esp
xor %eax, %eax
ret
答案 2 :(得分:0)
您可以找到一些有用的示例here
以下是如何将两个 32位数与 64 位结果相乘[Linux,GCC]的示例:
#include <stdio.h>
char *fr = "MUL %u * %u = %llu\n";
int main()
{
__asm__ (
"subl $0x14, %esp\n\t"
"movl $10, %eax\n\t"
"movl %eax, 0x4(%esp)\n\t"
"movl $100, %ebx\n\t"
// Multimpy two 32bit values and save 64bit result in edx:eax
"mull %ebx\n\t"
// Call printf
"movl fr, %esi\n\t"
"movl %esi, (%esp)\n\t"
"movl %ebx, 0x8(%esp)\n\t"
"movl %eax, 0xC(%esp)\n\t"
"movl %edx, 0x10(%esp)\n\t"
"call printf\n\t"
"addl $0x14, %esp\n\t");
return 0;
}
gcc -m32 ./ttt.c; ./a.out
MUL 10 * 100 = 1000
对于除法,您需要将数据转换为浮点值并使用fdiv
指令。
PS。 push
更改%esp
,因此您必须对恢复堆栈指针执行pop
相同的次数。否则你会得到未定义的行为。