Linux --靜態庫和動態庫的制作和原理

本章重點:

動靜態庫的制作,使用和查找

可執行程序ELF格式

可執行程序的加載過程

虛擬地址空間和動態庫加載的過程


動靜態庫的制作,使用和查找

? 1.在了解庫的制作之前,我們首先需要知道什么是庫。庫是寫好的現有的,成熟的,可以反復復用的代碼。有了庫我們只需要有頭文件和知道對應的調用方法就可以使用庫中的函數,不需要每次都造輪子手撕,我們平時使用的c/c++標準庫都是這樣封裝的庫,然后將頭文件暴露出來給用戶調用。

? 2.本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。庫分為靜態庫 .a[Linux]、.lib[windows],和動態庫.so[Linux]、.dll[windows]。

? 3.靜態庫:靜態庫(.a):程序在編譯鏈接的時候把庫的代碼鏈接到可執??件中,程序運?的時候將不再需要靜態庫,靜態庫可以理解為多個.o文件的集合。?個可執?程序可能?到許多的庫,這些庫運?有的是靜態庫,有的是動態庫,?我們的編譯默認為動態鏈接庫,只有在該庫下找不到動態.so的時候才會采?同名靜態庫。我們也可以使? gcc的 -static 強轉設置鏈接靜態庫。

? 這里使用之前在基礎IO文章中寫的mylib.c和mylib.h來封裝一個靜態庫。

? 需要先構造一個makefile文件幫助我們快速構造靜態庫,這里先用 ar 工具將 mylib.o 添加到libmylib.a 中,ar是gnu的一個歸檔工具,用于創建、修改、提取 .a 靜態庫文件。rc表示replace和create,表示如果這個庫存在就替換,不存在就創建它。

? 此時我們并沒有.o文件,所以還需要將.c文件編譯生成.o文件,%.o:%.c,這是一個通配規則,意思是:讓所有的 .c文件可以對應生成 .o 文件,此處只有一個.c文件,但是靜態庫可以由多個.o文件鏈接形成。

? 然后編寫一個清理指令即可。

? 執行make指令我們就得到了一個靜態鏈接庫

? 那么如何使用靜態鏈接庫呢?我們只需要在需要調用靜態庫函數的文件包含對應的頭文件,然后編譯的時候帶對應的庫即可,這里又有三種方法鏈接庫:

? (1)庫文件和頭文件都安裝在系統默認路徑,比如:頭文件在 /usr/include/,庫文件在 /usr/lib//usr/lib64/

? (2)庫文件和源文件在同一目錄下,直接使用指令g++?-o main?main.c. -L. -lmylib,-L告訴編譯器在當前目錄下尋找庫,-l鏈接名為libmylib.a的靜態庫

? (3)頭文件和庫文件分別在獨立目錄,此時mylib.h文件在Include文件中,libmylib.a在lib文件中,使用指令g++ -o main -main.c -Iinclude -Llib -lmylib,需要使用-I指定頭文件路徑,-L指定庫的路徑,-l指定連接哪個庫

? 注意形成執行程序以后即使刪除libmylib.a也可以正常運行可執行程序,因為靜態庫已經連接到可執行程序的內部了,所以我們可以看到的是此時的可執行程序會變得很大。

? 這里我們還可以在makefile內部使用指令將生成的靜態庫進行打包壓縮然后發送給別人使用,此時只需要解壓然后使用第三種方法也就是頭文件和庫文件分別在不同目錄就可以鏈接庫了。

? 所以我們完整的發布流程就是:先將.o文件鏈接成靜態庫,然后打包壓縮頭文件和靜態庫

? 4.動態庫:程序在運?的時候才去鏈接動態庫的代碼,多個程序共享使?庫的代碼。 ?個與動態庫鏈接的可執??件僅僅包含它?到的函數??地址的?個表,?不是外部函數所在?標?件的整個機器碼。在可執??件開始運?以前,外部函數的機器碼由操作系統從磁盤上的該動態庫中復制到內存中,這個過程稱為動態鏈接(dynamic linking) 。動態庫可以在多個程序間共享,所以動態鏈接使得可執??件更?,節省了磁盤空間。操作系統采?虛擬內存機制允許物理內存中的?份動態庫被要?到該庫的所有進程共?,節省了內存和磁盤空間

? 動態庫的生成過程與靜態庫類似,不一樣的是生成庫的指令以及生成.o文件的指令,shared: 表??成共享庫格式,fPIC:產?位置?關碼(position independent code) ,庫名規則:libxxx.s。

g++ -fPIC -c mylib.cpp -o mylib.o ? # 先編譯為位置無關的目標文件
g++ -shared -o libmylib.so mylib.o ?# 再鏈接為共享庫

? 動態庫的使用方法也有三種:

? (1)頭?件和庫?件安裝到系統路徑下,使用命令g++ main.c -lmylib即可鏈接動態庫

(2)頭文件與庫文件與源文件同目錄,使用命令g++ main.c -L. -lmylib

? (3)頭文件與庫文件分別有獨立的路徑,使用命令g++ main.c -Iinclude -Llib -lmylib,注意當前lib路徑下如果有同名動態庫和靜態庫優先會鏈接動態庫。

? 可以使用ldd 來查看鏈接了哪些庫,此時發現確實是鏈接了我們的動態庫

? 但是運行的時候發現報錯了,這是因為程序在運行時找不到共享庫 libmylib.so,因為Linux 默認只在系統路徑(如 /lib, /usr/lib)下查找共享庫,不會自動查找 -L 指定的路徑!

? 這里有三種方法可以解決,(1)拷貝.so文件到系統共享庫的路徑下 (2)向系統共享庫路徑下建立同名的軟連接 (3)更改環境變量 這里使用方法三來演示:

? 這樣就可以增加系統查找共享庫的路徑了。需要注意的是前面兩種方法操作以后都需要使用sudo ldconfig來更新系統共享庫的索引。

可執行程序ELF格式

? 在Linux之中有四種文件都是ELF格式的文件,有xxx.o文件,xxx.so文件,xxx可執行文件以及內核轉儲文件。一個ELF格式的文件由四個部分組成:

? (1)ELF頭:描述文件的主要特性,其文件的開始位置,它的最主要目的是定位文件的其他部分。

? (2)程序表頭:??列舉了所有有效的段(segments)和他們的屬性。表?記著每個段的開始的位置和位移(offset)、?度,畢竟這些段,都是緊密的放在?進制?件中,需要段表的描述信息,才能把他們每個段分割開。

? (3)節頭表(Section header table) :包含對節(sections)的描述。

? (4)節(Section ):ELF?件中的基本組成單位,包含了特定類型的數據。ELF?件的各種信息和 數據都存儲在不同的節中,如代碼節存儲了可執?代碼,數據節存儲了全局變量和靜態數據等。

可執行程序的加載過程

? ELF形成可執行程序分為以下兩部:(1)將多份c/c++源代碼翻譯成為.o文件 (2)將多份.o文件的section進行合并。

? 所以鏈接其實就像將一個個的相同屬性的section進行合并。

虛擬地址空間和動態庫加載的過程

? 一個可執行程序在加載到內存之前有沒有地址?進程mm_struct、vm_area_struct在進程剛剛創建的時候,初始化數據從哪?來的?個ELF程序,在沒有被加載到內存的時候,本來就有地址,當代計算機?作的時候,都采?"平坦模式"進??作。所以也要求ELF對??的代碼和數據進?統?編址,下?是 objdump -S 反匯編之后的代碼

? 左側的就是ELF的虛擬地址,其實,嚴格意義上應該叫做邏輯地址(起始地址+偏移量), 但是我們認為起始地址是0.也就是說,其實虛擬地址在我們的程序還沒有加載到內存的時候,就已經把可執?程序進?統?編址了.

? 進程mm_struct、vm_area_struct在進程剛剛創建的時候,初始化數據從哪?來的?從ELF各個 segment來,每個segment有??的起始地址和??的?度,?來初始化內核結構中的[start, end]等范圍數據,另外在?詳細地址,填充?表。

? 所以虛擬地址空間是cpu/編譯器/OS協調操作下的共同產物。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87926.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87926.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87926.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

50天50個小項目 (Vue3 + Tailwindcss V4) ? | IncrementingCounter(遞增計數器)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— IncrementingCounter組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API 和 <script setup&g…

簡約求職簡歷競聘工作求職PPT模版共享

簡歷競聘&#xff0c;自我介紹&#xff0c;個人簡歷&#xff0c;工作求職PPT模版&#xff0c;崗位競聘求職簡歷PPT模版&#xff0c;低調綠自我介紹PPT模版&#xff0c;簡約求職簡歷PPT模版&#xff0c;個人介紹PPT模版&#xff0c;我的簡歷PPT模版&#xff0c;個人求職簡介PPT模…

Java大廠面試攻略:Spring Boot與微服務架構深度剖析

問題一&#xff1a;Spring Boot 的自動配置原理是什么&#xff1f; 簡潔面試回答&#xff1a; Spring Boot 的自動配置基于條件化配置&#xff0c;通過 Conditional 注解實現&#xff0c;根據項目中依賴和環境自動裝配 Bean。 詳細解析&#xff1a; Spring Boot 自動配置的核…

Windows核心端口攻防全解析:135、139、445端口的技術內幕與安全實踐

Windows核心端口攻防全解析&#xff1a;135、139、445端口的技術內幕與安全實踐 引言&#xff1a;Windows網絡通信的命脈 在Windows網絡生態系統中&#xff0c;135、139和445端口猶如網絡通信的"大動脈"&#xff0c;承載著關鍵的系統服務和網絡功能。這些端口不僅是…

從生活場景學透 JavaScript 原型與原型鏈

一、構造函數&#xff1a;以 “人” 為例的對象工廠 1. 生活場景下的構造函數定義 我們以 “人” 為場景創建構造函數&#xff0c;每個人都有姓名、年齡等個性化屬性&#xff0c;也有人類共有的特征&#xff1a; // 人類構造函數 function Person(name, age) {this.name na…

學c++ cpp 可以投遞哪些崗位

此次描述知識針對應屆生來說哈&#xff0c;如果是社招&#xff0c;更多是對于你目前從事的方向&#xff0c;技術棧進行招聘就好了。 此次編寫是按照boss上崗位篩選的方式進行編寫的&#xff0c;其實投簡歷一般也是用boss&#xff0c;后面也會出一篇文章給大家介紹一般找工作都用…

【Docker基礎】Docker鏡像管理:docker rmi、prune詳解

目錄 引言 1 Docker鏡像管理概述 1.1 為什么需要鏡像清理&#xff1f; 1.2 鏡像生命周期管理 2 docker rmi命令詳解 2.1 基本語法 2.2 常用選項 2.3 刪除單個鏡像 2.4 刪除多個鏡像 2.5 強制刪除鏡像 2.6 刪除所有鏡像 3 docker rmi工作原理 3.1 鏡像刪除流程 3.…

57-Oracle SQL Profile(23ai)實操

在上一期中說到了SQL Tuning Advisor其中一個影響對象就是SQL Profile&#xff0c;同樣在管理和應用開發中,SQL性能優化是個任重道遠的工作&#xff0c;低效的SQL語句讓應用響應緩慢,用戶整體體驗下降,拖垮搞蹦整個系統都有可能。Oracle數據庫提供了多種組合工具&#xff0c;有…

man的使用

man的使用 文章目錄 man的使用基本用法&#xff1a;常見 man 命令操作&#xff1a;man 命令的章節&#xff1a;示例&#xff1a; man 是 Linux 和 macOS 系統中的命令&#xff0c;用于查看命令和程序的手冊頁&#xff08;manual pages&#xff09;。手冊頁包含了關于命令、函…

【藍牙】手機連接Linux系統藍牙配對,Linux Qt5分享PDF到手機

要實現手機連接 A40i Linux 系統并通過藍牙接收 PDF 文件&#xff0c;可以按照以下步驟操作&#xff1a; 1. 配置 Linux 藍牙功能 確保開發板上的藍牙模塊已正確驅動并支持藍牙協議棧。 安裝藍牙工具&#xff1a; bash sudo apt install bluetooth bluez bluez-tools 啟動藍…

1432. 改變一個整數能得到的最大差值

1432. 改變一個整數能得到的最大差值 題目鏈接&#xff1a;1432. 改變一個整數能得到的最大差值 代碼如下&#xff1a; class Solution { public:int maxDiff(int num) {string s to_string(num);function<int(char, char)> replace_stoi [&](char old_char, cha…

解密 Spring MVC:從 Tomcat 到 Controller 的一次完整請求之旅

今天&#xff0c;想和你聊一個我們每天都在打交道&#xff0c;但可能不曾深入思考的話題&#xff1a;當一個 HTTP 請求從瀏覽器發出&#xff0c;到最終被我們的 Spring Controller 處理&#xff0c;它到底經歷了一場怎樣的旅程&#xff1f; 理解這個流程&#xff0c;不僅僅是為…

在 Java 中操作 Map時,高效遍歷和安全刪除數據

在 Java 中操作 Map 時&#xff0c;高效遍歷和安全刪除數據可以通過以下方式實現&#xff1a; 一、遍歷 Map 的 4 種高效方式 1. 傳統迭代器&#xff08;Iterator&#xff09; Map<String, Integer> map new HashMap<>(); map.put("key1", 5); map.pu…

力扣-136.只出現一次的數字

題目描述 給你一個 非空 整數數組 nums &#xff0c;除了某個元素只出現一次以外&#xff0c;其余每個元素均出現兩次。找出那個只出現了一次的元素。 你必須設計并實現線性時間復雜度的算法來解決此問題&#xff0c;且該算法只使用常量額外空間。 class Solution {public i…

Go 網絡編程:HTTP服務與客戶端開發

Go 在標準庫中內置了功能強大的 net/http 包&#xff0c;可快速構建高并發、高性能的 HTTP 服務&#xff0c;廣泛應用于微服務、Web后端、API中間層等場景。 一、快速創建一個HTTP服務 示例&#xff1a;最簡Hello服務 package mainimport ("fmt""net/http&quo…

【Prism】 實現注入的幾個標準化步驟(相機舉例)

?? Prism 架構中如何優雅地注冊和注入相機服務 在開發基于 Prism + WPF 的應用時,合理使用依賴注入(DI)可以大大提高系統的可維護性和擴展性。本文以一個多相機平臺管理系統為例,展示如何通過接口、枚舉、容器注冊等方式,實現相機服務的靈活配置與使用。 ?? 一、定義…

vue3組件式開發示例

1&#xff0c;定義組件&#xff08;根據實際調整提交分析結果方法&#xff09; <template><!-- 分析結果上傳對話框組件 --><el-dialogv-model"uploadResultDialog":title"title":width"width":before-close"handleBeforeC…

基于arm linux的bluealsa開啟藍牙A2DP和SCO錄音功能

bluealsa的軟件架構 #mermaid-svg-ohITacCRHItwRR1t {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ohITacCRHItwRR1t .error-icon{fill:#552222;}#mermaid-svg-ohITacCRHItwRR1t .error-text{fill:#552222;stroke:…

網頁后端開發(基礎3--Springboot框架)

web的服務器資源&#xff1a; 靜態資源&#xff1a;服務器上存儲的不會改變的數據&#xff0c;通常不會根據用戶的請求而變化。比如&#xff1a;HTML、CSS、JS、圖片、視頻等&#xff08;負責頁面展示&#xff09; 動態資源&#xff1a;服務器端根據用戶請求和其他數據…

ROS通過urdf_to_graphiz對urdf和xacro文件進行結構可視化

對機器人的urdf文件進行結構可視化&#xff1a; 舉例命令如下&#xff1a; urdf_to_graphiz go2_description.urdf 輸出 .gv 和 .pdf文件&#xff0c;打開 pdf文件如圖&#xff1a;