2016-02-05 7 views
7

まず、RAMとROMの使用が優先されるようにマイクロコントローラ用に開発しています。GCCは初期化されていないスタティックコンストラクタの構造体コピーを最適化していません

私はこれがバグレポートとして読んでも、それほど具体的ではないことに気付いています。私がここで何の答えも得られないならば、私はそのように答えるだろう。

私はstatic const構造体を使用して、スタック構造体をデフォルトに初期化するのが好きです。ほとんどの場合、デフォルトの構造体はすべてゼロです。私は私の現在のツールチェーンを最適化-OsとのCortex M4のターゲット向けにコンパイル、arm-none-eabi-gcc-4_7_3ある

static const構造体ではなく、memsetmemset or struct assignmentstatic const assignment)でこれを行うことを好みます。

私は以下に気付きました。 GCCは私がstatic const構造体をゼロに明示的に初期化すると、異なるコードを生成します(static const struct foo; vs static const struct foo = {0};)。特に、初期化されていないstatic const構造体をメモリに割り当て、コピー操作を実行します。ここで

は、コードサンプルです:

struct foo {int foo; int bar;}; 
struct bar {int bar[20];}; 

static const struct foo foo1_init, foo2_init = {0}; 
static const struct bar bar1_init, bar2_init = {0}; 

extern struct foo foo1, foo2; 
extern struct bar bar1, bar2; 

void init_foo1(void) 
{ 
    foo1 = foo1_init; 
} 

void init_foo2(void) 
{ 
    foo2 = foo2_init; 
} 

void init_bar1(void) 
{ 
    bar1 = bar1_init; 
} 

void init_bar2(void) 
{ 
    bar2 = bar2_init; 
} 

はコンパイル、これは(再配置し、簡潔にするためにトリミング)リスト次のアセンブラを生成します。

396     .section .bss.foo1_init,"aw",%nobits 
397     .align 2 
398     .set .LANCHOR0,. + 0 
401    foo1_init: 
402 0000 00000000  .space 8 
402  00000000 

    40    .L2: 
    41 0010 00000000  .word .LANCHOR0 
    42 0014 00000000  .word foo1 

    55:     **** foo1 = foo1_init; 
    32     .loc 1 55 0 
    33 0000 034A   ldr r2, .L2 
    34 0002 044B   ldr r3, .L2+4 
    35 0004 92E80300  ldmia r2, {r0, r1} 
    36 0008 83E80300  stmia r3, {r0, r1} 


    67    .L5: 
    68 000c 00000000  .word foo2 

    60:     **** foo2 = foo2_init; 
    60 0000 024B   ldr r3, .L5 
    61 0002 0022   movs r2, #0 
    62 0004 1A60   str r2, [r3, #0] 
    63 0006 5A60   str r2, [r3, #4] 


389     .section .bss.bar1_init,"aw",%nobits 
390     .align 2 
391     .set .LANCHOR1,. + 0 
394    bar1_init: 
395 0000 00000000  .space 80 
395  00000000 
395  00000000 
395  00000000 
395  00000000 

    98    .L8: 
    99 0010 00000000  .word .LANCHOR1 
100 0014 00000000  .word bar1 

    65:     **** bar1 = bar1_init; 
    89     .loc 1 65 0 
    90 0002 0349   ldr r1, .L8 
    91 0004 0348   ldr r0, .L8+4 
    92 0006 5022   movs r2, #80 
    93 0008 FFF7FEFF  bl memcpy 


130    .L11: 
131 0010 00000000  .word bar2 

70:     **** bar2 = bar2_init; 
121     .loc 1 70 0 
122 0002 0021   movs r1, #0 
123 0004 5022   movs r2, #80 
124 0006 0248   ldr r0, .L11 
125 0008 FFF7FEFF  bl memset 

我々はfoo2 = init_foo2bar2 = init_bar2コンパイラのためにそれを見ることができますそのコピーを最適化してfoo2に直接格納するか、bar2の場合はmemsetを呼び出します。

我々はfoo1 = init_foo1bar1 = init_bar1のために、コンパイラは、明示的なコピーを実行しているにロードし、foo1用レジスタから保存しfoo2ためmemcpyを呼び出すことがわかります。

  1. が、これはGCCの操作を期待されている:

    は、私はいくつか質問がありますか?初期化されていないstatic const構造体が、初期化されたstatic const構造体と同じGCC内の同じパスをたどり、同じ出力を生成することを期待しています。
  2. これは他のバージョンのARM GCCで発生しますか?私は手作業で他のバージョンを用意していません。Cはアセンブラコンパイラには実際にはC++コンパイラです。
  3. これはGCCの他のターゲットアーキテクチャで起こりますか?繰り返しますが、私は他のバージョンを手にすることはありません。
+0

あなたは一貫性のために、あなたのコードを編集してもらえますか?現在、 'foo1_init'などを参照しています。これらはあなたのコードで定義されていません(代わりに' init_foo1'を定義しています)。私はあなたが同じスコープ内の変数と関数の両方として 'init_foo1'を持っているので、それは単にタイプミスであると思います。 –

+0

'memcpy()'を呼び出すと、スペースがかなり安いので、コピーをインライン化するのにかかるコストと比較しましたか?おそらく、バイト数が十分に大きいときに呼び出しを発行するヒューリスティックがあります。 – unwind

+0

@イアン確かにタイプミス。私はもともと何か別の名前の関数を持っていましたが、アセンブリの出力を理解するのが難しくなりました。 –

答えて

-1

私はamd64でテストしましたが、驚いたことに、これは一貫した動作のようです(ただし、バグかどうかわかりません)。 gccは、foo1_initとbar1_initを共通データセグメント、またはオペレーティングシステム(.bss)によってゼロで初期化された値のセグメントに置きます。 foo2_initとbar2_initは、読み込み専用セグメント(.rodata)に、ゼロ以外の初期化値であるかのように配置されます。これは-O0を使って見ることができます。 OSを使用していないので、OSの初期化されたセクションは、gccやリンカによって手作業で初期化され、コピーされます。 gccは、直接memsetを作成し、dead * 2_init変数を削除することで、rodata値を最適化します。しかし、clangは両方のケースを同じように最適化します。ここで

は、gccの出力(-O0)を、次のとおりです。

.file "defs.c" 
    .local foo1_init 
    .comm foo1_init,8,8 
    .section .rodata 
    .align 8 
    .type foo2_init, @object 
    .size foo2_init, 8 
foo2_init: 
    .zero 8 
    .local bar1_init 
    .comm bar1_init,80,32 
    .align 32 
    .type bar2_init, @object 
    .size bar2_init, 80 
bar2_init: 
    .zero 80 
    .text 
    .globl init_foo1 
    .type init_foo1, @function 
init_foo1: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq foo1_init(%rip), %rax 
    movq %rax, foo1(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size init_foo1, .-init_foo1 
    .globl init_foo2 
    .type init_foo2, @function 
init_foo2: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq $0, foo2(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size init_foo2, .-init_foo2 
    .globl init_bar1 
    .type init_bar1, @function 
init_bar1: 
.LFB2: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq bar1_init(%rip), %rax 
    movq %rax, bar1(%rip) 
    movq bar1_init+8(%rip), %rax 
    movq %rax, bar1+8(%rip) 
    movq bar1_init+16(%rip), %rax 
    movq %rax, bar1+16(%rip) 
    movq bar1_init+24(%rip), %rax 
    movq %rax, bar1+24(%rip) 
    movq bar1_init+32(%rip), %rax 
    movq %rax, bar1+32(%rip) 
    movq bar1_init+40(%rip), %rax 
    movq %rax, bar1+40(%rip) 
    movq bar1_init+48(%rip), %rax 
    movq %rax, bar1+48(%rip) 
    movq bar1_init+56(%rip), %rax 
    movq %rax, bar1+56(%rip) 
    movq bar1_init+64(%rip), %rax 
    movq %rax, bar1+64(%rip) 
    movq bar1_init+72(%rip), %rax 
    movq %rax, bar1+72(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE2: 
    .size init_bar1, .-init_bar1 
    .globl init_bar2 
    .type init_bar2, @function 
init_bar2: 
.LFB3: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movl $bar2, %eax 
    movl $80, %ecx 
    movl $0, %esi 
    movq %rsi, (%rax) 
    movl %ecx, %edx 
    addq %rax, %rdx 
    addq $8, %rdx 
    movq %rsi, -16(%rdx) 
    leaq 8(%rax), %rdx 
    andq $-8, %rdx 
    subq %rdx, %rax 
    addl %eax, %ecx 
    andl $-8, %ecx 
    movl %ecx, %eax 
    shrl $3, %eax 
    movl %eax, %ecx 
    movq %rdx, %rdi 
    movq %rsi, %rax 
    rep stosq 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE3: 
    .size init_bar2, .-init_bar2 
    .ident "GCC: (GNU) 6.3.1 20170306" 
    .section .note.GNU-stack,"",@progbits 
関連する問題