通过C代码中的内联asm行在Windows X86中添加函数

通过C代码中的内联asm行在Windows X86中添加函数,c,assembly,inline-assembly,C,Assembly,Inline Assembly,有人能解释一下我做错了什么吗: int MachineAdder(int a, int b) { int OUT = 0; /* Assign a pointer (&OUT) and write initial data (0) */ __asm ("mov %[dst], %[src]" /* Machine instruction to execute, separated by commas.*/ : [dst] &

有人能解释一下我做错了什么吗:

int MachineAdder(int a, int b)
{
    int OUT = 0;        /* Assign a pointer (&OUT) and write initial data (0) */

    __asm ("mov %[dst], %[src]" /* Machine instruction to execute, separated by commas.*/
      : [dst] "=r" (OUT)
      : [src] "r" (a)
    );
    __asm ("add %[dst], %[src]" /* Machine instruction to execute, separated by commas.*/
      : [dst] "=r" (OUT)
      : [src] "r" (b)
    );

    return OUT; /* Return the value a+b */
}
在我的
main()
函数中,我调用:

printf("0+0 = %d\n", MachineAdder(0,0));
printf("0+1 = %d\n", MachineAdder(0,1));
printf("1+0 = %d\n", MachineAdder(1,0));
printf("1+1 = %d\n", MachineAdder(1,1));
printf("2+1 = %d\n", MachineAdder(2,1));
printf("1+2 = %d\n", MachineAdder(1,2));
在我的输出中,它读作“02024”(而我期望的是“011233”)

谢谢!谷歌搜索的答案很混乱,因为一些机器指令似乎是前后颠倒的,而其他人则谈论寄存器,但我不知道哪个寄存器是哪个寄存器,或者如何使用它们

编辑:找到工作解决方案。有两个错误:src和dst是错误的,我从来没有听说过用于inout参数的“+r”字符串。以下是固定版本:

int MachineAdder(int a, int b)
{
    int OUT = 0;        /* Assign a pointer (&OUT) and write initial data (0) */

    __asm ("mov %[src], %[dst]" /* Machine instruction to execute, separated by commas.*/
      : [dst] "=r" (OUT)
      : [src] "r" (a)
    );
    __asm ("add %[src], %[dst]" /* Machine instruction to execute, separated by commas.*/
      : [dst] "+r" (OUT)
      : [src] "r" (b)
    );

    return OUT; /* Return the value a+b */
}

谢谢大家

这是因为,在输出操作数中,
=
标记不能保证该位置具有现有值,而
+
标记可以

说:

输出约束必须以“=”(覆盖现有值的变量)或“+”(读写时)开头。使用“=”时,除非操作数绑定到输入,否则不要假定该位置包含asm条目上的现有值


在第二个例子中,您需要说明dst是In和out。另外,从后到前的顺序也是一个恼人的GCC问题。您的第二个块仅将
OUT
指定为输出,但它当然会读取值,因此您应该将其指定为读写。使用
+
约束。此外,如果使用at&t汇编(默认)进行编译,则需要交换操作数顺序。在英特尔模式下也可以(
-masm=intel
)也许您希望这两条指令都在同一个asm语句中,因此
OUT
是只写指令(从编译器的角度来看)。写一个asm语句仅仅是一个
mov
,基本上是没有意义的;您可以使用输入匹配约束(如
“0”(a)
)执行相同的操作。另外,
int OUT=0的注释没有什么意义;这里不涉及地址。另外,如果您不知道如何在普通asm中使用寄存器,那么在尝试学习GNU C内联asm之前,您应该先学习这一点。您必须了解asm和C,以及编译器的想法,因为您需要能够将asm准确地描述为一个黑盒。否则你会有这样未定义的行为。如果您无法通过查看编译器生成的asm来调试它,并试图找出它认为您在告诉它什么(例如,
gcc-S
,或者),那么您就陷入了相当深的困境。