-1

我使用 xv6,它在 x86 机器上实现了原始 UNIX。我在 C 程序中编写了非常简单的内联汇编:

register int ecx asm ("%ecx");
printf(1, "%d\n", ecx);
__asm__("movl 16(%esp), %ecx\t\n");
printf(1, "%d\n", ecx);
__asm__("add $0, %ecx\t\n");
printf(1, "%d\n", ecx);
__asm__("movl %ecx, 16(%esp)\t\n");

我通常会得到第二个打印语句打印的 434 之类的值。但是,在添加命令之后它会打印 2。如果我改用 addl 命令,它也会打印 2。我使用的是 xv6 的最新稳定版本。所以,我真的不怀疑这是问题所在。有没有其他方法可以在内联汇编中添加两个数字?

本质上,我需要将 16(%esp) 增加 4。


将代码编辑为:

__asm__("addl $8, 16(%esp)\t\n");

4

1 回答 1

1

1)在您的示例中,您没有将 ecx 增加 4,而是将其增加 0。

__asm__("addl $4, %ecx");

2)您应该能够将多个命令链接到一个 asm 调用中

__asm__("movl 16(%esp), %ecx\n\t"
        "addl $4, %ecx\n\t"
        "movl %ecx, 16(%esp)");

3) register 关键字是一个提示,编译器可能会决定将您的变量放在它想要的任何位置。阅读 GCC 页面上的文档也会警告某些函数如何破坏各种寄存器。作为 C 函数的 printf() 可以很好地使用 ecx 寄存器而不保留其值。它可以保存它,但它可能不会;编译器可能会将该寄存器用于该调用中的各种优化。它是 80x86 上的通用寄存器,经常用于各种参数传递和返回值。

未经测试的更正:

int reg; // By leaving this out, we give GCC the ability to pick the best available register.

/*
 * volatile indicates to GCC that this inline assembly might do odd side
 * effects and should disable any optimizations around it.
 */
asm volatile ("movl 16(%esp), %0\n\t"
              "addl $4, %0\n\t"
              "movl %0, 16(%esp)" 
              : "r" (reg)); // The "r" indicates we want to use a register

printf("Result: %d\n", reg);

GCC 管理页面有更多详细信息。

于 2016-03-10T17:51:32.373 回答