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

时间:2015-03-17 12:48:26

标签: c gcc assembly arm const

我想对我系统上不同机器指令使用的循环次数进行基准测试(对于此示例,它是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版本4.8.3 20140228(发布)[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-macro有点冗长。它只增加了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

1 个答案:

答案 0 :(得分:1)

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

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