Glibc

在一個發行版上建構二進製文件以在另一個發行版上執行

  • August 15, 2022

我想在 docker 容器上建構一個非常簡單的命令行客戶端應用程序,以將該應用程序提供給客戶。該應用程序使用來自 PEAK(製造此適配器的公司)的 CAN 到 USB 適配器。PEAK 提供了一個庫 (libpcanbasic),應用程序使用該庫來訪問 CAN 匯流排。

為了建構 libpcanbasic 庫,必須安裝適配器的驅動程序。我使用分階段的 docker 容器,我首先在其中建構 libpcanbasic.so 庫。然後我使用第二階段來擁有一個帶有更新的 GCC (gcc:12.1.0-bullseye) 的容器。

不,我遇到了麻煩,連結我的應用程序。libpcanbasic.so 依賴於不屬於第二階段容器的 libc 版本/風格:

# readelf -d /usr/lib/libpcanbasic.so

Dynamic section at offset 0x189b8 contains 25 entries:
 Tag        Type                         Name/Value
0x0000000000000001 (NEEDED)             Shared library: [libc.musl-aarch64.so.1]
0x000000000000000e (SONAME)             Library soname: [libpcanbasic.so]
0x000000007ffffffd (AUXILIARY)          Auxiliary library: [visibility=hidden]
0x000000000000000c (INIT)               0x3f38
0x000000000000000d (FINI)               0x121f0
0x0000000000000019 (INIT_ARRAY)         0x28998
0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
0x000000000000001a (FINI_ARRAY)         0x289a8
0x000000000000001c (FINI_ARRAYSZ)       16 (bytes)
0x000000006ffffef5 (GNU_HASH)           0x190
0x0000000000000005 (STRTAB)             0x1638
0x0000000000000006 (SYMTAB)             0x558
0x000000000000000a (STRSZ)              2719 (bytes)
0x000000000000000b (SYMENT)             24 (bytes)
0x0000000000000003 (PLTGOT)             0x28b88
0x0000000000000002 (PLTRELSZ)           3096 (bytes)
0x0000000000000014 (PLTREL)             RELA
0x0000000000000017 (JMPREL)             0x3320
0x0000000000000007 (RELA)               0x20d8
0x0000000000000008 (RELASZ)             4680 (bytes)
0x0000000000000009 (RELAENT)            24 (bytes)
0x0000000000000018 (BIND_NOW)           
0x000000006ffffffb (FLAGS_1)            Flags: NOW
0x000000006ffffff9 (RELACOUNT)          185
0x0000000000000000 (NULL)               0x0

我可以將該 libc 文件 (libc.musl-aarch64.so.1) 複製到/lib第二階段容器中,然後連結就可以了:

# readelf -d ./build/client/bootloader_client 

   Dynamic section at offset 0x14da8 contains 29 entries:
     Tag        Type                         Name/Value
    0x0000000000000001 (NEEDED)             Shared library: [libpcanbasic.so]
    0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
    0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
    0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
    0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
    0x000000000000000c (INIT)               0x402d98
    0x000000000000000d (FINI)               0x40e670
    0x0000000000000019 (INIT_ARRAY)         0x424d78
    0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
    0x000000000000001a (FINI_ARRAY)         0x424d88
    0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
    0x0000000000000004 (HASH)               0x400278
    0x000000006ffffef5 (GNU_HASH)           0x4005d0
    0x0000000000000005 (STRTAB)             0x4010d0
    0x0000000000000006 (SYMTAB)             0x400620
    0x000000000000000a (STRSZ)              4274 (bytes)
    0x000000000000000b (SYMENT)             24 (bytes)
    0x0000000000000015 (DEBUG)              0x0
    0x0000000000000003 (PLTGOT)             0x424fe8
    0x0000000000000002 (PLTRELSZ)           2448 (bytes)
    0x0000000000000014 (PLTREL)             RELA
    0x0000000000000017 (JMPREL)             0x402408
    0x0000000000000007 (RELA)               0x402318
    0x0000000000000008 (RELASZ)             240 (bytes)
    0x0000000000000009 (RELAENT)            24 (bytes)
    0x000000006ffffffe (VERNEED)            0x402268
    0x000000006fffffff (VERNEEDNUM)         3
    0x000000006ffffff0 (VERSYM)             0x402182
    0x0000000000000000 (NULL)               0x0            

但我想,當我嘗試在其他地方執行生成的二進製文件時,我會遇到問題。

為什麼應用程序和共享對象(libpcanbasic.so)不依賴於libc.so?為什麼是非常具體的版本?這可以改變嗎?而且,如果我想為客戶提供二進製文件,最佳實踐是什麼?

最好的問候,托斯滕

您的庫最終不會“僅依賴於libc.so”,因為它是使用musl libc建構的(我猜您的第一階段使用的是基於 Alpine 的容器映像)。您的應用程序不依賴於libc.so任何一個,它取決於libc.so.6哪個是GNU C 庫(它是基於 Debian 建構的,預設為 GNU C 庫)。

由於您習慣於容器建構,因此向客戶提供二進製文件的最佳實踐是使用與您要支持的目標相對應的容器映像來建構它們。據我所知,由於您的庫沒有任何特定的依賴項,因此您可以通過使用較舊的基於 GNU C 庫的發行版建構它來簡化維護負擔(建構一個可在具有相同庫版本的任何發行版上使用的庫或稍後),如果您想支持基於 musl 的目標,則可以使用基於 musl 的發行版。

如果您繼續進行多階段建構,您至少應該確保所有階段都基於相同的映像(或兼容的映像)。

引用自:https://unix.stackexchange.com/questions/713652