困扰几天的问题,这是被 gcc 优化了吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
aqtata
V2EX    C++

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

  •  
  •   aqtata 164 天前 6974 次点击
    这是一个创建于 164 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个动态库项目,支持 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  
       164 天前   1
    要不还是加个-g gdb 进去看看? 根据你的描述看不出来啥原因啊
    zhyl
        2
    zhyl  
       164 天前   6
    只打印前两行会不会是没有 flush 输出缓冲区
    Niunai
        3
    Niunai  
       164 天前   1
    前两行都有 std::endl ,第三行没有。#2 说的没毛病。
    Niunai
        4
    Niunai  
       164 天前   2
    再说了,有没有被优化,反汇编来看看不就行了,有功夫上 V2 来问,没工夫反汇编吗?
    猜测完了要验证。
    xdeng
        5
    xdeng  
       164 天前   1
    拖到 IDA 里看一下就知道了
    tusj
        6
    tusj  
       164 天前   1
    你是依据什么判断函数没有被调用的?第 3 行没打印出来,可能是因为你没有 << std::endl;
    aqtata
        7
    aqtata  
    OP
       164 天前
    没 std::endl 确实,我等下加上。但打印不是问题关键,主要问题时 bar 中的逻辑都没执行,导致接下来其他 api 接口都会调用失败。
    但我这里试出来一个解决方法,给 bar 加上一个参数,比如 bar(int x),这样就能进入到 bar 中了,感觉还是和某种优化有关
    Ming5Ming
        8
    Ming5Ming  
       164 天前   1
    既然是一个方法,有没有可能是重载了?
    minami
        9
    minami  
       164 天前   1
    怀疑优化问题的话可以关闭优化看看。不过盲猜是动态库导出函数调用约定的问题,可以把 internal::bar();提前不要放到 return 里看看,如果能执行就是这个问题了
    Liuuwei
        10
    Liuuwei  
       164 天前 via iPhone   2
    程序都跑完了,缓冲区还会不刷新?
    nooneanyone
    &nbs;   11
    nooneanyone  
       164 天前   1
    是不是动态链接的问题?
    a83223676
        12
    a83223676  
       164 天前   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  
       164 天前   2
    问 ai 回答可能是符号冲突…你回复也说加一个参数就没问题
    kita
        14
    kita  
       164 天前   1
    你有无 extern "C" {}; 不然可能 link 时候 symbols 不对
    txhwind
        15
    txhwind  
       164 天前   1
    100%是名字冲突了
    Ilavena
        16
    Ilavena  
       164 天前   1
    首先,你自己写了一个控制台程序取调用它,没有问题,说明动态库是正常的,实际项目里面是否存在 internal::bar 接口影响的?
    1 ,在 my_fool 用 exectern C 包装一下,重新编译这个动态库。
    2 ,在 linux 下建议你尝试使用 dlopen 加载动态库,以及 dlsym 调用对应接口
    这样我觉得问题应该能够解决。
    请告诉结果哈
    Ilavena
        17
    Ilavena  
       164 天前   1
    c++还是蛮有魅力的,我搞了 5 年 c++开发,最近再学深度学习,搞 python ,觉得 python 真的简单易学,也觉得 python 真的牛逼。
    weidaizi
        18
    weidaizi  
       164 天前   1
    1. 首先,使用 -O2 也可以加 -g ,遇到这个情况先 debug ,看看代码到底跑哪里去了
    2. 其次,这种简单的问题 99.999999% 不是编译器的问题,所以快去做第 1 件事
    3. 如果在项目中调试也是确实没跑进去,建议开个 sanitizer 看看有没有出现未定义的行为
    hwdq0012
        19
    hwdq0012  
       164 天前   1
    感觉是动态库是旧的,看看编译时间
    cbythe434
        20
    cbythe434  
       164 天前   1
    internal 命名空间覆盖了吧
    yolee599
        21
    yolee599  
       164 天前 via Android   1
    你在第三行打印下面再加一行纯文本打印看看,有时候遇到空指针或者其他情况,不会执行打印的
    wanmyj
        22
    wanmyj  
       164 天前 via iPhone   1
    这个看起来是 rvo 。O2 只是关闭编译器优化,但没有关闭 rvo 。关闭 rvo 有单独的选项的, 加了 fno-elide-constructors 这个参数就 OK 了
    jim9606
        23
    jim9606  
       164 天前 via Android   1
    会不会是因为混用不同 c/c++运行时导致的?
    Gilfoyle26
        24
    Gilfoyle26  
       164 天前    /> 1</span> <div class=
    @Niunai #4 同意!!!
    Arthur2e5
        25
    Arthur2e5  
       164 天前   1
    @Liuuwei 又不是 main 跑完了,谁说程序跑完了?

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

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

    按照我的理解,so 文件已经是二进制了,都有各自的内存范围,不清楚为什么会“串门”
    aqtata
        29
    aqtata  
    OP
       163 天前   1
    解决了,是符号冲突了,gcc 默认把所有符号导出了,这点和 msvc 确实不同。
    Rorysky
        30
    Rorysky  
       161 天前
    @aqtata 动态链接库是共享的,又叫共享库
    kita
        31
    kita  
       161 天前
    @aqtata
    https://gcc.gnu.org/wiki/Visibility
    你没有看过这篇吧,贴代码要贴全,不然大家盲猜基本上都认为是 symbols 没有 link 对,但是没有办法告诉你哪里没有 link 对
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3182 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 43ms UTC 11:17 PVG 19:17 LAX 03:17 JFK 06:17
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86