x64装配部

时间:2015-01-13 18:53:52

标签: 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;"
              "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 ;
}

1 个答案:

答案 0 :(得分:3)

您的直接问题可能是因为没有正确阅读输入。

但是你也使用内联asm错误。 gcc inline asm是一个复杂的野兽,确保你真的需要它,然后准备在手册中做一些阅读。

您的代码很糟糕,因为您在不告诉编译器的情况下使用ebx

此外,gcc内联asm的经验法则是,如果你使用mov,你可能做错了。如果需要特定寄存器中的参数,则应使用适当的约束。另一个规则是你几乎不应该使用g约束。

可能的解决方法:

__asm__("cdq; idivl %3" : "=a" (quo), "=&d" (rem) : "a" (arg1), "rm" (arg2) );

当然,您不需要内联asm来执行分组。


更新:看起来问题出在其他地方,即您在代码中使用%edx而未通知编译器。由于编译器不知道,可以自由地为除数分配它,即替换为%3 = %edx。即使编译器正确地将除数放在那里,你做的第一件事就是零%edx,从而破坏了除数。后来你把那个零移到%ebx,并试图除以它,因此是例外。

我的建议使用了一个所谓的早期&#34;早期的&#34;修饰符(&中的=&d)向编译器发出信号,表示代码将在使用输入之前修改有问题的输出,因此编译器不能在那里放置任何输入。请注意,仅将其添加到原始代码仍然不够,因为这仍然会使%eax%ebx同样存在问题。

下次请记住,您可以使用gcc -S要求汇编列表(或者您可以使用objdump -dgdb内部进行反汇编),这样您就可以看到编译器进行了哪些替换