c - x64 assembly 部门

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

最佳答案

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

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

你的代码很糟糕,因为你使用 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 进行反汇编),这样您就可以看到编译器进行了哪些替换。

关于c - x64 assembly 部门,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27929410/

相关文章:

c - 红黑树中从节点A走到节点B的最快方法

gcc - 汇编器模板、asmSymbolicName 和 "error: expected string-literal"

c++ - 是否可以在不使用汇编的情况下告诉 clang 哪些寄存器用于代码的某些部分

c - 如何链接到我自己的 pthread 库

c - 具有不均匀 8 位成员的结构体大小不均匀

c - 缓存中的位屏蔽

c - printf 中的宏变量替换

assembly - 如何从 Cargo 构建中获取 assembly 输出?

c - 汇编函数终止但没有得到结果

linux - 如何在 Linux 64 位上运行 Rebol 脚本