V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
谷否 | 三分谷地,为你喜欢
AI 大模型 + 柔性供应链,不仅可以为你测试香水味道,还能一件定制实体香水,快速发货。
Promoted by wuqiwen
aqtata
V2EX  ›  C++

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

  •  
  •   aqtata · 11 天前 · 5549 次点击

    一个动态库项目,支持 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

    31 条回复    2025-07-07 10:13:26 +08:00
    OBJECTION
        1
    OBJECTION  
       11 天前   ❤️ 1
    要不还是加个-g gdb 进去看看? 根据你的描述看不出来啥原因啊
    zhyl
        2
    zhyl  
       11 天前   ❤️ 6
    只打印前两行会不会是没有 flush 输出缓冲区
    Niunai
        3
    Niunai  
       11 天前   ❤️ 1
    前两行都有 std::endl ,第三行没有。#2 说的没毛病。
    Niunai
        4
    Niunai  
       11 天前   ❤️ 2
    再说了,有没有被优化,反汇编来看看不就行了,有功夫上 V2 来问,没工夫反汇编吗?
    猜测完了要验证。
    xdeng
        5
    xdeng  
       11 天前   ❤️ 1
    拖到 IDA 里看一下就知道了
    tusj
        6
    tusj  
       11 天前   ❤️ 1
    你是依据什么判断函数没有被调用的?第 3 行没打印出来,可能是因为你没有 << std::endl;
    aqtata
        7
    aqtata  
    OP
       11 天前
    没 std::endl 确实,我等下加上。但打印不是问题关键,主要问题时 bar 中的逻辑都没执行,导致接下来其他 api 接口都会调用失败。
    但我这里试出来一个解决方法,给 bar 加上一个参数,比如 bar(int x),这样就能进入到 bar 中了,感觉还是和某种优化有关
    Ming5Ming
        8
    Ming5Ming  
       11 天前   ❤️ 1
    既然是一个方法,有没有可能是重载了?
    minami
        9
    minami  
       11 天前   ❤️ 1
    怀疑优化问题的话可以关闭优化看看。不过盲猜是动态库导出函数调用约定的问题,可以把 internal::bar();提前不要放到 return 里看看,如果能执行就是这个问题了
    Liuuwei
        10
    Liuuwei  
       11 天前 via iPhone   ❤️ 2
    程序都跑完了,缓冲区还会不刷新?
    nooneanyone
        11
    nooneanyone  
       11 天前   ❤️ 1
    是不是动态链接的问题?
    a83223676
        12
    a83223676  
       11 天前   ❤️ 1
    我会先这么写代码试试

    int my_foo()
    {
    std::cout << __FUNCTION__ << std::endl;
    std::cout << "before call bar" << std::endl;
    int ret = internal::bar();
    std::cout << "after call bar.ret:" << ret << std::endl;
    return ret;
    }
    rtv
        13
    rtv  
       11 天前   ❤️ 2
    问 ai 回答可能是符号冲突…你回复也说加一个参数就没问题
    kita
        14
    kita  
       11 天前   ❤️ 1
    你有无 extern "C" {}; 不然可能 link 时候 symbols 不对
    txhwind
        15
    txhwind  
       11 天前   ❤️ 1
    100%是名字冲突了
    Ilavena
        16
    Ilavena  
       11 天前   ❤️ 1
    首先,你自己写了一个控制台程序取调用它,没有问题,说明动态库是正常的,实际项目里面是否存在 internal::bar 接口影响的?
    1 ,在 my_fool 用 exectern C 包装一下,重新编译这个动态库。
    2 ,在 linux 下建议你尝试使用 dlopen 加载动态库,以及 dlsym 调用对应接口
    这样我觉得问题应该能够解决。
    请告诉结果哈
    Ilavena
        17
    Ilavena  
       11 天前   ❤️ 1
    c++还是蛮有魅力的,我搞了 5 年 c++开发,最近再学深度学习,搞 python ,觉得 python 真的简单易学,也觉得 python 真的牛逼。
    weidaizi
        18
    weidaizi  
       11 天前   ❤️ 1
    1. 首先,使用 -O2 也可以加 -g ,遇到这个情况先 debug ,看看代码到底跑哪里去了
    2. 其次,这种简单的问题 99.999999% 不是编译器的问题,所以快去做第 1 件事
    3. 如果在项目中调试也是确实没跑进去,建议开个 sanitizer 看看有没有出现未定义的行为
    hwdq0012
        19
    hwdq0012  
       11 天前   ❤️ 1
    感觉是动态库是旧的,看看编译时间
    cbythe434
        20
    cbythe434  
       11 天前   ❤️ 1
    internal 命名空间覆盖了吧
    yolee599
        21
    yolee599  
       11 天前 via Android   ❤️ 1
    你在第三行打印下面再加一行纯文本打印看看,有时候遇到空指针或者其他情况,不会执行打印的
    wanmyj
        22
    wanmyj  
       10 天前 via iPhone   ❤️ 1
    这个看起来是 rvo 。O2 只是关闭编译器优化,但没有关闭 rvo 。关闭 rvo 有单独的选项的, 加了 fno-elide-constructors 这个参数就 OK 了
    jim9606
        23
    jim9606  
       10 天前 via Android   ❤️ 1
    会不会是因为混用不同 c/c++运行时导致的?
    Gilfoyle26
        24
    Gilfoyle26  
       10 天前   ❤️ 1
    @Niunai #4 同意!!!
    Arthur2e5
        25
    Arthur2e5  
       10 天前   ❤️ 1
    @Liuuwei 又不是 main 跑完了,谁说程序跑完了?

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

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

    按照我的理解,so 文件已经是二进制了,都有各自的内存范围,不清楚为什么会“串门”
    aqtata
        29
    aqtata  
    OP
       10 天前   ❤️ 1
    解决了,是符号冲突了,gcc 默认把所有符号导出了,这点和 msvc 确实不同。
    Rorysky
        30
    Rorysky  
       8 天前
    @aqtata 动态链接库是共享的,又叫共享库
    kita
        31
    kita  
       8 天前
    @aqtata
    https://gcc.gnu.org/wiki/Visibility
    你没有看过这篇吧,贴代码要贴全,不然大家盲猜基本上都认为是 symbols 没有 link 对,但是没有办法告诉你哪里没有 link 对
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3935 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:26 · PVG 13:26 · LAX 22:26 · JFK 01:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.