如何用gcc优化“不关心”的说法?

时间:2017-03-11 00:58:31

标签: c gcc optimization

有时函数不使用参数(可能是因为另一个“flags”参数没有启用特定功能)。

但是,您必须指定一些内容,因此通常只需添加0。但是如果你这样做,并且函数是外部的,gcc将发出代码以“确保”该参数设置为0

有没有办法告诉gcc一个函数的特定参数无关紧要,它可以单独留下恰好在参数寄存器中的任何值?

更新:有人询问了XY问题。这个问题背后的背景是我想在x86_64中实现一个varargs函数而不使用编译器varargs支持。当参数在堆栈上时这是最简单的,所以我声明我的函数首先采用5或6个伪参数,以便最后的非vararg参数和所有vararg参数最终在堆栈上。这很好,除了它显然不是最优的 - 当查看汇编代码时,很明显gcc正在调用者中将所有这些参数寄存器初始化为零。

1 个答案:

答案 0 :(得分:2)

请不要认真对待以下回答。这个问题要求你进行黑客攻击。

GCC将有效地将未初始化变量的价值视为“不关心”#34;所以我们可以尝试利用这个:

int foo(int x, int y);

int bar_1(int y) {
  int tmp = tmp;  // Suppress uninitialized warnings
  return foo(tmp, y);
}

不幸的是,我的GCC版本仍然懦弱地将tmp初始化为零但你的版本可能更具侵略性:

bar_1:
.LFB0:
  .cfi_startproc
  movl  %edi, %esi
  xorl  %edi, %edi
  jmp   foo
  .cfi_endproc

另一种选择是(ab)使用内联汇编来假设GCC认为tmp已定义(事实上它不是):

int bar_2(int y) {
  int tmp;
  asm("" : "=r"(tmp));
  return foo(tmp, y);
}

通过此GCC设法摆脱参数初始化:

bar_2:
.LFB1:
  .cfi_startproc
  movl  %edi, %esi
  jmp   foo
  .cfi_endproc

请注意,内联asm必须紧接在函数调用之前,否则GCC会认为它必须保留会损害寄存器分配的输出值。