C x64装配部

C x64装配部,c,assembly,x86-64,C,Assembly,X86 64,当我在Ubuntu 64位中执行以下汇编代码时,我得到一个浮点异常核心转储错误: #include <stdio.h> int main() { int arg1, arg2, quo, rem ; printf( "Enter two integer numbers : " ); scanf( "%d%d", &arg1, &arg2 ); __asm__ ( "movl $0x0, %%edx;" "m

当我在Ubuntu 64位中执行以下汇编代码时,我得到一个浮点异常核心转储错误:

#include <stdio.h>

int main() {  
int arg1, arg2, quo, rem ;

    printf( "Enter two integer numbers : " );
    scanf( "%d%d", &arg1, &arg2 );

    __asm__ ( "movl $0x0, %%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 ;
}

您当前的问题可能是由于没有正确读取输入造成的

但是,使用内联asm也是错误的。gcc内联asm是一个复杂的野兽,请确保您确实需要它,然后准备阅读手册

您的代码是错误的,因为您使用ebx时没有告诉编译器

此外,gcc内联asm的一条经验法则是,如果您曾经使用过mov,那么您可能是做错了。如果希望参数位于特定寄存器中,则应使用适当的约束。另一条规则是您几乎不应该使用g约束

可能的解决方案:

__asm__("cdq; idivl %3" : "=a" (quo), "=&d" (rem) : "a" (arg1), "rm" (arg2) );
当然,执行除法不需要内联asm

更新:看起来问题毕竟出在其他地方,即您在代码中使用了%edx而没有通知编译器。因为编译器不知道,所以可以自由地将其分配给除数,即替换为%3=%edx。即使编译器正确地将除数放在那里,您做的第一件事是0%edx,从而销毁除数。后来,您将该零移动到%ebx中,并尝试除以它,因此出现了异常

我的建议使用了一个所谓的earlyclobber修饰符&in=&d,它向编译器发出信号,表示代码将在使用完输入之前修改有问题的输出,因此编译器不能在那里放置任何输入。请注意,仅将其添加到原始代码中仍然不够,因为这仍然会导致%eax和%ebx出现类似的问题


下一次,请记住,您可以使用gcc-S请求程序集列表,也可以使用objdump-d或在gdb内部进行反汇编,以便查看编译器进行了哪些替换。

然后您可能被0除。如果您的scanf是错误的,并且在我看来是错误的,那么arg2可能是0。scanf返回的已转换参数数是多少?少于2个?谢谢你的回答。事实上,我是这个趋势的初学者,我需要的是在这个领域的一个非常简单的水平。通过在我的代码中用&d替换d,问题已经解决了,但我不明白为什么。请解释一下。&表示一个早期的clobber输出操作数。它基本上阻止编译器为输入分配相同的寄存器。没有它,编译器就可以自由地将其中一个参数加载到edx中,然后将其归零并除以。