x64 汇编部门
x64 Assembly Division
当我在 Ubuntu 64 位中执行以下汇编代码时,出现浮点异常(核心已转储)错误:
#include <stdio.h>
int main() {
int arg1, arg2, quo, rem ;
printf( "Enter two integer numbers : " );
scanf( "%d%d", &arg1, &arg2 );
__asm__ ( "movl [=10=]x0, %%edx;"
"movl %2, %%eax;"
"movl %3, %%ebx;"
"idivl %%ebx;" : "=a" (quo), "=d" (rem) : "g" (arg1), "g" (arg2) );
printf( "%d / %d = %d\n", arg1, arg2, quo );
printf( "%d %% %d = %d\n", arg1, arg2, rem );
return 0 ;
}
您眼前的问题可能是由于未正确读取输入造成的。
不过你也用inline asm错了。 gcc inline asm 是一个复杂的野兽,确保你真的需要它,然后准备好阅读手册。
你的代码很糟糕,因为你使用了 ebx
而没有告诉编译器。
此外,gcc 内联汇编的一个经验法则是,如果您曾经使用过 mov
,您可能做错了。如果你想要特定寄存器中的参数,你应该使用适当的约束。另一个规则是你几乎不应该使用 g
约束。
可能的修复:
__asm__("cdq; idivl %3" : "=a" (quo), "=&d" (rem) : "a" (arg1), "rm" (arg2) );
当然你不需要内联汇编来执行除法。
更新:看起来问题毕竟出在别处,即您在代码中使用了 %edx
而没有通知编译器。由于编译器不知道,它可以自由分配除数,即替换为 %3 = %edx
。即使编译器正确地将除数放在那里,您做的第一件事就是零 %edx
,从而破坏了除数。后来你把那个零移到 %ebx
,并试图除以它,因此出现异常。
我的建议使用了所谓的 "earlyclobber" 修饰符(=&d
中的 &
),它向编译器发出信号,表明代码将在用完之前修改相关输出输入,因此编译器不能在那里放置任何输入。请注意,仅将其添加到您的原始代码中仍然不够,因为这仍然会留下 %eax
和 %ebx
类似的问题。
下次,请记住您可以使用 gcc -S
(或者您可以使用 objdump -d
或在 gdb
内反汇编),这样您就可以看到哪些替换编译器制作。
当我在 Ubuntu 64 位中执行以下汇编代码时,出现浮点异常(核心已转储)错误:
#include <stdio.h>
int main() {
int arg1, arg2, quo, rem ;
printf( "Enter two integer numbers : " );
scanf( "%d%d", &arg1, &arg2 );
__asm__ ( "movl [=10=]x0, %%edx;"
"movl %2, %%eax;"
"movl %3, %%ebx;"
"idivl %%ebx;" : "=a" (quo), "=d" (rem) : "g" (arg1), "g" (arg2) );
printf( "%d / %d = %d\n", arg1, arg2, quo );
printf( "%d %% %d = %d\n", arg1, arg2, rem );
return 0 ;
}
您眼前的问题可能是由于未正确读取输入造成的。
不过你也用inline asm错了。 gcc inline asm 是一个复杂的野兽,确保你真的需要它,然后准备好阅读手册。
你的代码很糟糕,因为你使用了 ebx
而没有告诉编译器。
此外,gcc 内联汇编的一个经验法则是,如果您曾经使用过 mov
,您可能做错了。如果你想要特定寄存器中的参数,你应该使用适当的约束。另一个规则是你几乎不应该使用 g
约束。
可能的修复:
__asm__("cdq; idivl %3" : "=a" (quo), "=&d" (rem) : "a" (arg1), "rm" (arg2) );
当然你不需要内联汇编来执行除法。
更新:看起来问题毕竟出在别处,即您在代码中使用了 %edx
而没有通知编译器。由于编译器不知道,它可以自由分配除数,即替换为 %3 = %edx
。即使编译器正确地将除数放在那里,您做的第一件事就是零 %edx
,从而破坏了除数。后来你把那个零移到 %ebx
,并试图除以它,因此出现异常。
我的建议使用了所谓的 "earlyclobber" 修饰符(=&d
中的 &
),它向编译器发出信号,表明代码将在用完之前修改相关输出输入,因此编译器不能在那里放置任何输入。请注意,仅将其添加到您的原始代码中仍然不够,因为这仍然会留下 %eax
和 %ebx
类似的问题。
下次,请记住您可以使用 gcc -S
(或者您可以使用 objdump -d
或在 gdb
内反汇编),这样您就可以看到哪些替换编译器制作。