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 位指令。这实际上取决于您想通过测试评估什么。
我想对系统上不同机器指令使用的周期数进行基准测试(对于本例,它是 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 位指令。这实际上取决于您想通过测试评估什么。