24小時學通Linux內核之構建Linux內核

24小時學通Linux內核之構建Linux內核html

  今天是臘八節,說好的女票要給我作的臘八粥就這樣泡湯了,好傷心,好心酸呀,看來代碼寫久了真的是惹人煩滴,因此告誡各位技術男敲醒警鐘,不要想我看齊,否則就只能和代碼爲伴了的~~話說沒了臘八粥但仍是有代碼,還有各位讀者的支持呀,因此得繼續寫下去,靜下心來,完成Linux內核的學習,堅持,加油~linux

  到目前爲止,咱們已經認識了Linux內核子系統,也探究了系統的初始化過程,而且深刻探索了start_kernel()函數,一樣,瞭解內核映像的建立也是很是重要的,接下來將討論一下內核映像的編譯和連接過程,那麼這些固然須要工具鏈了,工具鏈包含編譯程序、彙編程序、連接程序,是建立Linux內核映像的一組程序集合,下圖說明了工具鏈的鏈式關係:shell

ELF二進制目標文件

可執行ELF目標文件包括:ELF頭,程序頭表(用於加載的節),第1節,第2節。。。。節頭表(可選)編程

ELF頭文件架構

typedef struct elf32_hdr{
  unsigned char e_ident[EI_NIDENT]; //標識該文件是否爲ELF文件
  Elf32_Half    e_type;  //指定目標文件類型,例如可執行文件,重定位文件,共享的目標文件
  Elf32_Half    e_machine;   //被編譯文件所在系統的體系結構
  Elf32_Word    e_version; //目標文件的版本
  Elf32_Addr    e_entry;  /* Entry point */  //程序的起始地址
  Elf32_Off     e_phoff;   //保存程序頭表在文件中的偏移量
  Elf32_Off     e_shoff;   //保存節頭表在文件中的偏移量
  Elf32_Word    e_flags;   //保存於特定與處理器的標誌
  Elf32_Half    e_ehsize;  //字段保存ELF頭的大小
  Elf32_Half    e_phentsize;  //保存程序頭表中的每一項的大小
  Elf32_Half    e_phnum;  //程序頭中表項的個數
  Elf32_Half    e_shentsize;  //節頭表中每一項的大小
  Elf32_Half    e_shnum;   //保存節頭中項的數量,代表該文件中有多少節
  Elf32_Half    e_shstrndx;  //保存節頭中節字符串的索引
} Elf32_Ehdr;

節頭表ide

typedef struct elf32_shdr {
  Elf32_Word    sh_name;   //包含節名
  Elf32_Word    sh_type;   //包含節的內容
  Elf32_Word    sh_flags;  //各類屬性的內容
  Elf32_Addr    sh_addr;   //節在內存映像中的地址 
  Elf32_Off     sh_offset; //保存ELF文件中這一節中初始字節的偏移量
  Elf32_Word    sh_size;   //包含節的大小
  Elf32_Word    sh_link;   //表連接的索引
  Elf32_Word    sh_info;   //包含附加信息
  Elf32_Word    sh_addralign;  //包含地址對其的約束
  Elf32_Word    sh_entsize;  //節中每項的大小
} Elf32_Shdr;

非可執行ELF文件節函數

節點 說明
.data 已初始化的數據
bss 爲初始化的數據
.hash 符號散列表
.init 初始化代碼
.symtab  符號表
.text   可執行的指令
.plt   過程連接表
.rodata  只讀數據
dynamic 動態連接信息

 

 

 

 

 

 

 

 

 

 

程序頭表工具

typedef struct elf64_phdr {
  Elf64_Word p_type;    //描述該段的類型
  Elf64_Word p_flags;   //以p_type而定
  Elf64_Off p_offset;   //<span style="font-family: Arial, Helvetica, sans-serif;">該段的開始相對於文件開始的偏移量</span>
  Elf64_Addr p_vaddr;   //段虛擬地址
  Elf64_Addr p_paddr;   //段的虛擬地址  
  Elf64_Xword p_filesz; //文件映像中該段的字節數
  Elf64_Xword p_memsz;  //內存映像中該段的字節數
  Elf64_Xword p_align;  //描述要對齊的段在內存中如何對齊,該值是2的整數次冪    
} Elf64_Phdr; 

經過這些信息,系統函數exec()和連接程序合做,爲可執行程序在內存中建立進程映像,該過程以下:post

  • 將可執行文件的段加入內存
  • 加載全部須要的共享庫
  • 須要時重定向可執行文件及其共享對象
  • 將控制權交給程序

  

  那麼內核是如何被編譯成二進制文件的呢,又是如何在執行前裝入內存。下面將開始介紹編譯內核源代碼。內存啓動始於執行arch/x86/boot/目錄中的實模式彙編代碼。查看arch/x86/kernel/setup_32.c文件能夠看出保護模式的內核怎樣獲取實模式內核收集的信息。第一條信息來自於init/main.c中的代碼,深刻挖掘init/calibrate.c能夠對BogoMIPS校準理解得更清楚,而include/asm-your-arch/bugs.h則包含體系架構相關的檢查。學習

  內核中的時間服務由駐留於arch/your-arch/kernel/中的體系架構相關的部分和實現於kernel/timer.c中的通用部分組成。從include/linux/time*.h頭文件中能夠獲取相關的定義。

  jiffies定義於linux/jiffies.h文件中。HZ的值與處理器相關,能夠從include/asm-your-arch/ param.h找到,內存管理源代碼存放在頂層mm/目錄中。

Linux的官方源代碼發佈網址是www.kernel.org。其源代碼目錄結構示意圖以下:

  利用內核配置工具自動生成.config的內核配置文件,這是編譯的第一步,.config文件位於源代碼目錄下,其選項的位置根據它們在內核配置工具中的位置進行排序,咱們來看看一個.config文件的節選:

 1 #
 2 # Automatically generated make config: don't edit
 3 # 4 CONFIG_X86=y 5 CONFIG_MMU=y 6 CONFIG_UID16=y 7 CONFIG_GENERIC_ISA_DMA=y //這4行位於頂層菜單中 8 9 # 10  # Code maturity level options 11  # 12 CONFIG_EXPERIMENTAL=y 13 CONFIG_CLEAN_COMPILE= 14 CONFIG_STANDALONE=y 15 CONFIG_BROKEN_ON_SMP=y  //這4行位於代碼成熟度選項菜單中 16 17  # 18  # General setup 19  # 20 CONFIG_SWAP=y 21 CONFIG_SYSVIPC=y 22 #CONFIG_POSIX_MQUEUE is not set 23 CONFIG_BSD_PROCESS_ACCT=y  //這4行位於通用設置選項菜單中

  

  最後來粗略的介紹一下Linux內核的Makefile文件,也只能簡單的介紹一下啦,這個但是重難點,這裏我稍微說一下,之後會具體去學習。Linux內核是一種單體內核,可是經過動態加載模塊的方式,使它的開發很是靈活 方便。那麼,它是如何編譯內核的呢?咱們能夠經過分析它的Makefile入手。如下是 一個簡單的hello內核模塊的Makefile. 

ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
        $(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:
        rm -rf *.o *.mod.c *.mod.o *.ko
endif

  首先,因爲make 後面沒有目標,因此make會在Makefile中的第一個不是以.開頭的目標做爲默認的目標執行。因而default成爲make的目標。make會執行 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules shell是make內部的函數,make執行了兩次。

第一次執行時是讀hello模塊的源代碼所在目錄/home/s tudy/prog/mod/hello/下的Makefile。

第二次執行時是執行/usr/src/linux/下的Makefile時. 

這其中很複雜,我也不知道怎麼講了。關於make modules的更詳細的過程能夠在scripts/Makefile.modpost文件的註釋 中找到。不過我找到了一個大牛寫的跟我一下學Makefile的博客,我把博客地址附在下面,供你們參考一下:http://blog.csdn.net/haoel/article/details/2886/

 

  小結

  本章探究了目標文件的編譯,連接過程,以及目標文件的結構,以便理解可執行代碼的最終形式,構建Linux內核涵蓋了內核編譯所須要的工具,最後還簡單的描述了Makefile,,這些都是難點,,得多加縮習啦,,儘管今天沒吃到臘八粥,可是轉轉鍋仍是很給力的,吃到如今還不餓,是一個難忘的一天  ~~

 

  版權全部,轉載請註明轉載地址:http://www.cnblogs.com/lihuidashen/p/4253752.html

相關文章
相關標籤/搜索