• C专家编程 第5章 对链接的思考 5.3 函数库链接的5个特殊秘密


    函数库连接的五个特殊秘密:(UNIX链接的真实情况)
    1.动态库文件的扩展名“.so”,而静态库文件的扩展名是“.a”
    共享archive的文件名扩展名“.sa”,共享archive只是一种过渡形式,帮助人们从静态库转变成动态库。

    2.例如,通过-lthread选项,告诉编译链接到libthread.so
    实际上,编译器被告知根据选项-lname链接到相应的函数库,函数库的名字是libname.so---换句话说,"lib"部分和文件的扩展名被省略了,但在前面加了一个“-l”。

    3.编译器在确定的目录找到库
    它查看一些特殊的位置,在/usr/lib中查找库。例如,线程库位于/usr/lib/libthread.so.
    编译器选项-Lpathname告知链接器一些其他的目录,如果命令中加入了-l选项,链接器就往这些目录查找函数库。系统中的环境变量LD_LIBRARY_PATH和LD_RUN_PATH用于提供这类信息。处于安全,性能和创建运行独立性方面的考虑,使用环境变量的做法现在已经不提倡。一般还是在链接时使用-Lpathname和-Rpathname选项。

    4.观察头文件,确认所使用的函数库
    一个很好的建议就是可以观察程序所使用的#include指令。在程序中所包含的每个头文件都可能代表一个必须链接的库。但是头文件的名字通常并不与它所对应的函数库名相似。
                       Solaris 2x下的库约定
    #include文件名                库路径名                   所用的编译器选项
                      /usr/lib/libm.so                                  -lm
                      /usr/lib/libm.a                                    -dn -lm
                       /usr/lib/libc.so                                    自动连接
    "/user/openwin/include/X11.h" /usr/openwin/lib/libX11.so  -L/usr/openwin/lib-1X11
                    /usr/lib/libthread.h                            -lthread
                    /usr/lib/libcurses.a                           -lcurses
               /usr/lib/libsocket.so                         -lsocket
    函数库链接所存在的另一个不一致就是函数库包含许多函数的定义,但这些函数的原型声明
    却散布于多个头文件中。

    nm命令在/usr/lib的每个函数库中浏览所有的符号,从中寻找所丢失的符号。在缺省情况下,链接器会在/usr/cc/lib和/usr/lib中查找,你也应该从这两个地方着手,如果找不到就进一步扩展查找范围。(如/usr/openwin/lib)
    %cd /usr/lib
    %foreach i (lib?*)
    ?echo $i
    ?nm $i | grep xdr_refrence | grep -v UNDEF
    ?end
    ...
    这会在该目录中的所有函数库上运行nm命令,它显示函数库中已知的符号列表。通过grep设定需要搜索的符号,并过滤标记为UNDEF符号(在该函数库中有引用,但不是在此处定义)。结果显示xdr_reference位于libnsl库。需要在编译器命令行的末尾加上-lnsl。

    5.与提取动态库中的符号相比,静态库中的符号提取的方法限制更严
    在动态链接中,所有的库符号进入输出文件的虚拟地址空间中,所有的符号对于链接在一起的所有文件都是可见的。相反,对于静态链接,在处理archive时,它只是在archive中查找载入器当时所知道的未定义符号。简而言之,在编译器命令行中各个静态链接库出现的顺序是非常重要的。符号是通过从左到右的顺序进行解析的。如果相同的符号在两个不同的函数库中有不同的定义,且静态库出现的顺序不同,其结果就有可能不同。

    如果在自己的代码之前引入了静态库,又会带来一个问题。因为此时尚未出现未定义的符号,所以它不会从函数库中提取任何符号。接着,当目标问题被链接器处理时,他所有的对函数库的引用都将是未实现的! 

    libm经常是以静态链接的archive形式存在。如果你的程序使用了一些数学函数如sin()等,若像下面这样进行静态链接:
    cc -lm main.c
    则会得到一条错误信息,如下:
    Undefined first referenced
    symbol    in file
    sin       main.o
    ld:fatal: Symbol referencing errors. No output written to a.out
    为了能从math库中提取所需的符号,首先需要让文件包含未解析的引用,如下所示:
    cc main.c -lm
    链接器采用<命令><文件><选项>这样的约定。

    /*函数库选项应置于何处*/
    始终将-l函数库选项放在编译命令行的最右边

    工作区可以在被载入链接器的模式里声明像下面这样的函数,从而向链接器提供更多的线索:
    在PC上,当Borland的编译器驱动器试图猜测需要链接的浮点数时,也会出现这样的问题。
    scanf: floating point formats not linked
    abnormal program termination(scanf:浮点格式未链接,程序异常中止)
    当程序在scanf()或者printf()中使用浮点数格式,但并不调用任何浮点数函数时,就有可能
    猜测错误 
    static void forcefloat(float *p) {
        float f = *p; forcefloat(&f);

    不需要实际调用这个函数,只要保证它被链接即可。这样就能给Borland PC的链接器提供
    一个足够可靠的线索,即该浮点数库确实是需要的。
    另外还有一条类似的信息,当软件需要数值协处理器而计算机却未安装它时,Microsoft C运行时系统会打印一条信息,表示“浮点数未载入”。可以使用浮点数仿真库重新链接程序来解决这个问题。

  • 相关阅读:
    8 个关于提高你 Flutter 移动程序安全性的建议
    2010年09月15日 Go生态洞察:探索Go Playground的新颖之处
    Allegro PCB编辑界面功能全面介绍图文教程
    vscode 根据 ESLint 规范自动格式化代码
    FPGA学习笔记(七)verilog的深入学习之任务与函数(语法篇3)
    异硫氰酸荧光素FITC标记二氧化钛纳米粒纳米颗粒CY7-Se-PEG-TiO2(定制服务)
    【PDF】pdf 学习之路
    Windows环境下使用命令行在达梦数据库导入dmp文件
    自定义httpServletRequestWrapper导致上传文件请求参数丢失
    【NeurIPS 2020】基于蒙特卡罗树搜索的黑箱优化学习搜索空间划分
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126074769