The shared library soname

下面引用一段英文原文

The shared library soname

In the earlier example, we embedded the actual name (the real name) of the shared library in an executable file.

It is possible to create an alias, called the soname, which will be embedded in an executable file instead of the real name

At run-time, the dynamic linker will use the soname when searching for the library. 

The purpose of the soname is to provide a level of indirection.

  • At run-time, executable can use a version of the shared library that is different (but compatible) from that against which it was linked.

    The shared library soname (cont.)

    Here's how to use a soname:

    1. Specify soname when creating shared library:
      $ gcc -fPIC -c -Wall -g mod1.c mod2.c mod3.c $ gcc -shared -Wl,-soname,libbar.so -o libfoo.so \
                 mod1.o mod2.o mod3.o 
      
      -Wl,-soname,libbar.so  instructs linker to mark the shared library  libfoo.so  with the  soname  libbar.so.
    2. Create executable:


      $ gcc -g -Wall -o prog prog.c libfoo.so 
      
      Linker detects that  libfoo.so  contains the  soname  libbar.so  and embeds the latter name inside the executable.
    3. Run the program:
      $ LD_LIBRARY_PATH=. ./prog ./prog: error in loading shared libraries: 
      libbar.so: cannot open shared object file: 
      No such file or directory
      
      Dynamic linker cannot find anything named  libbar.so.
    4. Create a symbolic link from the soname to the real name of the library:
      $ ln -s libfoo.so libbar.so $ LD_LIBRARY_PATH=. ./prog Called mod1-x1
      Called mod2-x2
      

    At run-time this link can point to a version of the library which is different from the version against which linking was performed

    The shared library soname (cont.)

    This diagram shows the steps required in building a shared library, linking a program against it, and creating the requiredsoname symbolic link.

    The <wbr>shared <wbr>library <wbr>soname 

    The shared library soname (cont.)

    This diagram shows the steps that occur as the program is executed:

    The <wbr>shared <wbr>library <wbr>soname 

    Compatible Versus Incompatible Libraries

    We probably need to change a library over time.

    A new library version is said to be compatible with an existing library version if all of the following conditions hold true:

    • The semantics of each function in the library remain unchanged

      • All functions continue to produce same effect on global variables and returned arguments

      • All functions continue to return the same result values

      • Performance improvements and bug fixes (perhaps resulting in closer conformance to specified behavior) are compatible changes. 

    • No function in the library API is removed.
      New functions can be added.
    • The structures exported (i.e. allocated within and returned) by each function remain unchanged.
      Possible exception: new items may be added to the end of the existing structure

    If any of these conditions is violated, then the new library version is incompatible with the previous version.



    Shared library versions and naming

    • If a new version of a shared library is compatible with an existing library, we can make a new minor version of the library. 

    • If a new version of a shared library is incompatible with an existing library, we must make a new major version of the library. 

    • Constraint: it must be possible to continue running programs requiring the older version of the library. 

    • Solution: a naming convention is used for shared library real names and sonames.

    Shared library versions and naming (cont.)

    Real name

    Name of the file containing library code.

    Format: libname.so.major-id.minor-id

    • Major version identifier is a number which is sequentially incremented with each incompatible release of the library. 

    • Minor version identifier distinguishes different compatible minor versions of a library within the same major version.
      Usually either a number, or two numbers separated by a dot, with first number identifying  minor version, and second number indicating a patch level or  revision number  within the minor version.

    Examples:

    libdemo.so.1.0.1
    libdemo.so.1.0.2
    libdemo.so.2.0.1
    libreadline.so.4.0
    

    Shared library versions and naming (cont.)

    soname

    Format: libname.so.major-id

    soname includes the same major version identifier as corresponding real name, but does not include minor versionidentifier. 

    Purpose: run-time loading is dependent only on major version number of the library 

    soname is created as a symbolic link (usually in same directory as real name).

    • The soname for each major library version points to most recent minor version

    • Since it is the soname (not the real name) that is embedded in executable by linker: 

      1. At any time, we can change soname symbolic link to point to a newer minor version

      2. Different major versions can co-exist and be accessed by the programs that require them.

    Examples of sonames (along with the real names to which they might be symbolically linked):

    libdemo.so.1        -> libdemo.so.1.0.2
    libdemo.so.2        -> libdemo.so.2.0.1
    libreadline.so.4    -> libreadline.so.4.0
    

    Shared library versions and naming (cont.)

    Linker name

    • Format: libname.so 

    • Purpose: allows us to construct version-independent link commands which automatically operate with the right (i.e. most up to date) version of the shared library. 

    • Created as a symbolic link to either real name or soname of most recent major version of the library. 

    • More convenient to have it point to sonameWhy? 

    • Examples:
      libdemo.so           -> libdemo.so.2
      libreadline.so       -> libreadline.so.4
      

    Shared library versions and naming (cont.)

    Relationships between shared library names

    The <wbr>shared <wbr>library <wbr>soname

    Creating Shared Libraries Using Standard Naming Conventions

    We can create a shared library using standard naming conventions as follows:

    1. Create the shared library with real name libdemo.so.1.0.1 and soname libdemo.so.1.
      $ gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c $ gcc -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.1 \
                mod1.o mod2.o mod3.o 
      
    2. Create symbolic links for the soname and linker name:
      $ ln -s libdemo.so.1.0.1 libdemo.so.1 $ ln -s libdemo.so.1 libdemo.so $ ls -l libdemo.so* | cut -c 1-11,55- # Verify the setup lrwxrwxrwx  libdemo.so -> libdemo.so.1
      lrwxrwxrwx  libdemo.so.1 -> libdemo.so.1.0.1
      -rwxr-xr-x  libdemo.so.1.0.1
      
    3. Build executable using the linker name:
      $ gcc -g -Wall -o ./prog prog.c -L. -ldemo 
      
    4. Run the program as usual:
      $ LD_LIBRARY_PATH=. ./prog Called mod1-x1
      Called mod2-x2
      

    Installing Shared Libraries

    • Production applications should not require the user to set LD_LIBRARY_PATH

    • Privileged users can install a shared library in one of the standard library directories

      • /usr/lib - directory in which most standard libraries are installed 

      • /lib - directory containing libraries required during system startup 

      • /usr/local/lib non-standard or experimental libraries should be installed here;
        Also useful if  /usr/lib  is a network mount shared among multiple systems, and we want to install a library locally.
      or in one of the directories listed in /etc/ld.so.conf.【注:linux版本如有“/etc/ld.so.conf.d目录”也可以将my.conf这样的配置文件放在/etc/ld.so.conf.d目录下, my.conf的内容格式为 /ldddir/dir】 

    • After installation, symbolic links for soname and linker name must be created, as relative links in the same directory.

    ldconfig(8)

    ldconfig(8) addresses two potential problems with shared libraries:

    1. Speed: Shared libraries can reside in many different directories: it could take the dynamic linker a long time to search them

    2. Manually keeping sonames symlinks up to date is error-prone as new versions of libraries are installed, or old versions are removed.

    ldconfig solves these problems by:

    1. Creating a cache file:
      ldconfig  searches for latest major library versions  in: 

      • all of the directories specified in /etc/ld.so.conf
      • /lib
      • /usr/lib

      and  updates a cache file, /etc/ld.so.cache, to contain a list of the latest major library versions, and their locations.
      Cache file is used by dynamic linker at run-time when resolving library names. 

    2. Automating the creation of sonames

      • ldconfig examines (the latest minor version of) each major version of each library to find the embedded soname, and 

      • creates a relative symbolic link for this soname, in the same directory as the library. 

    In order to work properly, ldconfig relies on the use of the standard naming convention for shared libraries (i.e.,libname.maj.min) 


    ldconfig(8) (cont.)

    Example - installing two different major versions of a library.

    We copy both versions into /usr/lib:

    # mv libdemo.so.1.0.1 libdemo.so.2.0.1 /usr/lib # cd /usr/lib 
    

    We run ldconfig to update the dynamic linker cache:

    # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.1 (changed)
            libdemo.so.2 -> libdemo.so.2.0.1 (changed)
    
    • (We use grep to eliminate other output from ldconfig.)

    Then we manually create the linker name:

    # ln -s libdemo.so.2 libdemo.so 
    


    To install a new 2.x minor version:

    # mv libdemo.so.2.0.2 /usr/lib # cd /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.1
            libdemo.so.2 -> libdemo.so.2.0.2 (changed)
    

    The ldconfig command effectively also updates linker name...


    ldconfig(8) (cont.)

    • ldconfig should be run whenever a new library is installed or an existing library is updated or removed

    • ldconfig -p shows the current contents of the cache. 


    Upgrading Shared Libraries

    Note: A new major or minor version of a library can be installed, even while running programs are making use of an existing version.

    Example - upgrading a shared library with a new minor version (1.0.2):

    # gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c # gcc -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.2 \
            mod1.o mod2.o mod3.o # mv libdemo.so.1.0.2 /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.2 (changed)
    

    Assuming the linker name was already correctly set up, we do not need to modify it.

    Then upgrading to a new major version (2.0.1):

    # gcc -fPIC -g -c -Wall mod1.c mod2.c mod3.c # gcc -shared -Wl,-soname,libdemo.so.2 -o libdemo.so.2.0.1 \
            mod1.o mod2.o mod3.o # mv libdemo.so.2.0.1 /usr/lib # ldconfig -v | grep libdemo libdemo.so.1 -> libdemo.so.1.0.2
            libdemo.so.2 -> libdemo.so.2.0.1 (changed)      
    # cd /usr/lib # ln -sf libdemo.so.2 libdemo.so 
    

    ldconfig automatically creates a soname symbolic link, but we must manually update the linker name symbolic link. 


    Finding Shared Libraries at Run-time

    The dynamic linker searches for shared libraries in the following order:

    1. If LD_LIBRARY_PATH is defined, then each of the colon-separated directories listed in its value is searched in turn. 

    2. /etc/ld.so.cache is checked to see if it contains an entry for the library. 

    3. /lib and /usr/lib are searched (in that order).


    英文通俗易懂,大致总结一下:
    1.gcc编译编译选项-soname 为实际库文件(libsoname.so.major.minor)生成的别名,这个别名 libname.so.major,别名存放在 实际库文件的头部,执行readelf -d  libsoname.so.major.minor命令可以看到“0x0000000e (SONAME)                     Library soname: [libname.so.major]”

    2.执行ldconfig -n /current_dir命令,ldconfig会去读取 /curr ent_dir目录下所有动态库文件中(SONAME)信息,并生成指向各动态库文件的链接文件,链接文件的名字为相应 (SONAME)字段值(libname.so.major)。

    3.如果/current_dir被加入到/etc/ld.so.conf或/etc/ld.so.conf.d/中,则执行ldconfig -v命令可生成/current_dir目录下所有的SONAME链接文件并查看繁多的链接信息。

    4.连接器(linker)通过SONAME字段值( libname.so.major)在用户指定的路径查找链接 libname.so.major

    5.手动指定 libname.so --> libname.so.major,控制程序(progam)链接的 实际库文件( libsoname.so.major.minor),在/current_dir目录下我们会看到形如,
    libname.so  -->  libname.so.major
    libname.so.major -->  libname.so.major.minor
    的链接,其中仅
    libname.so.major.minor为规则文件。

    6.动态库的主、次版本号利用如下的一套约定即可实现动态库的版本管理。
    a.新生成库实际文件libname.so.major.minor,当
    库中函数接口未变化(更新不影响相关模块)主版本号major不改变,次版本号       minor加1。
    b. 库中函数接口变化(更新影响相关模块 )主版本号major加1 ,次版本号从0开始增加。
    c.当出现新旧版本共存情况
        libname.so.1 --> libname.so.1.2
        libname.so.2--> libname.so.2.0
    时需用户通过手动建立链接(libname.so链接libname.so.1还是libname.so.2),决定程序链接动态库。

    7.实际项目中可通过Makefile文件管理项目的动态库版本,具体实施过程待实践。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在中,当共享库(shared library)的接口发生重大变化时,可能会进行"soname bump"操作。"soname"是指共享库的名字,它用于标识库的版本和接口。 Soname bump是指对共享库进行更改,需要修改库的soname,以指示接口的变化。这样做的目的是为了确保旧的二进制程序仍然可以与旧版本的库保持兼容,而新的二进制程序则可以链接到新版本的库。 Soname bump通常涉及以下步骤: 1. 修改共享库的接口:在进行soname bump之前,可能会对共享库的接口进行更改,例如添加、删除或修改函数的签名、结构体的布局等。这些更改会导致旧版本的二进制程序无法与新版本的库兼容。 2. 修改共享库的soname:将共享库的soname更改为反映接口变化的新版本号。soname通常遵循一定的命名约定,例如使用lib<name>.so.<version>的形式,其中<name>是库的名称,<version>是库的版本号。 3. 重新编译和链接依赖于共享库的二进制程序:在soname bump之后,依赖于共享库的二进制程序需要重新编译和链接,以便它们可以使用新的接口。 4. 兼容性处理:为了确保向后兼容性,可以采取一些措施,如提供符号版本控制(Symbol Versioning)或使用动态符号表(Dynamic Symbol Table)。这些机制可以在运行时动态地加载适当版本的共享库。 进行soname bump操作时,需要谨慎处理,并与相关的二进制程序开发者和用户进行充分的沟通和测试,以确保过渡过程中的兼容性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值