您好,登錄后才能下訂單哦!
需求描述:業務提供一個鑒權的靜態庫,我只需要從url 和 參數中提取相應的參數傳給業務的靜態庫,將靜態庫的處理結果直接返回給業務(return < 0, 直接返回403)。
但是最近業務反饋,請求部分url直接返回Error:-1015錯誤,不符合預期。
業務剛開始反饋問題,我的第一反應:怎么可能是我的問題,我就僅僅寫了一個so(暫時命名1.so),直接調用了你們靜態庫,這個-1015不就是你們庫返回的結果。 有問題也是業務提供的庫有問題。 或者就是業務配置不正確。
我臨時解決方案:
最后還是走到方案3,業務說printf的結果不符合預期,經業務提醒,突然意識到是不是調用鏈接到其他庫的xx_func?
因為項目比較大, 涉及的庫比較多,我用nm認真檢查了編譯時加載的庫,竟然還真找到一模一樣的接口xx_func
nm ./lib/liba.a | grep xx_func
編譯代碼的時候,趕緊去掉了同名函數庫(因為在makefile文件編譯的時候某些公共庫默認都會編譯進去)。重新編譯版本。
沒有想到,去掉同名函數庫,還是存在問題,為什么呢?到底是哪里的問題?
隨手直接 nm *.so | grep xx_func
,結果在另外一個so(暫時命名2.so)中,發現了同名函數xx_func。 看了一下配置,程序啟動的時候首先加載了2.so動態庫, 1.so是在2.so后面加載的. 因為優先加載哪個庫,就使用哪個庫的同名函數,并不會覆蓋的情況(自己現網測試 + 測試代碼)
到這里問題的原因也算是找到了,下面接著就是如何解決問題?
因為業務本身提供的靜態庫,用nm
查看函數也不多,為了安全起見,修改每個函數的名稱(增加一些業務私有的東西)。 批量修改函數名可直接使用sed
現在C/C++這一塊有幾十年的歷史,該踩的坑大家都應該踩過去了。gcc編譯器就直接提供-fvisibility=hidden
編譯選項,直接讓庫函數global可見變成local可見, 使用__attribute__((visibility("default")))
直接將需要的函數暴漏在外面就行
-fvisibility=[default|internal|hidden|protected]
Set the default ELF image symbol visibility to the specified option---all symbols are marked with this unless overridden within the code. Using this feature can very substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export and prevent symbol clashes. It is strongly recommended that you use this in any shared objects you distribute.
A good explanation of the benefits offered by ensuring ELF symbols have the correct visibility is given by "How To Write Shared Libraries" by Ulrich Drepper (which can be found at <http://www.akkadia.org/drepper/>)---however a superior solution made possible by this option to marking things hidden when the default is public is to make the default hidden and mark things public.將默認ELF符號可見性設置為指定選項---除非在代碼中覆蓋,否則所有符號都標記為此。 使用此功能可以極大地改善共享對象庫的鏈接和加載時間,生成更優化的代碼,提供近乎完美的API導出并防止符號沖突。 強烈建議您在分發的任何共享對象中使用它
Ulrich Drepper的“如何編寫共享庫”(可在<http://www.akkadia.org/drepper/>上找到)中給出了確保ELF符號具有正確可見性所帶來的好處的一個很好的解釋 - - 當默認為公共時,通過此選項可以標記隱藏的內容的優秀解決方案是隱藏默認值并將事物標記為公共
.
├── libqqmusic.c
├── libtmemusic.c
├── main
├── main.c
├── makefile
└── README.md
//libqqmusic.c
#include<stdio.h>
int get_music_id()
{
return 1111;
}
void qqmusic_print()
{
printf("qqmusic id: %d\n", get_music_id());
return;
}
//libtmemusic.c
#include<stdio.h>
int get_music_id()
{
return 2222;
}
void tmemusic_print()
{
printf("tmemusic id: %d\n", get_music_id());
return;
}
//main.c
#include<stdio.h>
int main(int argc, char *argv[])
{
printf("start\n");
tmemusic_print();
qqmusic_print();
tmemusic_print();
printf("end\n");
return 0;
}
# 1. create /etc/ld.so.conf.d/vaynedu-test.conf
# /usr/lib64/vaynedu
# 2. mkdir /usr/lib64/vaynedu
#
# 3. \cp *.so /usr/lib64/vaynedu
all:
gcc -g -fpic -c -o libqqmusic.o libqqmusic.c
gcc -g -shared -o libqqmusic.so libqqmusic.o
gcc -g -fpic -c -o libtmemusic.o libtmemusic.c
gcc -g -shared -o libtmemusic.so libtmemusic.o
\cp *.so /usr/lib64/vaynedu
@ldconfig
#gcc -g -o main main.c -L. -lqqmusic -ltmemusic
gcc -g -o main main.c -L. -ltmemusic -lqqmusic
@echo -e "\n\ncompile complete\n\n"
clean:
rm -fr *.so *.o
將tmemusic放在前面gcc -g -o main main.c -L. -ltmemusic -lqqmusic
將qqmusic放在前面gcc -g -o main main.c -L. -lqqmusic -ltmemusic
《程序的自我修養-鏈接、裝載與庫》應該好好的啃一遍, 這個一個后臺開發必備的知識技能
-fvisibility=hidden的用法 https://blog.csdn.net/caspiansea/article/details/77113066
多共享動態庫中同名對象重復析構問題的解決方法 https://www.ibm.com/developerworks/cn/linux/l-cn-sdlstatic/
GCC的符號可見性——解決多個庫同名符號沖突問題 http://blog.chinaunix.net/uid-27875-id-5759441.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。