編譯等底層知識

目錄

一. GCC命令語句大全

二. GCC編譯4個階段

三. makefile的使用

四. CMake

五.?GNU工具鏈開發流程圖?

六. Keil中的地址段

七. 靜態庫和動態庫


一. GCC命令語句大全

-c只編譯源文件,生成目標文件(.o?文件),不進行鏈接。
-o <file>指定輸出文件的名稱。
-g生成調試信息,用于調試程序
-Wall打開所有警告提示。
-I <dir>添加頭文件搜索路徑。
-L <dir>添加庫文件搜索路徑。
-l <library>鏈接指定的庫文件。
-std=<standard>指定使用的語言標準,如?-std=c99
-0<level>優化級別,如?-O0(無優化)、-O1(基本優化)、-O2(更高級別優化)。
-D<macro>定義預處理宏。
-E只進行預處理,輸出預處理結果。
-S只進行編譯,生成匯編代碼。
-shared生成共享庫(動態鏈接庫)。
-static生成靜態可執行文件,使用靜態鏈接。
-pthread鏈接 POSIX 線程庫。
-lm鏈接數學庫。
-fopenmp啟用 OpenMP 并行編程支持。

二. GCC編譯4個階段

GCC不僅僅是一個編譯器,它還包括預處理器、匯編器以及鏈接器,可以處理從代碼編寫到可執行程序生成的整個流程。

三. makefile的使用

先新建一個main.c

#include "stdio.h"int add(int a, int b);
int main()
{printf("num:%d\r\n",add(1,2));return 0;}

再新建一個math.c?

int add(int a, int b)
{return (a + b);
}

編譯永遠都是以單個源文件為單位的。這里我們先編譯一下mian.c文件。編譯生成的.o文件是一個二進制文件,文件格式是ELF(Linux下所有可執行文件的通用格式),Windows使用的是PE格式,(都是對二進制代碼的封裝)

我們可以在文件頭部找到可執行文件的基本信息比如支持的操作系統,機器類型等

查看一系列的區塊,.text是代碼區.data是數據區(里面保存了我們初始化的全局變量,局部靜態變量等等),

查看main.o這個目標文件中的內容,這里call指令是之前調用的printf和add函數,但是它們的跳轉地址都被設為了0,而這里的0會在后面鏈接的時候被修正。

另外為了讓編譯器能夠定位到這些需要被修正的地址,在代碼塊中我們還可以找到一個重定位表,比如在.text區塊中,找到被重定位的兩個函數printf和add。

接下來編譯math.c且連同main.o一起鏈接生成一個獨立的可執行文件

gcc main.o math.o -o main

鏈接其實就是將編譯之后的所有目標文件,連同用到的一些靜態庫,運行時庫,組合拼裝成一個獨立的可執行文件,其中就包括之前說到的地址修正,在這個時候,連接器會根據我們的目標文件或者靜態庫中的重定位表,找到那些需要被重定位的函數,全局變量,從而修正它們的地址

但如果我們每次都要手動編譯和鏈接就不高效,所以我們就得使用makefile,而makefile的核心是對"依賴"的管理,所以makefile其實就是在定義一顆依賴樹。

新建一個makefile文件,具體makefile可以查看二. MakeFile-CSDN博客

堆makefile文件進行一定優化

1. 使用makefile變量

2. “%”表示長度任意的非空字符串,比如“%.c”就是所有的以.c 結尾的 文件,類似與通配符,a.%.c 就表示以 a.開頭,以.c 結束的所有文件。如 %.o : %.c

3. makefile自動化變量

4.?Makefile 偽目標

自動化變量描述
$@規則中的目標集合,在模式規則中,如果有多個目標的話,“$@”表示匹配模 式中定義的目標集合。
$%當目標是函數庫的時候表示規則中的目標成員名,如果目標不是函數庫文件, 那么其值為空。
$<依賴文件集合中的第一個文件,如果依賴文件是以模式(即“%”)定義的,那么 “$<”就是符合模式的一系列的文件集合。
$??所有比目標新的依賴目標集合,以空格分開。
$^所有依賴文件的集合,使用空格分開,如果在依賴文件中有多個重復的文件, “$^”會去除重復的依賴文件,值保留一份。
$+和“$^”類似,但是當依賴文件存在重復的話不會去除重復的依賴文件。
$*這個變量表示目標模式中"%"及其之前的部分,如果目標是 test/a.test.c,目標模 式為 a.%.c,那么“$*”就是 test/a.test。
all:main#我們最終需要的mian文件
objects =  main.o math.o
main:$(objects) #main文件是由main.o math.o而來gcc -o main $(objects)%.o : %.cgcc -c $<#main.o:main.c #main.o由main.c而來
#	gcc -c main.c
#math.o:math.c #math.math.c而來
#	gcc -c math.c.PHONY : cleanclean:rm *.orm main

接下來我們直接make就能生成最后的可執行文件.

四. CMake

CMake主要功能

1.配置和生成各大平臺的工程

2.生成makefile文件

因為makefile的配置與當前系統有關,如果要開發一個跨平臺的軟件所以我們使用cmake。

CMakeList.txt文件

cmake_minimum required(VERSION 3.10)
project(hello)
add_executable(hello main.cpp factorial.cpp printhello.cpp)

cmake . 之后,也能生成makefile文件這時候我們再make,就能生成可執行文件了。

五.?GNU工具鏈開發流程圖?

GNU工具鏈包括了一系列重要的組件,如GCC(GNU編譯器集合)、GNU Binutils、GNU Make和GDB等。

編譯:編譯器是armcc和armasm ,每個c/c++和匯編源文件編譯成對應的以“.o”為后綴名的對象文件。

鏈接:鏈接器armlink把各個.o文件及庫文件鏈接成一個映像文件“.axf”或“.elf”

格式轉換:一般來說Windows或Linux系統使用鏈接器直接生成可執行映像文件elf后,內核根據該文件的信息加載后,就可以運行程序了,但在單片機平臺上,需要把該文件的內容加載到芯片上,所以還需要對鏈接器生成的elf映像文件利用格式轉換器fromelf轉換成“.bin”或“.hex”文件,交給下載器下載到芯片的FLASH或ROM中。

六. Keil中的地址段

程序組件所屬類別
機器代碼指令Code
常量RO-data(Read Only data)
初值非0的全局變量RW-data(Read Write data)
初值為0的全局變量ZI-data(Zero Initialie data)
局部變量ZI-data的棧空間
使用malloc動態分配的空間ZI-data的堆空間

初值非0的全局變量和初值為0的全局變量其實就是數據區,而值為0的全局變量區又稱為bss段。

七. 靜態庫和動態庫

簡單的來說二者的區別:

  • 靜態庫:就是在編譯的時候直接將需要的代碼連接進可執行程序中去;

  • 動態庫:就是在需要調用其中的函數時,根據函數映射表找到該函數然后調入堆棧執行。當動態庫被加載到內存之后,一旦它的內存地址被確定,我們就可以去修正動態庫中的那些函數跳轉地址,也就是重定位,這些地址在程序加載之前不過只是一堆占位符而已,如果我們直接去修改代碼段中的跳轉地址,由于代碼段的內容被修改,自然就不能被其他進程所共享了,因為我們需要在內存中保存多個不同的副本,這剛好和節約內存的目標就背道而馳了,為了解決這個問題,動態鏈接采用了一種聰明的做法,不再修改代碼段,而是在數據段中專門預留一片區域用來存放函數的跳轉地址,它也被叫做全局偏移表

查看全局偏移表readelf -S ./libmath.so

got里面專門用來存放全局變量和函數的跳轉地址,于是我們在調用函數的時候,會首先查表,然后根據表中的地址來進行跳轉,這些地址會在動態庫加載的時候,被修改成為真正的地址,而查表的過程也很容易實現,由于全局偏移表與代碼段的相對位置是固定的,我們完全可以利用CPU的相對尋址來實現,有了全局偏移表,我們不再需要修改代碼段,因此代碼可以被所有進程共享,而全局偏移表雖然在每一個進程中保留一份副本,但由于占用空間很小,所以完全沒有問題,采用這種方式實現的動態鏈接也被叫做 PIC(地址無關代碼),換句話說我們的動態庫不需要做任何修改,被加載到任意內存地址都能夠正常運行,并且能夠被所有進程共享,這也是為什么之前我們給編譯器指定 -fPIC 參數的原因,另一方面由于動態鏈接在程序加載的時候需要對大量函數進行重定位,這一步是非常耗時的,為了進一步降低開銷,我們的操作系統還做了一些其他的優化,比如延遲綁定或者也叫PLT,與其在一開始就對所有函數進行重定位,不如將這個過程推遲到函數第一次被調用的時候,因為絕大多數動態庫中的函數可能在程序運行期間一次都不會被使用到。大概思路是,GOT中的跳轉地址默認會指向一段輔助代碼,它也被叫做樁代碼(Stub),在我們第一次調用函數的時候,這段代碼會負責查詢真正函數的跳轉地址,并且去更新GOT表,于是我們再次調用函數的時候,就會直接跳轉到動態庫中真正的函數實現。動態鏈接實際上將鏈接的整個過程,比如符號查詢、地址的重定位從編譯時推遲到了程序的運行時,更關鍵的是,它實現了二進制級別的代碼復用。

從上面的描述可以知道,靜態庫是我們MCU開發者常用的一種,而動態庫常用于Linux、Windows等開發場合

接下來我們創建一個動態鏈接庫。還是先創建一個main.c和math.c.

 gcc -shared  -fPIC math.c -o libmath.so//-shared 表明這是一個共享對象(共享對象),libmath.so是linux下動態庫的擴展名,windows下的動態庫就是我們熟悉的各種.dll文件,
 gcc main.c -lmath -L. -o main我們在編譯主程序的時候,我們需要指定一個-l參數,它告訴編譯器與之前建的libmath.so進行動態鏈接,這里在指定動態庫的時候,我們省略了前綴lib和擴展名.so,最后我們通過-L來指定動態庫所在的路徑,
在運行main時,會提示找不到libmath這個動態庫,這是因為linux默認只會去系統路徑下搜索動態庫
./main: error while loading shared libraries: libmath.so: cannot open shared object file: No such file or directory
解決辦法有
第一種,將動態庫拷貝到系統路徑下,但之后還得刪除這個文件所以不方便
另外一種是使用環境變量,將當前目錄添加到 LD_LIBRARY_PATH 環境變量中,這樣操作系統會先到我們指定的路徑下搜索,找不到的話再去搜索系統路徑。

下圖可以看到它成功調用了動態庫中的add函數并返回了正確的結果,那之前我們提到動態鏈接的一大優勢是允許我們單獨更新動態庫本身。?

這樣我們更新一下動態庫,對主程序不需要做任何修改,直接運行我們就可以看到剛才我們對動態庫的更新?

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

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

相關文章

CC++內存管理【new和delete操作符的詳細分析】【常見面試題】

C/C內存管理 1.C/C內存分布 我們先來看一段代碼&#xff0c;來了解一下C/C中的數據內存分布。 # include <stdlib.h>int globalVar 1; static int staticGlobalVar 1; // 比globalVar還要先銷毀,同一個文件下后定義的先析構 // 全局變量存在 數據段&#xff08;靜態…

[Unity]播放音頻卡頓問題

記錄一個問題&#xff1a; 游戲內播放完音頻A再去循環播放音頻B&#xff0c;在協程里使用等待n秒來實現拼接&#xff0c;發現在個別手機上會有卡頓的問題&#xff0c;盲猜是和幀率有關。 這是最初的實現方案&#xff1a; IEnumerator IEPlayAudio(){if(ASOnBeginDrag ! null)…

VSCode+Vite+Vue3斷點調試

目錄 lunch.json創建 vite.config.ts 打斷點運行 lunch.json創建 首先&#xff0c;點擊VSCode左上角&#xff0c;甲殼蟲運行的按鈕&#xff0c;然后點擊運行與調試&#xff0c;選擇chrome瀏覽器&#xff0c;修改成一下配置。 { // 使用 IntelliSense 了解相關屬性。 // 懸停…

codeforces round 949 div2

A Turtle and Piggy Are Playing a Game 題目&#xff1a; 思路&#xff1a;輸出2的冪次b使得2^b為最大的不超過x的數 代碼&#xff1a; #include <iostream>using namespace std;const int N 2e5 10;void solve() {int l, r;cin >> l >> r;if(r % 2) …

vscode 運行和調試

vscode使用斷點 1.安裝并激活擴展 Debugger for Chrome (棄用 --> JavaScript Debugger)Debugger for Firefox 2. 配置config文件 打開 config/index.js 并找到 devtool property。將其更新為&#xff1a; 如果你使用的是 Vue CLI 2&#xff0c;請設置并更新 config/in…

SpringBoot Redis讀寫與數據序列化 RedisTemplate 與 StringRedisTemplate 防轉字節

介紹 RedisTemplate 對象在底層默認會轉成字節&#xff0c;造成了內存的開銷很大&#xff0c;這是他底層進行處理的,造成可讀性差&#xff0c;如需要轉成簡單的字符串存儲需要進行序列化的配置。 RedisTemplate 配置類 Configuration public class RedisConfig {Beanpublic …

OpenGL系列(五)紋理貼圖

概述 OpenGL紋理是一種在三維圖形中應用紋理映射的技術。紋理是一張圖像&#xff0c;可以應用到三維模型的表面上&#xff0c;從而使得模型看起來更加真實和具有細節。通過紋理映射&#xff0c;可以將圖像的像素值與三維模型的頂點進行匹配&#xff0c;從而為模型的表面增加細節…

Java并發編程之由于靜態變量錯誤使用可能導致的并發問題

Java并發編程之由于靜態變量錯誤使用可能導致的并發問題 1.1 前言1.2 業務背景1.3 問題分析1.4 為什么呢&#xff1f;1.5 修復方案2 演示示例源碼下載 1.1 前言 我們知道在 Java 后端服務開發中&#xff0c;如果出現并發問題一般都是由于在多個線程中使用了共享的變量導致的。…

JVM相關:Java內存區域

Java 虛擬機&#xff08;JVM)在執行 Java 程序的過程中會把它管理的內存劃分成若干個不同的數據區域。 Java運行時數據區域是指Java虛擬機&#xff08;JVM&#xff09;在執行Java程序時&#xff0c;為了管理內存而劃分的幾個不同作用域。這些區域各自承擔特定的任務&#xff0c…

Day23 自定義對話框服務

?本章節實現了,自定義對話框服務的功能 當現有的對話框服務無法滿足特定需求時,我們可以采用自定義對話框的解決方案,以更好地滿足一些特殊需求。 一.自定義對話框主機服務步驟 在Models 文件夾中,再建立一個 IDialogHostService 接口類,繼承自 IDialogService 對話框服…

計算兩個LocalDateTime的相差時長

在Java中&#xff0c;你可以使用java.time.Duration類來計算兩個LocalDateTime對象之間的時間差。以下是一個示例代碼&#xff0c;展示了如何計算兩個LocalDateTime實例之間相差的時長&#xff1a; import java.time.Duration; import java.time.LocalDateTime;public class D…

絕對實用Linux命令行下的文件夾逐層創建術,從小白到大神的必學技能

哈嘍&#xff0c;大家好&#xff0c;我是木頭左&#xff01; 基礎篇&#xff1a;初識Linux文件系統 在深入了解如何在Linux中逐層創建文件夾之前&#xff0c;需要對Linux的文件系統有一個基本的認識。Linux文件系統以其樹狀結構而著稱&#xff0c;其中/&#xff08;根目錄&…

實用的供應商管理系統推薦:提升效率的合適選擇

隨著全球化和供應鏈的復雜性增加&#xff0c;供應商管理系統已經成為企業提高運營效率和競爭力的重要工具。一個優秀的供應商管理系統不僅能幫助企業優化采購流程&#xff0c;還能有效地管理供應商關系、降低成本、提高產品質量和服務水平。 供應商管理系統,供應商管理系統推薦…

SIMBA方法解讀

目錄 預處理scRNA-seqscATAC-seq 圖構建&#xff08;5種場景&#xff09;scRNA-seq分析scATAC-seq分析多模態分析批次整合多模態整合 圖學習SIMBA空間中查詢實體識別TF-target genes 預處理 scRNA-seq 過濾掉在少于三個細胞中表達的基因。原始計數按文庫大小標準化&#xff0…

DDS自動化測試落地方案 | 懌星科技攜最新技術亮相是德科技年度盛會

5月28日&#xff0c;懌星科技作為是德科技的重要合作伙伴亮相Keysight World Tech Day 2024。在此次科技盛會上&#xff0c;懌星科技不僅展示了領先的DDS自動化測試解決方案等前沿技術&#xff0c;還分享了在“周期短、任務重”的情況下&#xff0c;如何做好軟件開發和測試驗證…

前端開發之性能優化

本文章 對各大學習技術論壇知識點&#xff0c;進行總結、歸納自用學習&#xff0c;共勉&#x1f64f; 文章目錄 1. [CDN](https://www.bootcdn.cn/)2.懶加載3.緩存4.圖片壓縮5.圖片分割6.sprite7.Code Splitting8.gzip9.GPU加速10.Ajax11.Tree Shaking12.Resource Hints 1. CD…

YOLO系列模型 pt文件轉化為ONNX導出

文章目錄 啥是onnx怎么導出導出之后 啥是onnx Microsoft 和合作伙伴社區創建了 ONNX 作為表示機器學習模型的開放標準。許多框架&#xff08;包括 TensorFlow、PyTorch、scikit-learn、Keras、Chainer、MXNet 和 MATLAB&#xff09;的模型都可以導出或轉換為標準 ONNX 格式。 在…

C++筆試強訓day40

目錄 1.游游的字母串 2.體育課測驗(二) 3.合唱隊形 1.游游的字母串 鏈接https://ac.nowcoder.com/acm/problem/255195 英文字母一共就26個&#xff0c;因此可以直接暴力枚舉以每個字母作為最后的轉變字母。最后去最小值即可 #include <iostream> #include <cmath&…

趕緊收藏!2024 年最常見 20道 Kafka面試題(十)

上一篇地址&#xff1a;趕緊收藏&#xff01;2024 年最常見 20道 Kafka面試題&#xff08;九&#xff09;-CSDN博客 十九、在分布式情況下&#xff0c;Kafka 如何保證消息的順序消費&#xff1f; 在分布式系統中&#xff0c;Kafka保證消息順序消費主要依賴于其分區機制和消費…

項目實戰系列——WebSocket——websock簡介

最近項目中需要用到mes和本地客戶端進行實時通訊&#xff0c;本來想用webapi進行交互的&#xff0c;但是考慮到高效和實時性&#xff0c;就采用這一項技術。 以往采用的方式——長輪詢 客戶端主動向服務器發送一個請求&#xff0c;如果服務器沒有更新的數據&#xff0c;客戶端…