与GCC

时间:2015-07-16 09:42:31

标签: c++ gcc string-literals

我在此代码中无法理解原因:

#include <cstdio>

void use(const char *msg) { printf("%s\n", msg); }

void bar() { use("/usr/lib/usr/local/foo-bar"); }
void foo() { use("/usr/local/foo-bar"); }

int main() {
    bar();
    foo();
}

编译器(在我的例子中是GCC 4.9)决定共享字符串文字:

$ g++ -O2 -std=c++11 foo.cpp && strings a.out | grep /usr/
/usr/lib/usr/local/foo-bar

但是在相同但不同的情况下:

#include <cstdio>

void use(const char *msg) { printf("%s\n", msg); }

void bar() { use("/usr/local/var/lib/dbus/machine-id"); } // CHANGED
void foo() { use("/var/lib/dbus/machine-id"); }           // CHANGED

int main() {
    bar();
    foo();
}

它没有:

$ g++ -O2 -std=c++11 foo.cpp && strings a.out | grep /lib/
/usr/local/var/lib/dbus/machine-id
/var/lib/dbus/machine-id

编辑:

使用-Os,第二对字符串也是共享的。但这没有任何意义。它只是传递指针。具有恒定偏移的lea几乎不能被视为恶化性能,只允许在空间优化模式下共享。

字符串文字共享似乎有一个大小限制(30,包括终止NUL)。除了可能避免过长的链接器运行,尝试找到常见的后缀之外,这也没有多大意义。

1 个答案:

答案 0 :(得分:0)

This论文对gcc和本主题进行了很好的研究。我个人不知道-fmerge-all-constants,但您可以检查是否在两种情况下都使字符串重叠(因为该文件指出它不适用于O3Os)。

修改

由于有一个有效的评论,答案只是链接(我的意思是答案更多只是一个相关的信息而不是一个实际的答案),我觉得我需要更广泛地做到这一点。因此,我在http://gcc.godbolt.org/中尝试了两个示例,以查看生成的程序集,因为我没有可访问的Linux机器。奇怪的是,gcc 4.9没有合并字符串(或者我的汇编知识完全错误),所以问题是 - 它可以特定于你的工具链,还是解析工具失败了?见下图:

enter image description here enter image description here

当然,如果我对装配的理解是错误的,.LC1.LC3仍然可以在.rodata部分重叠,那么这不会证明什么,但至少有人会纠正我,我会意识到这一点。