0

次の C99 コードを検討してください。

#include <stdio.h>
#include <stdint.h>

struct baz { uint64_t x, y; };

uint64_t foo(uint64_t a, uint64_t b, struct baz c)
{
    return a + b + c.x + c.y;
}

void bar(uint64_t a, uint64_t b, struct baz c)
{
    printf("%lu\n", a);
}

でコンパイルした場合、私が期待する動作は、gcc -O3との両方にcレジスタで渡され、 でレジスタを使用してアクセスされ、 で完全に無視されることです。GCC は、 に対してこれを行うコードを生成します。ただし、 では、レジスタからスタックにコピーされ、すぐに無視されます。foobarfoobarfoobarc

    .file   "pbv.c"
    .text
    .p2align 4,,15
.globl foo
    .type   foo, @function
foo:
.LFB22:
    .cfi_startproc
    leaq    (%rcx,%rdx), %rdx
    leaq    (%rdx,%rdi), %rdi
    leaq    (%rdi,%rsi), %rax
    ret
    .cfi_endproc
.LFE22:
    .size   foo, .-foo
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "%lu\n"
    .text
    .p2align 4,,15
.globl bar
    .type   bar, @function
bar:
.LFB23:
    .cfi_startproc
    movq    %rdx, -24(%rsp)
    movl    $.LC0, %esi
    movq    %rdi, %rdx
    xorl    %eax, %eax
    movl    $1, %edi
    movq    %rcx, -16(%rsp)
    jmp __printf_chk
    .cfi_endproc
.LFE23:
    .size   bar, .-bar
    .ident  "GCC: (Ubuntu/Linaro 4.4.6-11ubuntu2) 4.4.6"
    .section    .note.GNU-stack,"",@progbits

( and はandに渡され、 andは andにa渡さbれることに注意してください。)%rsi%rdic%rcx%rdx

これについて推測できる唯一の理由は、ある種の ABI 要件 (たとえば、longjmp との対話) です。-fGCC の最適化 ( ) オプションも、この動作を阻害する GCC 固有の注釈も見つかりません。で注釈cを付けregisterても役に立ちません。

これは、さまざまなターゲットでも発生します。(特に、TileGX ではfoo、スタックに割り当てられたスペースと割り当て解除されたスペースがありますが、そこには何も格納されません。) GCC 4.4.6 と 4.6.1 の両方をテストしました。

これは予想される動作ですか、それとも GCC のバグですか? いずれにせよ、それを回避する方法はありますか (参照渡しを使用するbarか、リーフになることができることを確認する以外に)?

4

1 に答える 1

0

この欠点はバグ44194で言及されているものと同じであり、そのパッチは GCC の最新バージョン (4.7.2) に存在します。

原因は、(または任意の関数) への呼び出しがprintf、スタックベースのローカルを含む、メモリ内のあらゆるものにアクセスできると見なされていることです。このパッチにより、スタックベースのローカルが呼び出し先から到達可能と見なされなくなります。

于 2012-11-10T03:14:53.720 に答える