简体   繁体   English

GCC内联汇编的副作用

[英]GCC Inline Assembly side effects

Could someone explain me (in other words) the following section from GCC doc : 有人可以解释我(换句话说)GCC doc的以下部分:

Here is a fictitious sum of squares instruction, that takes two pointers to floating point values in memory and produces a floating point register output. 这是一个虚构的平方和指令,它在存储器中有两个指向浮点值的指针,并产生一个浮点寄存器输出。 Notice that x, and y both appear twice in the asm parameters, once to specify memory accessed, and once to specify a base register used by the asm. 请注意,x和y都在asm参数中出现两次,一次指定访问的内存,一次指定asm使用的基本寄存器。 You won't normally be wasting a register by doing this as GCC can use the same register for both purposes. 这样做通常不会浪费寄存器,因为GCC可以将相同的寄存器用于这两个目的。 However, it would be foolish to use both %1 and %3 for x in this asm and expect them to be the same. 但是,在这个asm中同时使用%1和%3作为x并且期望它们是相同的是愚蠢的。 In fact, %3 may well not be a register. 实际上,%3可能不是注册。 It might be a symbolic memory reference to the object pointed to by x. 它可能是x指向的对象的符号内存引用。

asm ("sumsq %0, %1, %2"
 : "+f" (result)
 : "r" (x), "r" (y), "m" (*x), "m" (*y));

Here is a fictitious *z++ = *x++ * *y++ instruction. 这是一个虚构的* z ++ = * x ++ * * y ++指令。 Notice that the x, y and z pointer registers must be specified as input/output because the asm modifies them. 请注意,必须将x,y和z指针寄存器指定为输入/输出,因为asm会修改它们。

asm ("vecmul %0, %1, %2"
 : "+r" (z), "+r" (x), "+r" (y), "=m" (*z)
 : "m" (*x), "m" (*y));

In the first example what is the point for listing *x and *y in the input operands? 在第一个例子中,在输入操作数中列出*x*y是什么意思? The same doc states: 同样的文件说明:

In particular, there is no way to specify that input operands get modified without also specifying them as output operands. 特别是,没有办法指定输入操作数被修改而不将它们指定为输出操作数。

In the second example why use the input operands section at all? 在第二个例子中为什么要使用输入操作数部分? None of its operands is used in the assembly statement anyway. 无论如何,它的所有操作数都不用于汇编语句中。

And as a bonus, how could one change the following example from this SO post so there was no need for the volatile keyword? 作为奖励,如何从这个 SO帖子中更改以下示例,以便不需要volatile关键字?

void swap_2 (int *a, int *b)
{
int tmp0, tmp1;

__asm__ volatile (
    "movl (%0), %k2\n\t" /* %2 (tmp0) = (*a) */
    "movl (%1), %k3\n\t" /* %3 (tmp1) = (*b) */
    "cmpl %k3, %k2\n\t"
    "jle  %=f\n\t"       /* if (%2 <= %3) (at&t!) */
    "movl %k3, (%0)\n\t"
    "movl %k2, (%1)\n\t"
    "%=:\n\t"

    : "+r" (a), "+r" (b), "=r" (tmp0), "=r" (tmp1) :
    : "memory" /* "cc" */ );
}

Thanks in advance. 提前致谢。 I'm struggling with this for two days now. 我现在已经挣扎了两天了。

In the first example, *x and *y have to be listed as input operands so that GCC knows that the outcome of the instruction depends on them. 在第一个例子中,必须将*x*y列为输入操作数,以便GCC知道指令的结果取决于它们。 Otherwise, GCC could move stores to *x and *y past the inline assembly fragment, which would then access uninitialized memory. 否则,GCC可以通过内联汇编片段将商店移动到*x*y ,然后访问未初始化的内存。 This can be seen by compiling this example: 通过编译此示例可以看出这一点:

double
f (void)
{
  double result;
  double a = 5;
  double b = 7;
  double *x = &a;
  double *y = &b;
  asm ("sumsq %0, %1, %2"
       : "+X" (result)
       : "r" (x), "r" (y) /*, "m" (*x), "m" (*y)*/);
  return result;
}

Which results in: 结果如下:

f:
    leaq    -16(%rsp), %rax
    leaq    -8(%rsp), %rdx
    pxor    %xmm0, %xmm0
#APP
# 8 "t.c" 1
    sumsq %xmm0, %rax, %rdx
# 0 "" 2
#NO_APP
    ret

The two leaq instructions just set up the registers to point into the uninitialized red zone on the stack. 两条leaq指令只是将寄存器设置为指向堆栈中未初始化的红色区域。 The assignments are gone. 作业消失了。

The same is true for the second example as well. 对于第二个例子也是如此。

I think you can use the same trick to eliminate the volatile . 我认为你可以使用相同的技巧来消除volatile But I think it is not actually necessary here because there already is a "memory" clobber, which tells GCC that memory is read or written from inline assembly. 但我认为这里实际上并不是必需的,因为已经有一个"memory"破坏者,告诉GCC内存是从内联汇编中读取或写入的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM