我正在尝试使用GCC的内联汇编程序熟悉x86程序集。 我正在尝试添加两个数字( ab )并将结果存储在c 我有四个略有不同的尝试,其中三个有效; 最后一个不会产生预期的结果。

前两个示例使用中间寄存器,这些都可以正常工作。 第三个和第四个示例尝试直接添加两个值而不使用中间寄存器,但结果会根据优化级别和添加输入值的顺序而有所不同。 我错了什么?

环境是:

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

首先,变量声明如下:

int a = 4;
int b = 7;
int c;

例1:

asm("   movl    %1,%%eax;"
    "   addl    %2,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

例2:

asm("   movl    %2,%%eax;"
    "   addl    %1,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11

例3:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

例4:

// this one appears to calculate a+a instead of a+b
asm("   movl    %1,%0;"
    "   addl    %2,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=8
// output with -O3: a=4, b=7, c=11

解决了。 Matthew Slattery的回答是正确的。 以前,它试图为bc重用eax

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %eax
addl    %eax, %eax

有了Matthew建议的修复,它现在使用ecx分别保存c

movl    -4(%rbp), %edx
movl    -8(%rbp), %eax
movl    %edx, %ecx
addl    %eax, %ecx

===============>>#1 票数:8 已采纳

默认情况下, gcc将假定在更新输出操作数之前,内联asm块将使用输入操作数完成。 这意味着输入和输出都可以分配给同一个寄存器。

但是,在您的示例3和4中并不一定如此。

例如在例3中:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
   );

...您已经更新c%0阅读前) a%1 )。 如果gcc碰巧将同一个寄存器分配给%0%1 ,那么它将计算c = b; c += c c = b; c += c ,因此将完全按照您观察到的方式失败:

printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14

您可以通过告诉gcc在输入消耗之前使用输出操作数来修复它,方法是在操作数中添加“ & ”修饰符,如下所示:

asm("   movl    %2,%0;"
    "   addl    %1,%0;"
    : "=&r" (c)
    : "r" (a), "r" (b)
   );

(请参阅gcc文档中的“约束修饰符字符” 。)

===============>>#2 票数:0

海,我没有看到那里的问题,它在这里编译和工作正常。 但是,一个小提示:我很快就对未命名的变量/寄存器感到困惑,所以我决定使用命名的变量/寄存器。 你可以添加的东西,例如这样实现:

static inline void atomicAdd32(volInt32 *dest, int32_t source) {
// IMPLEMENTS:  add m32, r32
__asm__ __volatile__(
        "lock; addl %[in], %[out]"
        : [out] "+m"(*dest)
        : [in] "ir"(source)//, "[out]" "m"(*dest)
        );
return;
  }

(你现在可以忽略原子/锁定事物),这清楚地说明了会发生什么:

1)哪些寄存器是可写的,可读的或两者兼而有之

2)使用的是什么(存储器,寄存器),这在性能和时钟周期方面很重要,因为寄存器操作比访问存储器的操作更快。

干杯,G。

PS:你检查过你的编译器是否重新排列了代码吗?

  ask by Graham Borland translate from so

未解决问题?本站智能推荐:

1回复

如何编写一个简短的内联gnu扩展程序集块来交换两个整数变量的值?

为了娱乐,我正在学习针对32位Linux目标使用针对x86的AT&T语法的gnu扩展程序集。 我刚刚花了最后三个小时来编写两个可能的解决方案,以应对交换两个整数变量a和b的值的挑战,但是我的解决方案都不能完全解决我的问题。 首先,让我们更详细地了解我的TODO障碍: 阅读此HOWTO
3回复

如何从内联汇编中的两个寄存器中检索值的高位和低位部分?

我目前正在开发一款可以从硬盘启动扇区运行的小游戏,只是为了做一些有趣的事情。 这意味着我的程序以16位实模式运行,并且我将编译器标志设置为发出纯i386代码。 我正在用C ++编写游戏,但是我确实需要大量内联汇编才能通过中断调用与BIOS通讯。 其中一些调用返回一个32位整数,但存储在两个
2回复

内联C汇编中的数字比较

我正在尝试使用c进行内联汇编,并且之前从未进行过任何汇编编程,因此,我尝试将必须转换的随机代码转换为汇编。 我在下面的代码中遇到了问题,如果a低于0x20(32)或高于0x7e(126),我希望它返回0x20(32)。 (那是无法打印的字符)但是,它也会将这些数字之间的字符转换为0x20(3
2回复

Visual C ++内联汇编程序的两个偏移量之差

我正在将代码块从MASM移植到C内联汇编程序(x86,Windows,MS VC)。Foolowing并不是真正的代码,只是出于欺骗的目的。 假设我有一些数据定义为静态数组,甚至是两个标签之间的代码块,我需要获取它的大小。 这样的代码可以在MASM中像超级按钮一样工作,但是在CI中会收
1回复

用汇编指令在C中递增数字

这个问题已经在这里有了答案: 如何访问C变量以进行内联汇编操作? (2个答案) 为什么不能在GNU C基本内联
1回复

使用C ++中的内联汇编求和缓冲区中的数字

我是汇编语言编程的新手,面临着一个可能对有经验的汇编语言用户显而易见的问题。 我有一个100字节的缓冲区,我需要找到n = 1至5的每个第n个字节的总和,并将结果存储在5个整数的数组中。 我需要在我的C ++代码中使用内联汇编来执行此操作。 我写了以下代码: 因此,最后,resul
1回复

我的汇编函数两次推送数据

所以我一直在调试它,并做了一个功能,可以将数据包发送到服务器 这是功能 这里的问题首先是当我调试我的应用程序时,它表明该函数具有3个参数而不是2个参数(Buffer,Length,Length),并且当我使用它时,它实际上第一次将长度推入两倍,第二次将其推入正确的长度。一些奇怪的负
3回复

使用内联汇编交换两个整数变量

(编者注:这是一个调试问题,涉及该尝试实现的问题(几乎所有问题),因此不是如何编写一个简短的内联gnu扩展程序集交换两个整数变量的值的复制品吗?问答和https://stackoverflow.com/tags/inline-assembly/info(如果您想使用示例)。 我正在尝试使
2回复

使用AVX异或两个zmm(512位)寄存器

我想用zmm1来位xor xor zmm0。 我在互联网上阅读并尝试过: 但是编译器给出“错误:'vpxorq'的操作数不匹配”。 我究竟做错了什么?
1回复

如何在(GNU)C中编写代理函数来连接两个不同的调用约定?

我正在编写一个解释器/编译器混合体,其中调用约定在CPU堆栈上传递参数。 函数只是在运行时可能生成的指向机器代码的指针(例如C函数指针)。 我需要一个代理功能来与自定义调用约定对接。 我想用C编写尽可能多的函数 ,尽管某些部分必须用汇编语言编写。 我将将此代理功能称为apply 。