【发布时间】:2021-07-16 12:21:36
【问题描述】:
我正在尝试编写一些带有memset 样式循环的裸机代码:
for (int i = 0; i < N; ++i) {
arr[i] = 0;
}
它是用 GCC 编译的,而 GCC 足够聪明,可以将其转换为对 memset() 的调用。不幸的是,因为它是裸机,所以我没有 memset()(通常在 libc 中)所以我收到链接错误。
undefined reference to `memset'
似乎进行这种转换的优化是-ftree-loop-distribute-patterns:
对可以通过调用库生成的代码执行循环分布。默认情况下,此标志在 -O2 及更高版本以及
-fprofile-use和-fauto-profile启用。
所以one person's solution 只是降低了优化级别。不是很满意。
我还发现 this really helpful page 解释了 -ffreestanding 不足以让 GCC 不这样做,基本上没有选择,只能提供您自己的 memcpy、memmove、memset 和memcmp。我很乐意这样做,但是怎么做呢?
如果我只写memset,编译器将检测其中的循环并将其转换为对 memset 的调用!事实上,在我使用的 CPU 供应商提供的代码中,我实际上发现了这条评论:
/*
// This is commented out because the assembly code that the compiler generates appears to be
// wrong. The code would recursively call the memset function and eventually overruns the
// stack space.
void * memset(void *dest, int ch, size_t count)
...
所以我认为这是他们遇到的问题。
我如何提供memset 的 C 实现,而不需要编译器将其优化为对其自身的调用,并且不禁用该优化?
【问题讨论】:
-
奇怪,
-ffreestandingworks for me。 -
@Lundin:我不明白您为什么需要了解目标系统。我想你误会了。
-
@EricPostpischil 事实证明,在初始化/复制large structs 时,即使使用
-ffreestanding,编译器也确实插入了memset和memcpy调用。 gcc documentation中也提到了这一点:GCC requires the freestanding environment provide memcpy, memmove, memset and memcmp. -
@supercat 我认为这里提供的答案是“正确”的方式,因为 glibc 就是这样做的(AFAIK 他们与 gcc 携手合作)。