x86 add和addl操作数是否添加错误?

时间:2016-03-10 17:24:26

标签: c assembly x86 gdb xv6

我使用的是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之类的值。但是,在add命令之后它打印2.如果我使用addl命令,它也会打印2.我使用的是xv6的最新稳定版本。所以,我真的不怀疑它是问题所在。有没有其他方法可以在内联汇编中添加两个数字?

基本上我需要增加16(%esp)4。

编辑代码:

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

1 个答案:

答案 0 :(得分: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页面上的文档会警告某些函数如何破坏各种寄存器。 printf()作为C函数可以很好地使用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 manage page有更多详情。