非常好!!!Linux源代碼閱讀——環境准備【轉】


Linux源代碼閱讀——環境准備

轉自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/0_prepare.html

目錄

  1. Linux 系統環境准備
    • 定制安裝 Ubuntu
    • 安裝工具鏈
  2. 編譯 Linux 內核
    • 默認編譯
    • 自定義編譯
  3. 模擬執行 Linux
    • 用 qemu 模擬 Hello World 系統
  4. 准備源碼閱讀環境
    • vim 基本設置
    • 在 vim 中使用 cscope
    • 在 vim 中使用 ctags
    • 使用 taglist 顯示 symbol 窗口
  5. Linux 內核源代碼結構

1 Linux系統環境准備

1.1 定制安裝Ubuntu

  1. 從科大源下載 Ubuntu Alternative CD,校驗 MD5。
  2. 掛載 ISO,使用 preseed 文件來進行一些預定制,參考 http://pxe.ustc.edu.cn/boot/conf/preseed.debian.ustc.cfg(當然其中的 debian 需要改為 ubuntu,hostname 改成自己希望的主機名),指定安裝所使用的源,以及其他一些預定義設置。
  3. 卸載ISO,使用 usb-creator-gtk 制作啟動U盤。
  4. 使用 parted 分區:將硬盤的一個空閑 NTFS 分區刪除;mkpartfs 建立一個ext2(用於/boot)、一個swap、一個ext4(用於根分區)。
  5. 從U盤啟動,選擇 Install a command-line system,設置鍵盤、分區等(其他設置已經寫在 preseed 中了),安裝基本系統,設置用戶名密碼。
  6. grub-mkimage 制作包含 reiserfs 模塊的 grub2(原有的 linux 所在分區是 reiserfs 的),grub-mkconfig 更新 grub.cfg 配置文件。
  7. 安裝 X(xserver-xorg)、GNOME 桌面環境(gdm、gnome-core、xinit、gnome-utils、synaptic)
  8. 安裝中文語言包(language-pack-zh-base、language-support-fonts-zh、xfonts-wqy、language-selector),修改 locale
  9. 安裝輸入法(fcitx)、vim等
  10. 安裝、設置聲卡驅動(alsa)(特定硬件的驅動問題,采用網上的辦法)
  11. 安裝 ntfs-3g、wine 等系統工具,tcpdump、firefox、filezilla、amule 等網絡工具,okular、chmsee、libreoffice 等辦公工具
  12. 安裝 ssh、nginx、php5-fpm、MySQL、memcached、vsftpd 等服務器需要的 daemon(網絡開發用)
  13. apt-get clean 清除緩存
  14. 編輯 /etc/modules,開機加載 fuse(用戶態文件系統)模塊,以便使用 ntfs-3g
  15. 編輯 /etc/fstab 將 /dev/sda4(NTFS)自動掛載上,為方便 Windows 使用,學習資料等數據放在這個分區。
    # <file system> <mount point>   <type>  <options>       <dump>  <pass>
    proc            /proc           proc    nodev,noexec,nosuid 0       0
    # / was on /dev/sda2 during installation
    UUID=d993c54c-0602-48d2-935f-be9ac654f9a0 /               ext4    errors=remount-ro 0       1
    /dev/sda1       none            swap    sw              0       0
    /dev/sda4	/media/DATA	ntfs-3g	silent,umask=0,locale=zh_CN.utf8	0	0
    

1.2 安裝工具鏈

  • 編譯內核所需工具鏈:
    • build-essential (gcc, make, ld等)
    • binutils
    • libncurses-dev (make menuconfig 時需要)
    • kernel-package
  • 模擬內核所需工具:
    • qemu
    • gdb
    • fakeroot (chroot)
    • initramfs-tools
    • module-init-tools

2 編譯Linux內核

2.1 默認編譯

  1. 從 kernel.org 下載 Linux 2.6.26 源碼,tar -zvxf
  2. make mrproper 清除所有已編譯文件和配置文件
  3. make i386_defconfig 生成x86體系結構的默認配置。此過程首先HOSTCC、SHIPPED、HOSTLD一些配置文件,然后進入 Linux Kernel Configuration,與 make config 的命令行界面相同,只是所有選項都被自動選擇了(具體參見 arch/x86/configs/i386_defconfig)。
  4. make 編譯代碼。由CC、LD、AR、AS、GEN、HOSTCC、OBJCOPY、BUILD等過程組成。其中有一些 warning,是因為代碼不符合當前C標准,可以忽略。
    BUILD   arch/x86/boot/bzImage
    Root device is (8, 2)
    Setup is 10140 bytes (padded to 10240 bytes).
    System is 2651 kB
    CRC e3791c7
    Kernel: arch/x86/boot/bzImage is ready  (#1)
    

2.2 自定義編譯

  1. 每次更改配置重新編譯前,make clean 清除上次編譯的目標文件和中間文件,但保留配置文件以便在其基礎上修改。
  2. make menuconfig 進入終端下的菜單選擇。相比完全命令行界面的 config,用起來更方便;而圖形界面的 xconfig 或 gconfig 雖然比較直觀,但不便於使用鍵盤。
  3. 設置完畢,保存到 .config
  4. make 編譯代碼,生成的內核映像是 arch/x86/boot/bzImage
    Root device is (8, 2)
    Setup is 10140 bytes (padded to 10240 bytes).
    System is 3063 kB
    CRC aa68b290
    Kernel: arch/x86/boot/bzImage is ready  (#3)
      Building modules, stage 2.
      MODPOST 26 modules
    
  5. 由於我們是在虛擬機內運行而不是安裝到本地系統,因此不需要 make install

具體設置參考:Linux 2.6.19.x 內核編譯配置選項簡介(金步國)

  • General Setup
    • 為 local version 賦予一個惟一的自定義版本號(如boj1),以免不同的內核發生混淆
    • 選中 Auditing Support,以方便以后試驗 SELinux
    • 要選中 Initramfs,現在 Linux 啟動一般都用 initramfs(原來的 initrd)
  • Loadable Module Support
    • modprobe 時需要使用
    • 選中 Automatic kernel module loading,讓內核通過運行 modprobe 來自動加載所需要的模塊,自動解決模塊的依賴關系
  • Enable the block layer
    • 塊設備需要使用
    • Large Block Device 暫時不需要,沒有 2TB 以上的塊設備
  • Processor Type and Features
    • 根據 /etc/cpuinfo,當前的CPU是 Intel(R) Core(TM) Duo CPU T2250 @ 1.73GHz
      因此選擇 Core 2/Newer Xeon。
    • 由於只在自己的計算機上使用,取消 Generic x86 support。
    • 由於自己的CPU是雙核的,Maximum number of CPUs 設為2,每個CPU在內核映像中占據8KB。
    • High Memory Support 選擇 4G(由於內存是2.5G的)
    • Timer Frequency 由於是桌面系統,對實時性要求較高,設為 1000Hz。
  • Power management options
    • 選中 Hibernation,以實現休眠功能
  • Bus options
    • 選中 PCI Express Support,顯卡和網卡都需要
  • Executable file formats
    • Kernel support for MISC binaries 允許插入二進制的封裝層到內核中,使用 Java 等語言編寫的程序時需要它
  • Networking Support
    • Networking options
      • 選中 Packet Socket 和 mmaped IO,以便使用網絡監控工具。
      • 選中 TCP Syncookie support,抵抗 SYN flood 攻擊。需要同時啟用 /proc 文件系統和 Sysctl support,然后在系統啟動並掛載了 /proc 之后執行 "echo 1 >/proc/sys/net/ipv4/tcp_syncookies" 命令。
      • 選中 Network packet filtering,Netfilter 對數據包進行過濾和修改。
        • 選中 IPv4/IPv6 connection tracking support,以使用 NAT。
        • 選中 IP tables 和 ARP tables,經常需要用。其中選中 Full NAT 以便使用 iptables 中的 NAT 功能。
        • 選中 IP6 tables support,監控 IPv6 協議需要用。
      • 選中 Network Testing 中的 Packet Generator(編譯為 pktgen 模塊),方便網絡測試。
    • 選中 Ameteur Radio Support,因為我們要玩無線電。AX.25 協議編譯為 ax25 模塊。
    • 將 IrDA (infrared) subsystem support 編譯為 irda 模塊,以便使用無線鼠標鍵盤。
    • 選中 Bluetooth subsystem support,藍牙經常要用。
    • 選中 Generic IEEE 802.11 Networking Stack,wifi 等都是基於 802.11 的協議。
  • Device Drivers
    • Block Devices
      • 取消 Normal Floppy Disk support,沒有軟驅
      • 需要選中 RAM block device support,initrd 需要用。
        Menuconfig Help 中說
          │ Saying Y here will allow you to use a portion of your RAM memory as
          │ a block device, so that you can make file systems on it, read and
          │ write to it and do all the other things that you can do with normal
          │ block devices (such as hard drives). It is usually used to load and
          │ store a copy of a minimal root file system off of a floppy into RAM
          │ during the initial install of Linux.
        
        Most normal users won't need the RAM disk functionality, and can thus say N here.
        
        因此第一次配置時沒有編譯進內核,導致虛擬機無法啟動:
        [   0.776881] Unpacking initramfs...<0>Kernel panic - not syncing: bad gzip magic numbers
    • ATA/ATAPI/MFM/RLL support
      • 取消 Include IDE/ATA-2 DISK support
    • SCSI device support
      • 選中 RAID Transport Class,將來可能折騰 RAID
    • Multiple devices driver support (RAID and LVM)
      • 將 RAID support 及相關選項編譯為模塊,以使用軟RAID。
      • 選中 Device Mapper support,以使用 LVM。
    • 取消 Macintosh device drivers
    • Multimedia devices
      • 選中 Video for Linux,以便進行攝像頭編程
    • Sound
      • 選中 Advanced Linux Sound Architechture,計算機上的聲卡需要用 ALSA。
      • 取消 Open Sound System
    • 選中 Real Time Clock,以便獲取系統時間
    • 選中 DMA Engine Support,以便使用 Direct Memory Access
  • Firmware Drivers
    沒有特殊固件,因此保留默認配置。
  • File Systems
    • ext2、ext3、ext4 都是 Linux 經典文件系統,經常需要用到,編譯進內核
    • ReiserFS 對於小文件的處理效率很高,有個存放各種源代碼的分區用這個文件系統,編譯進內核
    • 選中 Filesystem in Userspace Support,ntfs-3g 是基於 fuse 的,這樣不用每次開機都加載 fuse 模塊。
    • 微軟文件系統:不選 NTFS 文件系統支持,內核中對於 NTFS 寫的支持不好,使用用戶態的 ntfs-3g 代替。
    • 本地語言支持:默認本地語言設為 utf-8,選中 Codepage 437, GB2312, Big5, ASCII, ISO 8859-1, UTF-8.
  • Kernel Hacking
    • 選中 Show timing information on printks,方便內核調試
    • 選中 Magic SysRq key,在緊急狀態時使用 reisub 奪回系統控制權
  • Security Options
    暫時不需要其他安全模型,保留默認值,全不選。
  • Cryptographic options
    將 MD5、SHA1、Blowfish、DES 等常用加密算法編譯為模塊備用。
  • Virtualization
    電腦硬件不支持 KVM,因此不選。
  • Library routines
    保留默認值。

3 模擬執行 Linux

3.1 用 qemu 模擬 Hello World 系統

  1. 寫一個 Hello World 程序:
    [boj@boj-laptop:~/test]$ cat test.c
    #include<stdio.h>
    int main() {
    	printf("Hello World!");
    	return 0;
    }
    
  2. 靜態鏈接編譯
    [boj@boj-laptop:~/test]$ gcc -static -o init test.c
  3. 建立目標根目錄映像
    [boj@boj-laptop:~/test]$ dd if=/dev/zero of=initrd4M.img bs=4096 count=1024
    [boj@boj-laptop:~/test]$ mke2fs initrd4M.img
    [boj@boj-laptop:~/test]$ mkdir rootfs
    [boj@boj-laptop:~/test]$ sudo mount -o loop initrd4M.img rootfs
    
  4. 將init拷貝到目標根目錄下
    [boj@boj-laptop:~/test]$ cp init rootfs/
  5. 准備 /dev 目錄、console 設備、linux 根設備(ram)
    [boj@boj-laptop:~/test]$ sudo mkdir rootfs/dev
    [boj@boj-laptop:~/test]$ sudo mknod rootfs/dev/console c 5 1
    [boj@boj-laptop:~/test]$ sudo mknod rootfs/dev/ram b 1 0
    [boj@boj-laptop:~/test]$ sudo umount rootfs
    
  6. 用 qemu 模擬運行
    [boj@boj-laptop:~]$ qemu -kernel linux-2.6.26/arch/x86/boot/bzImage -initrd test/initrd4M.img -append "root=/dev/ram init=/init"
    

    一段初始化后,輸出了 Hello World,隨即 Kernel Panic(因為 init 在輸出字符串后就自行退出了)

    [    4.270006] Freeing unused kernel memory: 244k freed
    Hello World![    4.326627] Kernel panic - not syncing: Attempted to kill init!

4 准備源碼閱讀環境

4.1 vim 基本設置

[boj@boj-laptop:~]$ cat ~/.vimrc
set encoding=UTF-8
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
set fileencoding=utf-8
sy on
set ai
set nu
set shiftwidth=2
set tabstop=4
set softtabstop=4
set ic "搜索時忽略大小寫,以便在某些“駱駝”變量名風格的源碼中查找

4.2 在 vim 中使用 cscope

  1. 安裝 CScope:
    sudo apt-get install cscope
  2. 確認 vim 支持 cscope:
    vim --version | grep cscope
  3. 給源代碼建立索引:
    cscope -Rbq

    其中,ctags 遞歸的在每個目錄下生成 tags 文件,供 vim 讀取;cscope 生成 cscope.out

    cscope.out: cscope reference data version 15 with inverted index
  4. 將以下內容添加到 ~/.vimrc 中,以自動加載 cscope.out。
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " cscope setting
    
    if has("cscope")
       set csprg=/usr/bin/cscope              "指定用來執行 cscope 的命令
       set csto=1                             "先搜索tags標簽文件,再搜索cscope數據庫
       set cst                                "使用|:cstag|(:cs find g),而不是缺省的:tag
       set nocsverb                           "不顯示添加數據庫是否成功
       " add any database in current directory
       if filereadable(ncscope.out")
          cs add cscope.out                   "添加cscope數據庫
       endif
       set csverb                             "顯示添加成功與否
    endif
    
    nmap <C-@>s :cs find s <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>g :cs find g <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>c :cs find c <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>t :cs find t <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>e :cs find e <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
    nmap <C-@>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
    nmap <C-@>d :cs find d <C-R>=expand("<cword>")<CR><CR>
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    
  5. 根據上面的 .vimrc,使用簡單的組合鍵和字母即可使用 cscope 的查找功能。

    例如,<C-@>g 先按 ctrl+@,再按 g,即可查看當前光標所在符號的定義。

    :cs help

    • s: 查找 C 語言符號,即查找函數名、宏、枚舉值等出現的地方
    • g: 查找函數、宏、枚舉等定義的位置,類似 ctags 所提供的功能
    • d: 查找本函數調用的函數
    • c: 查找調用本函數的函數
    • t: 查找指定的字符串
    • e: 查找 egrep 模式,相當於 egrep 功能,但查找速度快多了
    • f: 查找並打開文件,類似 vim 的 find 功能
    • i: 查找包含本文件的文件

4.3 在 vim 中使用 ctags

在源代碼根目錄下執行 ctags -R 命令用來為程序源代碼生成標簽文件,-R 選項表示遞歸操作,同時為子目錄也生成標簽文件。vim 利用生成的標簽文件,可以進行相應檢索、並在不同的文件中的C語言元素之間來回切換。

需要在 tags 文件所在的目錄下運行 vim。否則,要用 :set tags=xxx 指定 tags 文件的路徑。

使用 tag 命令時,可以使用 TAB 鍵進行匹配查找,繼續按 TAB 鍵向下切換。

  • 跳到函數或數據結構xxx處
    :tag xxx
  • 跳到第一個定義處,優先跳轉到當前文件
    :tnext
  • 跳到第一個
    :tfirst
  • 跳到前 count 個
    :[count]tprevious
  • 跳到后 count 個
    :[count]tnext
  • 跳到最后一個
    :tlast
  • 在所有 tagname 中選擇
    :tselect tagname
  • 跳到包含 block 的標識符
    :tag /block 

    (這里 '/' 就是告訴 vim,'block' 是一個語句塊標簽。)

  • 跳轉到光標所在函數標識符的定義處
    Ctrl+]
  • 使用"ctrl+t"退回上層
    Ctrl+t
  • 在以 write_ 開頭的標識符中選擇
    :tselect /^write_
    這里,'^'表示開頭,同理,'$'表示末尾。

在函數中移動光標的快捷鍵:

  • [{ 轉到上一個位於第一列的"{"
  • }] 轉到下一個位於第一列的"{"
  • { 轉到上一個空行
  • } 轉到下一個空行
  • gd 轉到當前光標所指的局部變量的定義
  • * 轉到當前光標所指的單詞下一次出現的地方
  • # 轉到當前光標所指的單詞上一次出現的地方

4.4 使用 taglist 顯示 symbol 窗口

taglist 插件可以像 Source Insight 那樣將當前文件中的宏、全局變量、函數等 tag 顯示在 Symbol 窗口,用鼠標點上述 tag,就跳到該 tag 定義的位置;可以按字母序、該tag所屬的類或scope,以及該 tag 在文件中出現的位置進行排序;如果切換到另外一個文件,Symbol 窗口更新顯示這個文件中的 tag。taglist 依賴於 ctags。

  1. 打開 vim 的文件類型自動檢測功能;
  2. 系統中裝了 Exuberant ctags 工具,並且 taglist 能夠找到此工具(因為 taglist 需要調用它來生成 tag 文件);
  3. vim 支持 system() 調用;
  4. 在 ~/.vimrc 中加入
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " ctags setting
    set tags=./tags,./../tags,./*/tags;
    
    " Tag list (ctags)
    
    filetype on                            "文件類型自動檢測
    
    if MySys() == "windows"                "設定windows系統中ctags程序的位置
       let Tlist_Ctags_Cmd = 'ctags'
    elseif MySys() == "linux"              "設定linux系統中ctags程序的位置
       let Tlist_Ctags_Cmd = '/usr/bin/ctags'
    endif
    
    let Tlist_Show_One_File = 1            "不同時顯示多個文件的tag,只顯示當前文件的
    let Tlist_Exit_OnlyWindow = 1          "如果taglist窗口是最后一個窗口,則退出vim
    let Tlist_Use_Right_Window = 1         "在右側窗口中顯示taglist窗口 
      
    map <silent> <F8> :TlistToggle<cr>     "在映射F8鍵打開tags窗口
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    

上述配置過程參考了:http://www.cnblogs.com/sunblackshine/archive/2011/08/25/2152962.html

5 Linux 內核源代碼結構

Linux 2.6.26 源碼各目錄大致作用:

  • Documentation/ 內核文檔,包括 CodingStyle 等
  • include/子目錄包含了建立內核代碼時所需的大部分包含文件,這個模塊利用其它模塊重建內核。每種體系結構有相應的子目錄。
  • init/ 子目錄包含了內核的初始化代碼,這是內核開始工作的起點。(main.c, function start_kernel)
  • arch/ 子目錄包含了所有硬件結構特定的內核代碼,在 x86 體系結構下,包括 kernel、mm、lib 等子目錄,分別是與體系結構相關的核心、內存管理、庫代碼。
  • drivers/ 目錄包含了內核中所有的設備驅動程序,如字符設備、塊設備。
  • fs/ 目錄包含了所有文件系統的代碼,如:ext2、vfat、proc。
  • net/ 目錄包含了內核的網絡代碼。
  • mm/ 目錄包含了所有的內存管理代碼。
  • ipc/ 目錄包含了進程間通信的代碼。
  • kernel/ 目錄包含了主內核代碼
  • lib/ 目錄包含了與體系結構無關的內核庫代碼
  • modules/ 目錄包含了可動態加載的模塊。
  • Scripts/ 目錄包含了配置核心的腳本文件。

Copyright © 2012 李博傑 PB10000603

This document is available from http://home.ustc.edu.cn/~boj/courses/linux_kernel/0_prepare.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM