0%

信创系统-凝思606替换GLIBC库以运行QT的可行性调查

信创系统-凝思606替换GLIBC库以运行QT的可行性调查

  1. 安装CentOS7编译的带UI的QT程序,其中systemctl相关服务已被替换为service

    由于606系统libc.so.6版本过低,无法正常运行

  2. 尝试替换其他高版本的libc.so至本地的lib目录,同时替换其依赖

    image-20240508143943090

    image-20240508143957295

  3. 替换完成后,碰到一些系统命令调用的问题,由于eps_service脚本会指定LD_LIBRARY_PATH,所以在该脚本中执行的系统调用命令会优先使用刚在替换的库,先在尝试将这些命令也替换为高版本gcc编译出的可执行文件,为了避免造成系统出错,这里将脚本中的系统命令换位执行本地目录的命令

    1. 替换/增加的文件有

      1
      2
      3
      4
      5
      6
      7
      bash、ln、sleep、pidof、mkdir、dirname
      ld-linux-x86-64.so.2 -> ld-2.17.so
      libtinfo.so.5 -> libtinfo.so.5.9
      libgcc_s.so.1 -> libgcc_s-4.8.5-20150702.so.1
      libm.so.6 -> libm-2.17.so
      libstdc++.so.6 -> libstdc++.so.6.0.19
      libc.so.6 -> libc-2.17.so
  1. 替换这些文件后, 报错信息仍然如下

    1
    relocation error: /opt/apps/xxx/lib/libc.so.6: symbol _dl_starting_up, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference
  2. 经查阅(https://stackoverflow.com/questions/847179/multiple-glibc-libraries-on-a-single-host)

    ld-linux-x86-64.so.2所指向的ld-2.17.so是一个链接器,他是可执行的,并且可执行文件所需要的链接器路径是写死在文件头信息中的,可通过工具patchelf来修改文件头部信息,命令如下

    patchelf --set-interpreter ${从别处拷贝的链接器(ld-linux-x86-64.so.2)} --set-rpath ${自己的lib目录} ${文件名}

    例如patchelf --set-interpreter /opt/apps/xxx/lib/ld-linux-x86-64.so.2 --set-rpath /opt/apps/xxx/lib/ /opt/apps/xxx/bin/bash

    同时,也可直接使用ld-linux-x86-64.so.2文件本身来单次指定链接器,仅当次生效,这在设置了LD_LIBRARY_PATH后想要执行系统自身命令,如想要使用gdb看看情况时==非常有用==。可以用低版本系统本身的ld-linux-x86-64.so.2指向系统本身的库,如下

    /lib64/ld-linux-x86-64.so.2 --library-path /lib64 /usr/bin/gdb ./edr_monitor

  3. 当做完这些后,发现仍然无法启动程序,启动报段错误,使用/lib64/ld-linux-x86-64.so.2 --library-path /lib64 /usr/bin/gdb ./app调试,未能发现其他问题,而==导入环境变量后直接执行程序会段错误==

改变思路

  1. 在凝思606上安装gcc4.8.5编译器

    1
    ./configure -enable-checking=release -enable-languages=c,c++ -disable-multilib
  1. 编译QT5.9.8

    1
    ./configure -confirm-license -opensource -release -prefix "/tmp/qt" -nomake tests -nomake examples -no-compile-examples -qt-xcb -no-openssl -skip webengine -skip tools -skip 3d -skip gamepad -skip multimedia -skip doc -skip location -skip sensors -skip androidextras -c++std c++11 -no-static -no-use-gold-linker -no-glib -no-iconv -no-icu -qt-freetype -qt-harfbuzz -no-fontconfig -no-xkbcommon-evdev -no-gtk -qt-libjpeg -qt-libpng -no-libinput -no-cups -dbus-runtime -no-eglfs -skip wayland -optimize-size -skip serialport -skip virtualkeyboard -skip connectivity -skip activeqt -no-avx2

    其中-no-avx2这个参数很重要, 指定编译用的CPU指令集不包含avx2, qt的configure在这个环境下无法自动检测, 会造成一些编译错误, 例如下图

    image-20240508144334144

  2. 编译代码(部分三方库需要重编, 因为glibc库此时还是低版本的)

  3. 此时编译出来的终端除了ui外其他都可以正常运行, 经排查, 是系统libstdc++.so版本问题, 尝试将高版本库放入终端lib目录

  4. 引入高版本libstdc++.so此时UI程序报 段错误,经排查,是由于其中一个list进行push_back操作导致

    image-20240508144424382

    虽然不能找出具体原因,但是替换为vector后即可正常使用

  5. 此时QT的画笔模块出现问题

    image-20240508144450629

  6. 对比了可以正常运行版本的依赖,发现依赖数量相差九个

    image-20240508144503912

  7. 经排查多出来的为libGL.so的依赖,属于OpenGL库,遂安装mesa-10.1.0,此时安装后,依赖数量仍差两个,此时UI仍然无法正常启动,问题同之前,通过gdb调试得到其崩溃是因为QT库的问题,程序异常退出并存在信号SIGFPE

  8. 编译debug版本的QT,重新编译UI准备调试,此时托盘图标页无法弹出,通过gdb运行发现有信号SIGABRT,经过追踪,确定问题出在加载托盘图标,实例化QIcon这一步,其中有一个函数获取系统不透明度格式时返回了非法值,触发了接下来的一个assert,从而导致出现问题,通过将QT源码改写,将原来出问题的函数中的连续三次指针调用成员函数改为分三句执行,发现最重要的第三步无法跟进去,同时gdb报RTTI symobl not found for class 'QXcbScreen',怀疑其和QXcbScreen这个类有关,同时也在该类中找到了同名函数format

image-20240508144536501

image-20240508144549717

-------------本文结束感谢您的阅读-------------