【发布时间】:2019-05-06 11:08:28
【问题描述】:
出于某种原因,GCC 将 const char 字符串的内容复制到单独的rodata 区域,我不明白。 我编译提供的代码:
static const char pattern[] = "[SOME TEST PATTERN TO CALCULATE SUM FROM] ";
static char tmpbuf[sizeof(pattern) + 1];
uint16_t sum(char *buf, int size)
{
uint16_t ret = 0;
for(int i = 0; i < size; ++i)
ret += buf[i];
return ret;
}
void getPattern(char **retbuf)
{
memcpy(tmpbuf, pattern, sizeof(tmpbuf) -1);
*retbuf = tmpbuf;
}
int main(int argc, char *argv[])
{
getPattern(&argv[0]);
return sum((char *)pattern, sizeof(pattern) - 2) > 0;
}
void _exit(int status)
{
while(1)
{
asm("nop");
}
}
使用arm gcc编译器,使用命令:
arm-none-eabi-gcc -Os dbstr.c -o dbstr -Wl,-Map,"dbstr.map" -fdata-sections
在生成的二进制文件中,即使它被剥离,我也会找到字符串:
"[SOME TEST PATTERN TO CALCULATE SUM FROM] "
重复。
查看符号图,我发现:
.rodata.pattern
0x000087d8 0x2b ... ccumYoyx.o
.rodata.str1.1
0x00008803 0x2b ... ccumYoyx.o
and
.bss.tmpbuf 0x00018ca0 0x2c ... ccumYoyx.o
符号“模式”是原始数组 符号“str1”是重复的 并且符号“tmpbuf”是目标缓冲区,我想将“pattern”复制到其中。
查看生成的程序集,我发现 memcpy 使用了编译器创建的副本:
getPattern:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
-> ldr r3, .L6
push {r4, lr}
mov r2, #43
mov r4, r0
ldr r1, .L6+4
mov r0, r3
bl memcpy
...
.L6:
.word .LANCHOR0
-> .word .LC0
...
pattern:
.ascii "[SOME TEST PATTERN TO CALCULATE SUM FROM] \000"
.section .rodata.str1.1,"aMS",%progbits,1
.LC0: /*duplicate string*/
.ascii "[SOME TEST PATTERN TO CALCULATE SUM FROM] \000"
.ident "GCC: (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.1 20181213 (release) [gcc-8-branch revision 267074]"
我检查了从 6-2017-q1-update 到 8-2018-q4-major 的 arm-none-eabi-gcc 版本是否会发生这种情况(developer.arm.com 上提供的最新版本)。
我也尝试过使用各种优化。仅在使用 -O0 时不会发生重复。对其他人来说确实如此。
在更大的应用程序中,发生了这个问题,结果证明 memcpy 复制了重复的字符串而不是原始字符串 - 它是通过替换二进制中的原始字符串来确定的。我需要 memcpy 才能使用原始字符串。
【问题讨论】:
-
您可以尝试将
pattern变量也声明为volatile,以防止对其进行任何优化。拥有const和volatile是完全合法的,因此声明将是:static const volatile char pattern[] = "[SOME TEST PATTERN TO CALCULATE SUM FROM] "; -
您可以尝试优化尺寸 (
-Os)。如果可行,那么可能有一个特定的优化选项可以控制这种行为(GCC 优化是高度可调的)。 -
并且要清楚,这里的问题是二进制文件比它需要的大,是吗?如果它产生不正确的行为,那么我们希望看到实际展示这种不当行为的代码,以便诊断该问题。
-
@JohnBollinger 是对的,为了给出正确的答案,我们需要实际问题和演示它的代码。尽管如此,当
const变量不像编译器可能认为的const时,我的评论仍然适用。例如,当使用能够擦除其部分内存并用其他数据替换它的 uC 时,可能会发生这种情况。编译器不会知道这种行为,因为它不是标准 C。这可以通过使用volatile关键字来解决。 -
我忽略了这一点,@andreee。我还忽略了 OP 正在查看目标文件,而不是链接的可执行文件,这也可能会有所不同。
标签: c string gcc duplicates memcpy