1. 程式人生 > >arm-linux核心編譯過程小結

arm-linux核心編譯過程小結

記在前面的雜七雜八

  1. 核心的生成,實際上最終的目的是生成一個binary檔案zImage,大小2-5MB的數量級。
  2. 使用者可以從kernel.org得到的tar.gz格式的核心原始碼,此程式碼解壓後,就會生成初始狀態的核心原始碼樹,這種狀態稱為核心的初始狀態
  3. 通過make mrproper/make distclean等指令,可以使核心恢復到剛解壓的狀態。其中make mrproper只清除包括.config檔案在內的,為核心編譯及連線而生成的諸多配置檔案。distclean物件執行mrproper命令,清除核心編譯後生成的所有物件檔案,備份檔案等。
  4. 如果將初始化狀態的核心直接編譯,雖然能生成vmlinux,但大多數情況下會引起核心嚴重錯誤(kernel panic)。構建核心前,需要執行的最重要,最需謹慎處理的部分是核心配置(kernel configureation)過程。核心配置過程也是適當選擇與自身相吻合的各種核心要素的過程。
  5. 核心的配置可以用xconfig,menuconfig,gconfig等,最終都是會執行一個二進位制檔案,如menuconfig最終執行的是mconf,這個程式在./script/kconfig/目錄下。
  6. 在構建核心時,各個*.o的目錄下都有一個.*.cmd,這個檔案是記錄這個.o最終執行的編譯命令的,如vmlinux.cmd和.vmlinux.o.cmd。
  7. 一句make一般來說,預設的目標有兩個,一個是vmlinux,一個是zImage
  8. 通過emulator啟動goldfish的時候,實際上啟動的是zImage,這貨才2.5MB左右,啟動命令如下:

    emulator -show-kernel -kernel
    /mnt/VMDisk1/kernel/goldfish/arch/arm/boot/zImage -avd test -qemu -s
    • 1
    • 1
  9. 在圖形化介面下,核心的配置也會有很多很多問題,一般每個系統均提供自定義配置檔案,這些配置檔案都是與具體晶片相關的(Soc, System on Chip),如下:

tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish$ cd arch/
alpha/      blackfin/   frv/        ia64/       microblaze/ openrisc/   s390/       sparc/      unicore32/  
arm/        c6x/        h8300
/ m32r/ mips/ parisc/ score/ tile/ x86/ avr32/ cris/ hexagon/ m68k/ mn10300/ powerpc/ sh/ um/ xtensa/ tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish/arch/arm/configs$ ll total 632 drwxr-xr-x 2 tigger tigger 4096 2014-10-14 20:09 ./ drwxr-xr-x 88 tigger tigger 4096 2014-11-01 02:28 ../ -rw-r--r-- 1 tigger tigger 1998 2014-10-11 02:28 acs5k_defconfig -rw-r--r-- 1 tigger tigger 2011 2014-10-11 02:28 acs5k_tiny_defconfig -rw-r--r-- 1 tigger tigger 2509 2014-10-14 20:09 afeb9260_defconfig -rw-r--r-- 1 tigger tigger 2241 2014-10-11 02:28 ag5evm_defconfig -rw-r--r-- 1 tigger tigger 2617 2014-10-11 02:28 am200epdkit_defconfig ......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

核心的構建

  • 如想使用goldfish的配置,可以:
    //根據goldfish_armv7_defconfig生成.config檔案
    make goldfish_armv7_defconfig
    //調整一些具體細節項
    make menuconfig
    //然後就可以編譯了
    make
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • .config檔案是構建核心所需的核心配置目錄,它是在CONFIG_XXX變數中用y,n,m三個狀態進行配置的目錄,這種形態的核心配置系統叫做kconfig。根據kconfig提供的三個狀態(y,n,m)決定是否構建核心相應的模組(Kconfig系統中y,n,m只是bool型別的配置選項,實際上.config中可能有hex/int/bool/tristate/string這多種型別的選項)。

    • 狀態為y時:相應的二進位制檔案,與vmlinux連結。
    • 狀態為m時:不會和vmlinux連結,但作為模組執行編譯。
    • 狀態為n時:不編譯。
  • mconf通過.config配置檔案,生成autoconf.h標頭檔案

tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish$ find ./ -name autoconf.h
./include/linux/autoconf.h
./include/generated/autoconf.h
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

這兩個檔案是一樣的,也不知道誰複製的誰,大體看一下檔案內容:

#define CONFIG_RING_BUFFER 1
#define CONFIG_NF_CONNTRACK_H323 1
#define CONFIG_KERNEL_GZIP 1
#define CONFIG_INPUT_KEYBOARD 1
#define CONFIG_IP_NF_TARGET_REDIRECT 1
#define CONFIG_CRC32 1
#define CONFIG_NF_NAT_PROTO_SCTP 1
#define CONFIG_HAVE_AOUT 1
#define CONFIG_VFP 1
#define CONFIG_AEABI 1
#define CONFIG_FB_TILEBLITTING 1
#define CONFIG_HIGH_RES_TIMERS 1
#define CONFIG_BLK_DEV_DM 1
#define CONFIG_VLAN_8021Q 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

可以發現,在.config中定義的的巨集,在預處理階段被處理成了各種#define語句。

  • 利用kconfig完成核心配置,準備好.config檔案後,即可構建核心。構建核心是指,編譯核心,連結各個二進位制檔案,最終生成一個二進位制檔案zImage的一系列過程。

  • 從linux2.6開始,核心採用kbuild系統來進行編譯了,kbuild是指上是一堆指令碼的組合。

linux核心Makefile分類: 
* Kernel Makefile: 位於核心原始碼的頂層目錄,也叫Top Makefile。主要用於指定編譯核心的目標檔案(vmlinux)和模組。在編譯核心或模組時,這個檔案會被首先讀取,並根據內容設定環境變數。 
* kbuild Makefile: kbuild系統使用kbuild Makefile來編譯核心或模組,Kbuild Makefile指定哪些編譯近核心,哪些編譯為模組。 
* arch Makefile: 位於./arch/$(ARCH)/Makefile,是系統對應平臺的Makefile。top makefile會包含這個檔案來指定平臺相關資訊,只有平臺開發人員需要關心這個檔案。

vmlinux的生成

編譯後,vmlinux是在核心目錄樹的根目錄下生成的一個ELF檔案,這裡以goldfish下執行make為例,檢視vmlinux的生成。 當執行make命令的時候,會先掃描核心的根目錄的Makefile:

##(後續只列舉關鍵內容),./Makefile
##.PHONY: $(PHONY)是在Makefile最後定義的, .PHONY是將一個目標宣告為偽目標,
##這樣make在執行規則時不會試圖去查詢隱含規則來建立他(簡單理解不會把_all當
##成一個檔案,不會存在如果當前目錄存在_all這個檔案,而檔案不更新,系統不能編譯的問題)
##所有這樣的檔案都加到了.PHONY裡面。
PHONY := _all
##_all是編譯的預設目標,就是make指令的預設目標
_all:
ifeq ($(KBUILD_EXTMOD),)
##如果沒指定編譯模組
_all: all
else
##如果指定是編譯模組
_all: modules
endif
#如果沒指定編譯模組,則這裡最終編譯的就是vmlinux
#(注:在體系結構相關的makefile中一般還有一個all,即zImage)
all: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
    ##vmlinux-modpost不存在,這裡好像是忽略了??
    $(call vmlinux-modpost)
    ##如果if_changed_rule成立則執行rule_vmlinux__
    $(call if_changed_rule,vmlinux__)
    ##刪除.old_version
    $(Q)rm -f .old_version
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

後續會分析其中的各個目標

目標檔案 vmlinux.o

vmlinux.o是沒有去除符號表的可執行檔案,最終生成的vmlinux為真正的核心映象

-rwxr-xr-x   1 tigger tigger  61M 2014-12-22 01:21 vmlinux*
-rw-r--r--   1 tigger tigger 109M 2014-12-22 01:21 vmlinux.o
  • 1
  • 2
  • 1
  • 2

目標檔案 vmlinux.lds

vmlinux.lds是一個連結指令碼,是給ld連結器使用的。一般來說,普通程式是不需要指定linker script的,也不需要關心各個section的具體位置。當程式執行時,kernel中的ELF Loader會根據ELF檔案頭解析可執行檔案的各個section,並把他們對映到虛擬地址空間。然而,核心啟動時,必須首先確定各個section的具體位置,這就是vmlinux.lds的作用。這個檔案必然是體系結構相關的,在arm中有兩個連線指令碼分別位於: 
./arch/arm/kernel/vmlinux.lds(這個是給vmlinux編譯用的連線指令碼,就是這裡面的vmlinux.lds
./arch/arm/boot/compressed/vmlinux.lds(這個是給zImage編譯時候用的連線指令碼)

目標檔案 kallsyms.o

在2.6核心中,為了更好的除錯核心,引入了kallsyms機制。kallsyms把核心中用到的所有函式地址和名稱連結到核心檔案,當核心啟動後,同時載入到記憶體中。當發生oops時候,核心就會 
解析eip位於哪個函式中,然後打印出backtrace資訊。核心編譯的最後,make會執行:nm -n vmlinux|scripts/kallsyms,其中: 
1. nm -n vmlinux負責生成所有的核心符號並按地址排序 
2. scripts/kallsyms負責處理這個列表,並生成需要的連結檔案tmp_kallsyms%.s 
也就是說kallsyms實際上是核心編譯完了之後,vmlinux中通過nm命令生成的,所以所有符號地址都包括了,實際上是和System.map是一樣的。 
而且kallsyms中所有函式的地址,是放在一個全域性陣列kallsyms_addresses[]中的,如下:

kallsyms_addresses:
        PTR     _text + 0x180
        PTR     _text + 0x180
        PTR     _text + 0x180
        PTR     _text + 0x194
        PTR     _text + 0x360
        PTR     _text + 0x374
        PTR     _text + 0x484
        PTR     _text + 0x594
        PTR     _text + 0x5f4
        PTR     _text + 0x5f8
        PTR     _text + 0x60c
        PTR     _text + 0x624
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
kallsyms_addresses中的每一個表項,都在重定位表中有記錄,如果核心發生了重定位,那麼kallsyms中的內容也會跟著修改,所以cat /proc/kallsyms的時候總是看到的是真正的函式地址。

kallsyms的整個符號表,最終都會放在kallsyms.o檔案中。

#kallsyms也是最終依賴一個檔案,這個是.tmp_kallsymsX.o
kallsyms.o := .tmp_kallsyms$(last_kallsyms).o          
  • 1
  • 2
  • 1
  • 2

目標 vmlinux-init

#./Makefile
vmlinux-init := $(head-y) $(init-y)
  • 1
  • 2
  • 1
  • 2
  • head-y
#./Makefile
#head-y定義在具體體系結構的makefile中,這句include會載入head-y的定義
include $(srctree)/arch/$(SRCARCH)/Makefile
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
#./arch/arm/Makefile
#這裡的MMUEXT應該是是否開啟mmu的意思,如果不開啟就是head-nommu.o,開啟就是head.o
head-y := arch/arm/kernel/head$(MMUEXT).o \
        arch/arm/kernel/init_task.o
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • init-y
#./Makefile
#一開始init-y是個目錄
init-y  := init/
#後續把init-y變數中所有符合%/的替換為%/built-in.o,這句之後init-y 被賦值為 init/built-in.o
init-y          := $(patsubst %/, %/built-in.o, $(init-y))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

所以最終vmlinux-init 實際上是: 
1. arch/arm/kernel/head.o(這是Image/vmlinux的入口程式碼)。 
2. arch/arm/kernel/init_task.o 
3. init/built-in.o 
三者連結而來的。

目標 vmlinux-main

vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
  • 1
  • 1
  • core-y
#./Makefile
core-y := usr/
ifeq ($(KBUILD_EXTMOD),)
core-y  += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
#如果是編譯核心的話,core-y最終包含: usr/ kernel/ mm/ fs/ ipc/ security/ crypto/ block/
#目錄下的built-in.o。編譯模組的話,就只包含usr/build-in.o。
core-y := $(patsubst %/, %/built-in.o, $(core-y))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

            
           

相關推薦

arm-linux核心編譯過程小結

記在前面的雜七雜八核心的生成,實際上最終的目的是生成一個binary檔案zImage,大小2-5MB的數量級。使用者可以從kernel.org得到的tar.gz格式的核心原始碼,此程式碼解壓後,就會生成初始狀態的核心原始碼樹,這種狀態稱為核心的初始狀態。通過make mrproper/make distcle

linux核心編譯過程的最終總結版

一、實驗目的 學習重新編譯Linux核心,理解、掌握Linux核心和發行版本的區別。 二、實驗內容 在Linux作業系統環境下重新編譯核心。實驗主要內容: A. 查詢並且下載一份核心原始碼,本實驗使用最新的Linux核心2.6.36。 B. 配置核心。 C. 

Linux核心編譯過程

準備工作 硬體:筆記本 系統: Ubuntu18.04 64位 下載核心 1、先安裝ubuntu18.04的系統。 2、到核心官網下載最新的核心code: https://www.kernel.org/ 如圖所示下載最新kernel 例如 Linux-4.19:

打造自己的專屬linux(四):Linux核心編譯過程簡介

linux在前不久剛釋出了最新的3.0核心,在linux的學習中,瞭解核心的編譯是一個必不可少的功課。前幾天,學習了linux核心的編譯流程,在此總結下,大家來一起學習。 以最新的3.0核心為例,我下載的是linux3.0.1 下載地址:http://www.kernel.

arm linux核心啟動過程詳解

         可以結合《hi3536uboot引導核心全過程》一文一起看 1、uImage生成過程 (1)vmlinux 根目錄下vmlinux為kernel未經過任何處理的原始可執行檔案。根據arch/arm/kernel/vmlinux.lds連線檔案生成:    

Linux 核心編譯過程常遇到的錯誤總結

depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || C

Linux核心編譯過程中遇到的問題

首先還是宣告編譯環境,和交叉編譯工具,還有核心是天嵌移植過的核心原始碼,上一篇寫的編譯核心問題,移植沒有解決,今天編譯成功後,感覺上次問題好白痴,我還去改了很多檔案和函式,殊不知是自己操作錯誤,在此宣告,有些版本的核心都是移植過的,如果是按照第三方提供的資料或者視訊去編譯

基於armLinux核心編譯

我的Ubuntu版本是14.04 1、在官網下載Linux核心原始碼     官網地址:https://www.kernel.org/ 2、解壓Linux核心原始碼 3、安裝arm-gcc交叉編譯工具鏈:sudo apt-get install arm-linux-gn

Ubuntu 12.04嵌入式交叉編譯環境arm-linux-gcc搭建過程圖解

安裝前的絮叨 首先簡單介紹一下,所謂的搭建交叉編譯環境,即安裝、配置交叉編譯工具鏈。在該環境下編譯出嵌入式Linux系統所需的作業系統、應用程式等,然後再上傳到目標機上。 交叉編譯工具鏈是為了編譯、連結、處理和除錯跨平臺體系結構的程式程式碼。對於交叉開發的工具鏈來說,在檔名稱上加了一個字首,用來區別本地的

ARMLinux核心編譯與裁剪

Win7下使用Oracle VM VirtualBox搭建的Ubuntu11.10虛擬機器 1、建立交叉編譯環境:       下載交叉編譯器arm-linux-gcc-3.4.1.tar.bz2             tar jxvf arm-linux-gcc-3.

ubuntu 交叉編譯arm linux 核心

相關文章 安裝arm-linux-gcc 4.2.3 sudo tar  xvzf arm-linux-gcc-4.3.2.tar.gz  -C / 此時將安裝到/usr/local/arm下面 設定環境變數 gedit ~/.profile 在

arm的2級頁表在Linux核心建立過程解析

系統DDR的基地址為0x0,記憶體為1GB,所以TTB的基地址為0x4000。下面要建立虛擬地址0xfe700000到實體地址0xffff0000之間的對映,對映大小為64KB,即16頁。由於實體地址不是1MB位元組對齊,所以必須建立兩級對映。   使用者空間/核心空間

Ubuntu 14.04 LTS嵌入式交叉編譯環境arm-linux-gcc搭建過程圖解

1、將壓縮包arm-linux-gcc-3.4.5-glibc-2.3.6.tar.bz2存放在一個目錄下,這個目錄就是你等會解壓縮的目錄,以後這個目錄就不能隨便刪掉了,我的存放路徑是/home/g

arm linux編譯庫System.Net.Primitives.dll和System.Xml.XmlSerializer.dll

cad serial linu 5.4 mcs download 切換 mon dll 1.環境: /home/jello # uname -aLinux 3.10.0 #2 SMP Mon Mar 6 17:52:09 CST 2017 armv7l GNU/Linux

轉:Linux 程式編譯過程的來龍去脈

轉自:https://blog.csdn.net/p23onzq/article/details/81977367 大家肯定都知道計算機程式設計語言通常分為機器語言、組合語言和高階語言三類。高階語言需要通過翻譯成機器語言才能執行,而翻譯的方式分為兩種,一種是編譯型,另一種是解釋型,因此我們基本上

arm linux 系統呼叫過程

在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.h> 3:

Linux核心編譯以及新增系統呼叫函式

實驗內容 (作者:Baron_w,禁止轉載) ⚫ 編譯 Linux 核心 ⚫ Linux 啟動過程 ⚫ Linux 系統呼叫實現分析 ⚫ 增加一個系統呼叫** 相關知識 dmesg 的用法 ⚫ 列出載入到核心中的所有驅動 我們可以使用如‘more’。 ‘tail’ ,

linux核心編譯報錯1- error: expected specifier-qualifier-list before 'u_quad_t'

編譯核心出現 error: expected specifier-qualifier-list before 'u_quad_t' 錯誤。 解決方法: 在核心配置中有如下 File Systems ->    

用make-kpkg簡化Ubuntu系統的核心編譯過程

本文介紹的make-kpkg可以用於所有Debian系的發行版如Debian、Ubuntu、Linux Mint等。   傳統編譯方式 通常,如果我們需要編譯Linux核心,大概要經歷以下幾個步驟: 1、配置核心 最常用的配置核心的方法是“make menuconfig

Linux核心編譯初體驗

1. 下載核心 在ftp://ftp.kernel.org/pub/linux/kernel/下載原版核心 此處使用linux-2.6.22.6.tar.bz2 2. 解壓核心 tar -xjvf linux-2.6.22.6.tar.bz2 3. 打補丁 補丁