GCC:为什么 const 数据填充在我的函数内部而不是开头?

GCC: Why is const data filled inside my function and not at the beginning?

我想对系统上不同机器指令使用的周期数进行基准测试(对于本例,它是 ARM Cortex-M4)。所以我使用了一个宏,它重复目标指令多次,在此之前和之后,我读取了我的控制器的循环计数器。在 asm-dump 中,我看到在某个位置填充了 const 数据(我的循环计数器寄存器的地址)(位置 8003140 到 8003150,标有“>”):

    08002d58 <testThis>:
    8002d58:    48fa        ldr r0, [pc, #1000] ; (8003144 <testThis+0x3ec>)
    8002d5a:    49fb        ldr r1, [pc, #1004] ; (8003148 <testThis+0x3f0>)
    8002d5c:    4bfb        ldr r3, [pc, #1004] ; (800314c <testThis+0x3f4>)
    8002d5e:    4afc        ldr r2, [pc, #1008] ; (8003150 <testThis+0x3f8>)
    8002d60:    6800        ldr r0, [r0, #0]
    8002d62:    6008        str r0, [r1, #0]
    8002d64:    681b        ldr r3, [r3, #0]
    8002d66:    6812        ldr r2, [r2, #0]
    8002d68:    fa82 f183   qadd    r1, r3, r2
    8002d6c:    fa82 f183   qadd    r1, r3, r2
    ..
    8003138:    fa82 f183   qadd    r1, r3, r2
    800313c:    fa82 f183   qadd    r1, r3, r2
    > 8003140:  e008        b.n 8003154 <testThis+0x3fc>
    > 8003142:  bf00        nop
    > 8003144:  e0001004    .word   0xe0001004
    > 8003148:  20000598    .word   0x20000598
    > 800314c:  20000594    .word   0x20000594
    > 8003150:  200002e4    .word   0x200002e4
    8003154:    fa82 f183   qadd    r1, r3, r2
    8003158:    fa82 f183   qadd    r1, r3, r2
    ..
    8003b84:    fa82 f183   qadd    r1, r3, r2
    8003b88:    fa82 f383   qadd    r3, r3, r2
    8003b8c:    4803        ldr r0, [pc, #12]   ; (8003b9c <testThis+0xe44>)
    8003b8e:    4904        ldr r1, [pc, #16]   ; (8003ba0 <testThis+0xe48>)
    8003b90:    6003        str r3, [r0, #0]
    8003b92:    4b04        ldr r3, [pc, #16]   ; (8003ba4 <testThis+0xe4c>)
    8003b94:    680a        ldr r2, [r1, #0]
    8003b96:    601a        str r2, [r3, #0]
    8003b98:    4770        bx  lr
    8003b9a:    bf00        nop
    8003b9c:    2000058c    .word   0x2000058c
    8003ba0:    e0001004    .word   0xe0001004
    8003ba4:    20000338    .word   0x20000338

为什么这个开头没有填写? 我能控制这个吗?

GCC 版本:

gcc version 4.8.3 20140228 (release) [ARM/embedded-4_8-branch revision 208322]

C 代码:

    #define READCYCCNT() *((volatile unsigned int *)0xE0001004)

    uint32_t cyc_begin, cyc_end;
    int c, a, b;
    void testThis(void *obj)
    {
        cyc_begin = READCYCCNT();
        REP(9,0,0, c, __QADD, a, b);
        cyc_end = READCYCCNT();
    }

REP 宏有点长。它只是向

添加了 900 次调用
    c = __QADD(a,b)

编译器调用:

    arm-atollic-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -std=gnu90 -DDEBUG=1 -I../Inc -I../CoreSupport -I../DeviceSupport -Ofast -ffunction-sections -fdata-sections -g -Wall -o Application\Main.o ..\Application\Main.c

编译器已使用 ldr 指令生成了您的代码,并相对于 PC 寻址。这些指令只有 5 位来存储相对地址,因此它们只能访问从当前程序计数器位置开始的 0-124 字范围内的数据。这就是编译器将您的数据放在代码中间的原因。这是 quick reference card 的拇指说明。

有几种方法可以避免这种情况。您可以用使用不同寻址模式的手写程序集替换宏。您可以用常量替换变量并完全避免寻址。您可以减少调用宏的次数。您可以删除 -mthumb 标志以生成具有更多寻址位的 32 位指令。这实际上取决于您想通过测试评估什么。