c - x86 add 和 addl 操作数相加错误?

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

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

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

<小时/>

将代码编辑为:

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

最佳答案

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有更多详细信息。

关于c - x86 add 和 addl 操作数相加错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35923200/

相关文章:

eclipse - 设置反汇编 View 颜色

c++ - 使用较少位的无符号 qword(64 位)的值范围?

debugging - mov eax, 大 fs :30h

c++ - Linux 上的 memcpy 性能不佳

c - 如何在 C 中实现 "private/restricted"函数?

assembly - 如何在 8086 中声明局部变量?

visual-c++ - _umul128 在 Windows 32 位上

.net - .NET 上 x86/x64/ia64 内存模型之间的差异

c - 多个 execlp 不工作

c - 使用 imagemagick API 截图