骚操作:利用强弱符号制作插件库
當有強符號和弱符號時,選擇使用強符號
那么我們正可以利用這個原則做以下事情:
定義為弱符號,如果是弱符號,使用默認行為
如果鏈接了庫,是強符號,則使用外部定義行為
以此來實現一個類似插件的功能。通俗一點說:
當沒有插件時,使用默認行為
鏈接了插件時,使用插件的功能
原理和示例
其原理也非常簡單:
外部引用弱符號
如果符號地址為0,則說明外部沒有鏈接插件庫,未有強符號,走默認流程
如果符號地址不為0,則說明鏈接了插件庫,執行插件庫的功能。
示例程序如下:
#include __attribute__((weak))?void?my_print();void?test_print() {//?如果是強符號,說明鏈接了外部插件,使用外部定義if(my_print){my_print();}else{//?弱符號,走默認邏輯printf("this?is?weak?print\n");} } int?main(void) {test_print();return?0; }上面的test_print函數是弱符號,在沒有其他地方定義的情況下,也是能夠正常編譯運行的:
$?gcc?-o?main?main.c $?./main this?is?weak?print觀察可執行文件:
$?nm?main?|grep?my_printw?my_print通過nm命令我們也可以知道test_print是弱符號,它前面的修飾字符是W,代表weak。
插件庫
前面的示例程序已經能否工作了,如何讓它能否支持插件庫呢?或者說,如何讓它支持外部的插件功能呢?
這里以靜態庫為例:
//?print_plugin.c #include void?my_print() {printf("this?is?plugin?print\n"); }制作靜態庫:
$?gcc?-c?print_plugin.c $?ar?-rcs?libprint_plugin.a?print_plugin.o鏈接插件庫
現在重新編譯main程序,并使用插件庫:
$?gcc?-o?main?main.c?-L./?-lprint_plugin $?gcc??-o?main??main.c??-L.?-Wl,--whole-archive?-lprint_plugin?-Wl,--no-whole-archive $?nm?main?|grep?my_print 000000000000067a?T?my_print $?./main this?is?plugin?print需要注意的是,這里在鏈接插件庫之前,需要加上:
-Wl,--whole-archive該選項會將插件庫中所有符號都鏈接進來,若非如此,在main.c中已經有了my_print符號,將不會鏈接進來,而在此之后,又要將該選項恢復。最終我們可以通過nm命令看到my_print符號已經不再是W了。也就看到了最后:
this?is?plugin?print的打印了。
也就實現了我們所謂插件的功能,換句話說,可以對目標程序進行功能的裁剪或者增加。
總結
由于以下幾點原因,我們可以自己做一些支持插件庫的程序:
1.重復強弱符號同存在時,使用強符號
2.弱符號鏈接不存在時,不會報錯
3.未鏈接的外部符號,地址為0,可通過判斷避免訪問非法地址
再結合前面的例子分別解釋一下:
1.在開始的程序中,即便沒有鏈接插件庫,程序也可以正常編譯鏈接通過,而不會報錯
2.沒有鏈接插件庫時,由于其函數地址為0,因此,我們程序內判斷,if(xxx),當地址為0時,執行默認的行為語句。
聲明:
本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的骚操作:利用强弱符号制作插件库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iPhone 14 Pro息屏显示时间设
- 下一篇: 函数或全局变量重复定义时会怎样?