導航:首頁 > 源碼編譯 > arm查詢法的局限性和編譯流程

arm查詢法的局限性和編譯流程

發布時間:2025-01-13 07:31:15

⑴ 如何編譯arm linux的go

Golang也就是Go語言,現在已經發行到1.4.1版本了,語言特性優越性和背後Google強大靠山什麼的就不多說了。Golang的官方提供了多個平台上的二進制安裝包,遺憾的是並非沒有發布ARM平台的二進制安裝包。ARM平台沒辦法直接從官網下載二進制安裝包來安裝,好在Golang是支持多平台並且開源的語言,因此可以通過直接在ARM平台上編譯源代碼來安裝。整個過程主要包括編譯工具配置、獲取Golang源代碼、設置Golang編譯環境變數、編譯、配置Golang行環境變數等步驟。
註:本文選用樹莓派做測試,因為樹莓派是基於ARM平台的。

1、編譯工具配置
據說下個版本的golang編譯工具要使用golang自己來寫,但目前還是使用C編譯工具的。因此,首先要配置好C編譯工具:
1.1 在Ubuntu或Debian平台上可以使用sudo apt-get install gcc libc6-dev命令安裝,樹莓派的RaspBian系統是基於Debian修改的,所以可以使用這種方法安裝。
1.2 在RedHat或CentOS 6平台上可以使用sudo yum install gcc libc-devel命令安裝。
安裝完成後可以輸入 gcc --version命令驗證是否成功安裝。

2、獲取golang源代碼
2.1 直接從官網下載源代碼壓縮包。
golang官網提供golang的源代碼壓縮包,可以直接下載,最新的1.4.1版本源代碼鏈接:https://storage.googleapis.com/golang/go1.4.1.src.tar.gz
2.2 使用git工具獲取。
golang使用git版本管理工具,也可以使用git獲取golang源代碼。推薦使用這個方法,因為以後可以隨時獲取最新的golang源代碼。
2.2.1 首先確認ARM平台上已經安裝了git工具,可以使用git --version命令確認。一般linux平台都安裝了git,沒有的話可以自行安裝,不同平台的安裝方法可以參考:http://git-scm.com/download/linux
2.2.2 克隆遠程golang的git倉庫到本地
在終端cd到你想要安裝golang的目錄,確保該目錄下沒有名為go的目錄。然後以下命令獲取代碼倉庫:
git clone https://go.googlesource.com/go
大陸地區可能會獲取失敗,在不翻牆的情況下我試了幾次都沒成功,原因大家都懂的。好在google已經將golang也託管到github上面,所以也可以通過下面命令獲取:
git clone https://github.com/golang/go.git
視網路情況,下載可能需要不少時間。我2M的帶寬花了將近兩個小時才下載完,雖然整個項目不過幾十兆= =
下載完成後,可以看到目錄下多了一個go目錄,裡面即為golang的源代碼,在終端上執行cd go命令進入該目錄。
執行下面命令檢出go1.4.1版本的源代碼,因為現在已經有新的代碼提交上去了,最新的代碼可能不是最穩定的:
git checkout go1.4.1
至此,最新1.4.1發行版的源代碼獲取完畢

3、設置golang的編譯環境變數
主要有GOROOT、GOOS、GOARCH、GOARM四個環境變數需要設置,先解釋四個環境變數的意義。
3.1 GOROOT
主要代表golang樹結構目錄的路徑,也就是上面git檢出的go目錄。一般可以不用設置這個環境變數,因為編譯的時候默認會以go目錄下src子目錄中的all.bash腳本運行時的父目錄作為GOROOT的值。為了保險起見,可以直接設置為go目錄的路徑。
3.2 GOOS和GOARCH
分別代表編譯的目標系統和平台,可選值如下:

GOOS GOARCH
darwin 386
darwin amd64
dragonfly 386
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
plan9 386
plan9 amd64
solaris amd64
windows 386
windows amd64
需要注意的是這兩個值代表的是目標系統和平台,而不是編譯源代碼的系統和平台。樹莓派的RaspBian是linux系統,所以這些GOOS設置為linux,GOARCH設置為arm。
3.3 GOARM
表示使用的浮點運算協處理器版本號,只對arm平台有用,可選值有5,6,7。如果是在目標平台上編譯源代碼,這個值可以不設置,它會自動判斷需要使用哪一個版本。
總結下來,在樹莓派上設置golang的編譯環境變數,可編輯$HOME/.bashrc文件,在末尾添加下面內容:
export GOROOT=你的go目錄路徑
export GOOS=linux
export GOARCH=arm
編輯完後保存,執行source ~/.bashrc命令讓修改生效。

4、編譯源代碼
環境變數配置完成自後就可以開始編譯源代碼。在go目錄下的src子目錄中,主要有all.bash和make.bash兩個腳本(另外還有兩個all.bat和make.bat腳本適用於window平台)。編譯實際上就是執行其中一個腳本,兩者的區別在於all.bash在編譯完成後還會執行一些測試套件。如果希望只編譯不測試,可以運行make.bash腳本。使用cd命令進入go下src目錄,執行./all.bash或者./make.bash命令即可開始編譯。由於硬體情況不同,編譯耗費的時間不同。在我的B型樹莓派編譯過程花費了將近半個小時,編譯完成後執行的測試套件又花費了差不多一個小時,總共花費了一個半小時左右。

5、配置golang運行環境變數
編譯完成後,go目錄下會生成bin目錄,裡面就是go的運行腳本。為了以後使用方法,可以將這個bin路徑添加到PATH環境變數中。同樣編輯~/.bashrc文件,因為前面設置過GOROOT環境變數指向go目錄了,所以只需要在末尾加上
export PATH=$PATH:$GOROOT/bin
保存後同樣執行source ~/.bashrc命令讓環境變數生效。

至此,golang源代碼編譯安裝成功。執行go version應該就能看到當前golang的版本信息,表示編譯安裝成功。

⑵ iOS底層原理08-dyld載入流程

本文的目的主要是分析dyld的載入流程,了解在main函數之前,底層還做了什麼

引子

創建一個project,在ViewController中重寫了load方法,請問它們的列印先後順序是什麼?

運行程序,查看 load、main的列印順序,下面是列印結果,通過結果可以看出其順序是 load ?--> main

為什麼是這么一個順序?按照常規的思維理解,main不是入口函數嗎?為什麼不是main最先執行?

下面根據這個問題,我們來探索在走到main之前,到底還做了什麼。

編譯過程及庫

在分析app啟動之前,我們需要先了解iOSapp代碼的編譯過程以及動態庫和靜態庫。

編譯過程

其中編譯過程如下圖所示,主要分為以下幾步:

源文件:載入.h、.m、.cpp等文件

預處理:替換宏,刪除注釋,展開頭文件,產生.i文件

編譯:將.i文件轉換為匯編語言,產生.s文件

匯編:將匯編文件轉換為機器碼文件,產生.o文件

鏈接:對.o文件中引用其他庫的地方進行引用,生成最後的可執行文件

靜態庫 和 動態庫

靜態庫:在鏈接階段,會將可匯編生成的目標程序與引用的庫一起鏈接打包到可執行文件當中。此時的靜態庫就不會在改變了,因為它是編譯時被直接拷貝一份,復制到目標程序里的

好處:編譯完成後,庫文件實際上就沒有作用了,目標程序沒有外部依賴,直接就可以運行

缺點:由於靜態庫會有兩份,所以會導致目標程序的體積增大,對內存、性能、速度消耗很大

動態庫:程序編譯時並不會鏈接到目標程序中,目標程序只會存儲指向動態庫的引用,在程序運行時才被載入

減少打包之後app的大小:因為不需要拷貝至目標程序中,所以不會影響目標程序的體積,與靜態庫相比,減少了app的體積大小

共享內存,節約資源:同一份庫可以被多個程序使用

通過更新動態庫,達到更新程序的目的:由於運行時才載入的特性,可以隨時對庫進行替換,而不需要重新編譯代碼

優勢:

缺點:動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴於外部環境,如果環境缺少了動態庫,或者庫的版本不正確,就會導致程序無法運行

靜態庫和動態庫的圖示如圖所示

dyld載入流程分析

根據dyld源碼,以及libobjc、libSystem、libdispatch源碼協同分析

什麼是dyld?

dyld(the dynamic link editor)是蘋果的動態鏈接器,是蘋果操作系統的重要組成部分,在app被編譯打包成可執行文件格式的Mach-O文件後,交由dyld負責連接,載入程序

所以 App的啟動流程圖如下

app啟動的起始點

在前文的demo中,在load方法處加一個斷點,通過bt堆棧信息查看app啟動是從哪裡開始的

【app啟動起點】:通過程序運行發現,是從dyld中的_dyld_start開始的,所以需要去OpenSource下載一份dyld的源碼來進行分析

也可以通過xcode左側的堆棧信息來找到入口

dyld::_main函數源碼分析

在dyld-750.6源碼中查找_dyld_start,查找arm64架構發現,是由匯編實現,通過匯編注釋發現會調用dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)方法,是一個C++方法(以arm64架構為例)

源碼中搜索dyldbootstrap找到命名作用空間,再在這個文件中查找start方法,其核心是返回值的調用了dyld的main函數,其中macho_header是Mach-O的頭部,而dyld載入的文件就是Mach-O類型的,即Mach-O類型是可執行文件類型,由四部分組成:Mach-O頭部、Load Command、section、Other Data,可以通過MachOView查看可執行文件信息

進入dyld::_main的源碼實現,特別長,大約900多行,如果對dyld載入流程不太了解的童鞋,可以根據_main函數的返回值進行反推,這里就多作說明。在_main函數中主要做了一下幾件事情:

【第一步:環境變數配置】:根據環境變數設置相應的值以及獲取當前運行架構

【第二步:共享緩存】:檢查是否開啟了共享緩存,以及共享緩存是否映射到共享區域,例如UIKit、CoreFoundation等

【第三步:主程序的初始化】:調用instantiateFromLoadedImage函數實例化了一個ImageLoader對象

【第四步:插入動態庫】:遍歷DYLD_INSERT_LIBRARIES環境變數,調用loadInsertedDylib載入

【第五步:link 主程序】

【第六步:link 動態庫】

【第七步:弱符號綁定】

【第八步:執行初始化方法】

【第九步:尋找主程序入口即main函數】:從Load Command讀取LC_MAIN入口,如果沒有,就讀取LC_UNIXTHREAD,這樣就來到了日常開發中熟悉的main函數了

下面主要分析下【第三步】和【第八步】

第三步:主程序初始化

sMainExecutable表示主程序變數,查看其賦值,是通過instantiateFromLoadedImage方法初始化

進入instantiateFromLoadedImage源碼,其中創建一個ImageLoader實例對象,通過instantiateMainExecutable方法創建

進入instantiateMainExecutable源碼,其作用是為主可執行文件創建映像,返回一個ImageLoader類型的image對象,即主程序。其中sniffLoadCommands函數時獲取Mach-O類型文件的Load Command的相關信息,並對其進行各種校驗

第八步:執行初始化方法

進入initializeMainExecutable源碼,主要是循環遍歷,都會執行runInitializers方法

全局搜索runInitializers(cons,找到如下源碼,其核心代碼是processInitializers函數的調用

進入processInitializers函數的源碼實現,其中對鏡像列表調用recursiveInitialization函數進行遞歸實例化

在這里,需要分成兩部分探索,一部分是notifySingle函數,一部分是doInitialization函數,首先探索notifySingle函數

notifySingle 函數

全局搜索notifySingle(函數,其重點是(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());這句

全局搜索sNotifyObjCInit,發現沒有找到實現,有賦值操作

搜索registerObjCNotifiers在哪裡調用了,發現在_dyld_objc_notify_register進行了調用

注意:_dyld_objc_notify_register的函數需要在libobjc源碼中搜索

在objc4-781源碼中搜索_dyld_objc_notify_register,發現在_objc_init源碼中調用了該方法,並傳入了參數,所以sNotifyObjCInit的賦值的就是objc中的load_images,而load_images會調用所有的+load方法。所以綜上所述,notifySingle是一個回調函數

load函數載入

下面我們進入load_images的源碼看看其實現,以此來證明load_images中調用了所有的load函數

通過objc源碼中_objc_init源碼實現,進入load_images的源碼實現

進入call_load_methods源碼實現,可以發現其核心是通過do-while循環調用+load方法

進入call_class_loads源碼實現,了解到這里調用的load方法證實我們前文提及的類的load方法

所以,load_images調用了所有的load函數,以上的源碼分析過程正好對應堆棧的列印信息

【總結】load的源碼鏈為:_dyld_start --> dyldbootstrap::start --> dyld::_main --> dyld::initializeMainExecutable --> ImageLoader::runInitializers --> ImageLoader::processInitializers --> ImageLoader::recursiveInitialization --> dyld::notifySingle(是一個回調處理) --> sNotifyObjCInit --> load_images(libobjc.A.dylib)

那麼問題又來了,_objc_init是什麼時候調用的呢?請接著往下看

doInitialization 函數

走到objc的_objc_init函數,發現走不通了,我們回退到recursiveInitialization遞歸函數的源碼實現,發現我們忽略了一個函數doInitialization

進入doInitialization函數的源碼實現

這里也需要分成兩部分,一部分是doImageInit函數,一部分是doModInitFunctions函數

進入doImageInit源碼實現,其核心主要是for循環載入方法的調用,這里需要注意的一點是,libSystem的初始化必須先運行

進入doModInitFunctions源碼實現,這個方法中載入了所有Cxx文件

走到這里,還是沒有找到_objc_init的調用?怎麼辦呢?放棄嗎?當然不行,我們還可以通過_objc_init加一個符號斷點來查看調用_objc_init前的堆棧信息,

_objc_init加一個符號斷點,運行程序,查看_objc_init斷住後的堆棧信息

在libsystem中查找libSystem_initializer,查看其中的實現

根據前面的堆棧信息,我們發現走的是libSystem_initializer中會調用libdispatch_init函數,而這個函數的源碼是在libdispatch開源庫中的,在libdispatch中搜索libdispatch_init

進入_os_object_init源碼實現,其源碼實現調用了_objc_init函數

結合上面的分析,從初始化_objc_init注冊的_dyld_objc_notify_register的參數2,即load_images,到sNotifySingle --> sNotifyObjCInie=參數2 到sNotifyObjcInit()調用,形成了一個閉環

所以可以簡單的理解為sNotifySingle這里是添加通知即addObserver,_objc_init中調用_dyld_objc_notify_register相當於發送通知,即push,而sNotifyObjcInit相當於通知的處理函數,即selector

【總結】:_objc_init的源碼鏈:_dyld_start --> dyldbootstrap::start --> dyld::_main --> dyld::initializeMainExecutable --> ImageLoader::runInitializers --> ImageLoader::processInitializers --> ImageLoader::recursiveInitialization --> doInitialization -->libSystem_initializer(libSystem.B.dylib) --> _os_object_init(libdispatch.dylib) --> _objc_init(libobjc.A.dylib)

第九步:尋找主入口函數

跑完了整個流程,會回到_dyld_start,然後調用main()函數,通過匯編完成main的參數賦值等操作

所以,綜上所述,最終dyld載入流程,如下圖所示,圖中也詮釋了前文中的問題:為什麼是load-->main的調用順序

原文:https://juejin.cn/post/7096170825136472078

⑶ zlib開發筆記(三):zlib庫介紹、在ubuntu上進行arm平台交叉編譯

本文主要介紹了zlib庫的特性、下載方法,以及在ubuntu上進行arm平台的交叉編譯步驟。zlib是一個免費、通用且不受專利保護的數據壓縮庫,適用於各種硬體和操作系統。以下是具體的操作流程:

首先,確保你的交叉編譯環境已准備就緒,包括製作交叉編譯鏈工具並將其添加到環境變數中。在終端中,創建環境文件`env.sh`,並編輯它以包含交叉編譯器的路徑。啟動控制台並運行`source ../tool/env.sh`來引入這些設置。

接下來,解壓zlib庫(如zlib-1.2.11.tar.gz),並使用交叉編譯器進行配置和編譯。在`makefile`中可能需要修改CC的設置以確保正確連接庫。執行`make`進行編譯,然後用`sudo make install`進行安裝。

模塊化部分,雖然Ubuntu上對庫的模塊化不包含庫,你可以參考《zlib開發筆記(一)》了解更多信息。此外,工程模板zipDemo_v1.0.0_基礎模板可供參考,但可能需要根據ubuntu系統的問題進行適當調整。

以上就是在ubuntu上進行arm平台zlib庫交叉編譯的詳細步驟,如果你對其他平台或版本有疑問,可以查看《zlib開發筆記(二)》或期待後續的文章更新。

⑷ 【圖文】鯤鵬916-ARM64架構源碼gcc編譯完整記錄


以下是關於ARM64架構源碼gcc編譯的詳細步驟記錄:




  1. 首先,確保已經准備就緒,如果cmake未安裝,需要進行安裝。檢查cmake版本以確認其是否滿足需求。




  2. 安裝必要的依賴包,如isl、gmp、mpc、mpfr等,檢查它們是否已成功安裝。




  3. 針對gcc版本過低的問題,需下載並更新到7.3版本。下載並解壓gcc7.3的安裝包。





    1. 在gcc-7.3.0目錄下,確認已下載和安裝了所有依賴包。




    2. 利用多核CPU的優勢,通過「-j32」參數加速編譯過程。原先是按照官方文檔使用make -j16,但速度緩慢,後來調整為make -j32以提升效率。




    3. 依次執行編譯目錄創建、gcc編譯、安裝以及確認「libstdc++.so」軟連接在正確的目錄(/usr/lib64)。





  4. 編譯完成後,通過查看gcc版本來確認安裝是否成功。




以上就是完整的gcc編譯安裝流程。如果您覺得這些信息對您有所幫助,歡迎分享和關注我們的更新。更多技術內容敬請期待,感謝您的支持!


⑸ arm匯編跟匯編、C語言的區別

不一樣,匯編主要是要了解CPU指令及用法。
我們常說的是PC機的x86匯編,指令是x86的復雜指令集。
arm匯編是arm的精簡指令集,比x86容易學,程序格式倒是和x86匯編差不多。你下載一份arm的手冊就可以了解了。
C語言ARM的和x86的差不多,除了對硬體寄存器操作不同,其它語法和流程都一樣。
回答補充:
arm匯編程序每一行是指定arm
core執行一條指令,每條指令都是硬體相關。

LDR
R3,
#1
;用LDR指令將數值1放入R3寄存器准備參與運算
C語言與arm指令無關,只與邏輯運算有關,指定硬體地址的操作才與硬體相關;如果用arm編譯器來編譯,每行可能編譯出1到多條arm指令。

i++;
//變數
i
遞增1
等效於
LDR
R3,#1
;用LDR指令將數值1放入R3寄存器准備參與運算
ADD
R2,
R2,
R3
;用ADD指令將R2、R3寄存器里的數值相加後放回R2寄存器
以上等效匯編的R2、R3寄存器只是為了舉例,C語言不像匯編,不需要由程序員指定用哪個寄存器參與運算,編譯器編譯時會根據程序結構自動判斷選擇。
強調mcuos有錯,「c語言被編譯器編譯的時候會最終解釋為匯編語言的」,無論是c語言還是匯編語言,編譯器編譯後的結果是機器執行碼,很多人因為匯編語言比較難懂及指令相關,所以以為它就是機器語言,其實它仍是人類設計的編寫程序的語言,仍需要編譯器編譯成機器碼才能執行,它只是比C語言更接近硬體而已。

⑹ linuxarm開發需要全部重編譯嗎

不需要。
根據查詢知乎網顯示,在LinuxARM開發中,只需要針對新的ARM架構平台進行編譯即可,與ARM架構無關的代碼並不需要重新編譯。

閱讀全文

與arm查詢法的局限性和編譯流程相關的資料

熱點內容
亞馬遜雲伺服器到期了怎麼續費 瀏覽:848
我的世界網易如何在伺服器裡面加光影 瀏覽:284
nat地址訪問外網伺服器 瀏覽:966
怎樣用java編譯一個心形 瀏覽:934
如何使用python中的pygame 瀏覽:836
python實用小工具 瀏覽:24
怎麼在安卓手機上去除馬賽克 瀏覽:235
農行濃情通app怎麼下載 瀏覽:533
怎麼把原文件夾找回來 瀏覽:535
俄羅斯方塊實現python思路 瀏覽:735
漢語拼音英語編譯代碼 瀏覽:501
程序員應具備的能力 瀏覽:606
手機石墨文檔文件夾訪問許可權 瀏覽:656
客戶端如何登陸域文件伺服器 瀏覽:530
兩位數的平方計演算法 瀏覽:930
android圖片分塊 瀏覽:715
圖形平移命令 瀏覽:962
聚類演算法JAVA代碼 瀏覽:407
網站圖標素材壓縮包 瀏覽:892
娛樂化app怎麼做 瀏覽:639