• gcc 库的链接顺序问题


    前言

    最近MIPS上开发一个程序,需要用到浮点运算。

    写好bootloader,main函数,在main函数调用log浮点运算,包含math库。

    然后再写好makefile,ld脚本。

    gcc的参数用到了:

    CFLAGS= -c -march=3081 -msoft-float -fno-inline  $(ENDIAN) -G0

    ld的参数用到了:

    LDFLAGS= -march=3081 -msoft-float -nostartfiles -lgcc -lm -lc  -Wl,-Map,rlx_test.map

    库的链接顺序

    本文的重点是讲述gcc库的链接顺序。

    刚开始的时候,在链接参数部分,我的顺序是这么安排的: -lc -lgcc -lm。

    结果compile正常,但是在ld的时候,遇到问题了,总是报log函数找不到errno变量。

    经过仔细分析,发现我的程序本身是有问题的,运算表达式可以总结为:log(a)。

    结果a为0了,log函数会报错,会将错误代码赋给__errno这个全局变量。而__errno变量是声明在errno.h头文件中,但是定义在libc的某个file中。

    gcc库的链接顺序,官方是这么解释的:

    https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Link-Options.html#Link-Options

    gcc -l 解释如下:
           -l library
               Search the library named library when linking.  (The second alter-
               native with the library as a separate argument is only for POSIX
               compliance and is not recommended.)

               It makes a difference where in the command you write this option;
               the linker searches and processes libraries and object files in the
               order they are specified.  Thus, foo.o -lz bar.o searches library z
               after file foo.o but before bar.o.  If bar.o refers to functions in
               z, those functions may not be loaded.

    这句话翻译过来的意思就是说,如果你的库在链接时安排的顺序是:foo.o -lz bar.o。那么gcc的链接器先搜索库foo,然后是z库,然后是bar库。

    这样就带来一个问题,如果库bar调用了库z里面的函数,但是链接器是先搜索的库z,这时候并没有发现库bar调用库z啊,所以就不会把库z中的这部分函数体挑出来进行链接。

    而是只把库z中,被foo库调用的函数体挑出来。

    回到我们之前的描述。

    由于__errno全局变量是定义在库libc中,而库libm中的log函数会访问__errno全局变量。这就要求链接时,libm在libc的前面。所以我们应该这样安排库的链接顺序:

     -lm -lgcc -lc 

    一句话,越是被别人调用的越底层的库,就越放在后面;越是调用别人的越上层的库,就越放在前面。

    库的说明

    下面我们来讲讲libm,libgcc, libc分别是做什么用的:

    libm库,是数学运算函数的库,里面包含了各种基本的数学函数实现,例如sin,cos,平方根,log等。

    libgcc库,要想用gcc编译代码就需要调用的库,里面包含了一些基本的函数。参考https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html。例如部分整形/浮点运算,异常处理,一些杂项函数。

    libc库,是c的标准库,里面包含了基本输入输出函数,memcpy之类,string copy之类的函数。

    从这些库的用途,我们就知道为什么要按照-lm -lgcc -lc 的顺序调用了。

    当然在编译内核和一些库时,我们可能会看到nostdlib,这个选项,意思是不调用标准库libc和libgcc,而是要我们自己去实现这些基本的库函数被内核函数调用。

    一些编译和链接参数的说明

    -march=3081,是指定cpu架构是MIPS 3081。

    -msoft-float,是针对没有FPU单元的CPU,编译浮点运算代码需要的,也叫软浮点。

    -nostartfiles,是指不用默认的bootload代码,而要用我们自己写启动引导代码。

  • 相关阅读:
    机器学习介绍
    Day03 作业
    Python函数基础
    Python练习
    耳机 线控 控制播放
    edittext 底线颜色
    从service启动activity startActivity慢 的解决方案
    国产手机没有google services 和google play崩溃,判断google services是否存在
    检测耳机插入和拔出
    获取view宽高
  • 原文地址:https://www.cnblogs.com/ironx/p/4939508.html
Copyright © 2020-2023  润新知