困扰几天的问题,这是被 gcc 优化了吗?

13 天前
 aqtata

一个动态库项目,支持 win32 和 arm64 ,编译器是 msvc 和 gcc ( gcc 是自己从源码编译的,版本 15.1.0 ) 对外暴露一个标准 C API ,其内部实现只有一行代码,调用一个内部名称空间内的方法

int my_foo()
{
    return internal::bar();
}

魔幻的事情是,这个 so 文件,我写一个控制台程序去调用它,能顺利进入到bar()中,放到实际项目中bar()根本就没有被调用,于是尝试打印

int my_foo()
{
    std::cout << "111111111111111" << std::endl;
    std::cout << __FUNCTION__ << std::endl;
    std::cout << "internal::bar address: " << (long long)((void*)&internal::bar);
    return internal::bar();
}

好家伙,在 linux 下只能打印前两行,然后函数返回 0 ,但这种情况只发生在项目引用时出现。写一个简单的命令行程序触发完全没问题,win32 下也都没问题。 我想 so 文件已经是二进制了,还能被链接它的程序优化不成?这里卡住了,不知道怎么办 项目均使用了-O2

5597 次点击
所在节点    C++
31 条回复
yolee599
13 天前
你在第三行打印下面再加一行纯文本打印看看,有时候遇到空指针或者其他情况,不会执行打印的
wanmyj
13 天前
这个看起来是 rvo 。O2 只是关闭编译器优化,但没有关闭 rvo 。关闭 rvo 有单独的选项的, 加了 fno-elide-constructors 这个参数就 OK 了
jim9606
13 天前
会不会是因为混用不同 c/c++运行时导致的?
Gilfoyle26
13 天前
@Niunai #4 同意!!!
Arthur2e5
13 天前
@Liuuwei 又不是 main 跑完了,谁说程序跑完了?

@jim9606 那直接链接时爆炸没了
o0DoO0o
13 天前
反汇编应该就可以了,看看 myfoo 返回的是寄存器还是常量 0
johnnyyeen
13 天前
看看 internal::bar();实现,如果 internal::bar();什么也没做,多半被优化了。
aqtata
13 天前
我加上了 std::endl ,地址可以打印出来了。然后又将 so 文件拖到 ida 中看了,代码都在,没有被优化。

根据楼上朋友的提示说可能是符号问题,我找到了项目中另一个 so 文件,确实发现了同名空间下的同名函数!!
加入输出后果然破案了,在 a.so 内执行 internal::bar() 却串到了 b.so 文件内部的 internal::bar() 中去了!?

按照我的理解,so 文件已经是二进制了,都有各自的内存范围,不清楚为什么会“串门”
aqtata
13 天前
解决了,是符号冲突了,gcc 默认把所有符号导出了,这点和 msvc 确实不同。
Rorysky
11 天前
@aqtata 动态链接库是共享的,又叫共享库
kita
10 天前
@aqtata
https://gcc.gnu.org/wiki/Visibility
你没有看过这篇吧,贴代码要贴全,不然大家盲猜基本上都认为是 symbols 没有 link 对,但是没有办法告诉你哪里没有 link 对

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1142912

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX