簡體   English   中英

使用RTLD_DEEPBIND動態加載共享庫

[英]Dynamic loading of shared library with RTLD_DEEPBIND

背景:我有應用程序哪個部分用作其他獨立應用程序的庫。 它們在鏈接時間鏈接到該庫(比如lib.so)。 這種方法的問題是我們必須使用相同的外部庫,如boost,ace等,否則我們將有重復的符號,最終會導致崩潰。 我們想解決這個問題。

我知道兩種技術 - 一種是隱藏所有符號(不確定共享庫的全局/本地范圍的順序),另一種是使用動態鏈接。 我們選擇了第二個選項(動態鏈接),因為它為客戶提供了使用存根lib.so進行簡單測試的機會。 我們有非常簡單的api。

我在下面寫了一個小的應用程序示例,它加載了示例共享庫並且崩潰了(我想了解它崩潰的原因以及它應該如何編寫)。 崩潰是在dlopen中,恰好在分配給std :: string(Aclass類型的構造函數)的全局變量的初始化中。 從我們的測試中可以看出,在繼續初始化庫時對std庫的任何訪問都會導致崩潰。

我們設法通過向EXECUTABLE添加-fPIC標志來刪除崩潰(為什么這解決了我們的問題,我認為它應該設置為共享庫,任何人都可以更准確地解釋我)? 不必理解這個標志是有問題的,因為它減慢了應用程序,在我的情況下(低延遲應用程序)它是很成問題的。

總結:1。為什么會發生這種崩潰? 2.為什么-fPIC標志足以解決此崩潰問題? 3.為什么將-fPIC標志設置為可執行文件就足夠了? 4.是否有可能以其他方式解決我的問題,因此共享庫和客戶端應用程序可以使用不同版本的庫(如boost,ace等,編譯器,linux版本和std庫保證相同)? 5.刪除標志RTLD_DEEPBIND也會修復崩潰但是從gcc man看起來我應該使用這個標志,因為它會改變共享庫的符號范圍順序 - 首先它會在本地范圍內搜索符號然后在全局 - 看起來對我來說必須有因為共享庫將使用與可執行文件不同的外部庫(動態加載將保護可執行文件並污染其符號范圍)。 為什么在這個簡單的情況下刪除此標志會修復崩潰

共享庫dynLib.cpp:

#include <string>
class Aclass
{
    std::string s;
    s = "123";
}

Aclass a;

Exacutable main.cpp:

#include <stdlib.h>
#include <dlfcn.h>
#include <string>
#include <unistd.h>
#include <iostream>

int main()
{
    std::string dummyCrasher;
    dlerror();
    void* handle = dlopen("./libdynLib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
    if(!handle)
    {
        std::cout << "handle is null" << dlerror();
    }

    usleep(1000 * 1000 * 10);
}  

Makefile:makefile

CXXFLAGS=-m32 -march=x86-64 -Wl,v -g -O3 -Wformat -Werror=format -c
CLINKFLAGS=-Wl,-Bstatic -Wl,Bdynamic -ldl -m32 -march=x86-64

all: dynLib.so dynamiclinking

dynLib.so: dynLib.o
    g++44 $(CLINKFLAGS) -shared -o libdynLib.so dynLib.o

dynLib.o: dynLib.cpp
    g++44 $(CXXFLAGS) dynLib.cpp

dynamiclinking: main.o
    g++44 $(CLINKFLAGS) -o dynamiclinking main.o -ldl

main.o: main.cpp
    g++44 (CXXFLAGS) main.cpp

.PHONY: clean
clean:
    rm dynLib.o main.o dynamiclinking libdynLib.so

PS。 我手工編寫代碼(可以做一些拼寫錯誤)PS 2.使用-fPIC標志它會起作用:

main.o: main.cpp
    g++44 (CXXFLAGS) main.cpp -fPIC

更新可以通過libstdc ++的靜態鏈接解決此問題。 但仍然我的問題沒有回答:(也許有人有時間看看它?

UPDATE2 GCC 4.4.6和4.8.1也出現同樣的問題。

我認為您遇到的問題與我們應該使用RTLD_DEEPBIND時的問題相同 ,可執行文件獲取全局變量的副本:

那么這是你在沒有 -fPIC選項的情況下構建主應用程序的一個很棒的功能。 [...]這意味着當在libdep.so找到符號時,它會被復制到該地址的主可執行文件的初始數據段中。 然后查找libdep.so duplicate引用,它指向主可執行文件中的符號副本。

由於RTLD_DEEPBIND ,dynLib.so在初始化std::string時會從原始libstdc ++中看到錯誤的全局變量集,從而導致崩潰。

至於為什么鏈接器有這種行為, 本文有一個詳細的解釋(強調我的):

回想一下,程序/可執行文件不可重定位,因此其數據地址必須在鏈接時綁定。 因此,鏈接器必須在程序的地址空間中創建變量的副本,動態加載程序將使用它作為重定位地址。 這類似於上一節中的討論 - 從某種意義上說, myglob中的myglob會覆蓋共享庫中的myglob ,並且根據全局符號查找規則,它將被替代使用。

最后要注意的是:這種行為是特定於平台的,至少在PowerPC上,主可執行文件中沒有這樣的額外全局變量副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM