c - GCC x86 内联汇编中的 (+r) 与 (=r) 约束

标签 c gcc assembly x86 inline-assembly

我在使用 c 语言的一段代码使用内联汇编 block 对数组进行排序时遇到问题。

我的完整代码是这样的:

#include <stdio.h>
#define n 20

int main()
{
    int array[n];
    int i;
    int swapped;

    printf("Enter the elements one by one \n");
    for (i = 0; i < n; i++)
    {
        scanf("%d", &array[i]);
    }

    printf("Input array elements \n");
    for (i = 0; i < n ; i++)
    {
        printf("%d\n", array[i]);
    }

    /*  Bubble sorting begins */   
    do
    {
          swapped = 0;
          for (i = 1; i < n; i++)
          {
/* 
           if (array[i] < array [i-1])
           {
               swapped =1;
               int temp = array [i-1];
               array [i-1] = array [i];
               array[i] = temp;
           }
*/

               //body of the for loop
               //converted to assembly
               __asm__ __volatile__("cmp %0, %1;"
                                    "jge DONE;"
                                    "mov eax, %0;"
                                    "mov %0, %1;"
                                    "mov %1, eax;"
                                    "mov %2, 1;"
                                    "DONE: "
                                    : "+r" (array[i]), "+r" (array[i-1]), "=r" (swapped)
                                    : //no input
                                    : "eax", "cc"
                                    );


          }

    } while (swapped > 0);

    printf("Sorted array is...\n");
    for (i = 0; i < n; i++)
    {
        printf("%d\n", array[i]);
    }

    return 0;
}

由于某种原因, do while 变成了无限循环,但是当我更改 swapped 的修饰符时变量为 "+r" (swapped) 它有效。我查看了这两种情况生成的汇编代码(-save-temp),除了移动 swapped 之外没有注意到任何其他内容。在使用“+r”的情况下变量到寄存器,这是预期的。

为什么我需要使用"+r"

最佳答案

如果您使用=,则意味着它是一个输出,并且必须写入。但是,只有在发生交换时才编写它。编译器将优化您使用的 swapped = 0,因为它假定汇编器 block 将生成一个新值来覆盖它。这意味着,如果没有交换,编译器将很乐意使用它为 %2 选择的寄存器中的任何垃圾作为 swapped 的新值,并且偶然地,产生了无限循环。

下面是一些代码来说明:

swapped = 0;
/* this is the asm block */
{
    /* this is not initialized, because it's declared as output */
    int register_for_operand2;
    if (array[i] < array[i - 1])
    {
        /* body here */
        register_for_operand2 = 1;
    }
    /* the compiler generates this code for the output operand */
    /* this will copy uninitialized value if the above condition was false */
    swapped = register_for_operand2;
}

关于c - GCC x86 内联汇编中的 (+r) 与 (=r) 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26722008/

相关文章:

assembly - 在跳转目标基于动态环境值的情况下如何构建控制流图?

c - 移动结构元素时数组赋值无效

在有向图中创建最短路径的数量

c - arm-linux-gcc 编译器链接,找不到文件

c++ - 在 Fedora 14 上编译 C++ 程序时出现编译错误

assembly - x86 asm 将 16 位值转换为 8 位?

c - 为什么我的所选元素的清除功能无法正常工作?

c - 如何以相反的顺序打印文件中的行

c++ - Eclipse:GNU 工具链 - 使用 g++ 编译的 C 文件,重复 GNU C

linux - 在 Linux 上创建 .SO 文件,而不使用 PIC(位置无关代码)(x86 32 位)