內核鏈接腳本

1、 arch/arm/kernel/vmlinux.lds 文件的生成

通過頂層Makefile中的規則生成vmlinux是根據arch/arm/kernel/vmlinux.lds這個腳本鏈接生成的。 arch/arm/kernel/vmlinux.lds是由arch/arm/kernel/vmlinux.lds.S生成的,其生成規則在 scripts/Makefile.build的第236行開始定義

quiet_cmd_cpp_lds_S = LDS     $@
      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<

%.lds: %.lds.S FORCE
       $(call if_changed_dep,cpp_lds_S)

2 、頂層vmlinux 的起始地址

在arch/arm/kernel/vmlinux.lds.S的開始處有

#ifdef CONFIG_XIP_KERNEL
       . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
       . = PAGE_OFFSET + TEXT_OFFSET; (即0xc0008000)
#endif

我們這裏的起始地址就是PAGE_OFFSET + TEXT_OFFSET。

在include/asm-arm/memory.h的49行開始有

#ifndef PAGE_OFFSET
#define PAGE_OFFSET        UL(0xc0000000)
#endif

而arch/arm/kernel/vmlinux.lds.S的開頭有

#include <asm/memory.h>

asm是一個符號,鏈接到asm-arm上的

在arch/arm/Makefile第140行,有

TEXT_OFFSET := $(textofs-y)

第90行有

textofs-y := 0x00008000

所以TEXT_OFFSET := 0x00008000

在153行有export TEXT_OFFSET將此變量輸出。這樣arch/arm/kernel/vmlinux.lds.S也就獲得了PAGE_OFFSET + TEXT_OFFSET的值。

3、 SEP4020 的虛實地址;

(1)在arch/arm/mach-sep4020/Makefile.boot文件定義了一個壓縮內核鏡像zImage的起始地址
   zreladdr-$(CONFIG_ARCH_4020)   := 0x30008000
這個地址在製作boot目錄下面的zImage,uImage時候會用到的,這可以在arch/arm/boot/Makefile中的21行有定義
ZRELADDR    := $(zreladdr-y)
PARAMS_PHYS := $(params_phys-y)
INITRD_PHYS := $(initrd_phys-y)
(2)在/include/asm-arm/arch-sep4020/memory.h中定義了一個物理的頁偏移地址,即sdram的地址
/*
* Page offset: 3GB
*/
#define PHYS_OFFSET        UL(0x30000000)
這個地址在啓動代碼arch/arm/kernel/head.s中會用到的:
#define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET) @其中TEXT_OFFSET = 0x8000
//swapper_pg_dir是放啓動時的臨時頁表的頁表基址(虛地址)
.globl swapper_pg_dir
.equ swapper_pg_dir, KERNEL_RAM_ADDR - 0x4000
在這部分要建立頁表的時候會用到這個地址的。

4、 壓縮的自引導鏡像arch/arm/boot/compressed/vmlinux 的起始地址

現在看看arch/arm/boot/compressed/makeflie生成的vmlinux。它是根據arch/arm/boot /compressed/vmlinux.lds鏈接腳本生成的。這個腳本由arch/arm/boot/compressed /vmlinux.lds.in生成,在這個文件的開始處有

. = TEXT_START;

現在看arch/arm/boot/compressed/Makefile,在110行有

$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
       @sed "$(SEDFLAGS)" < $ $@

這就是由vmlinux.lds.in生成vmlinux.lds的規則,在它的命令中有個變量SEDFLAGS,在74行定義

SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/

這裏就把TEXT_START換成了ZTEXTADDR。再往上看從arch/arm/boot/compressed/makeflie的66行起

ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR    := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR    := ALIGN(4)
endif

如果zImage是從ram中啓動ZTEXTADDR      := 0,否則從rom或flash啓動時ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT),這裏要在配置時設定CONFIG_ZBOOT_ROM_TEXT的值。

5、 /arch/arm/kernel/vmlinux.lds.s 鏈接文件的分析

下面先看下這個文件:
#include <asm-generic/vmlinux.lds.h>
#include <linux/config.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
      
OUTPUT_ARCH(arm)                /* 指定目標板體系結構 */
ENTRY(stext)                             /* 代碼段入口 */
jiffies = jiffies_64;                       /*/kernel/Timer.c 中定義的*/
SECTIONS                                /* 代碼段各部分 */
{
       . = PAGE_OFFSET + TEXT_OFFSET;    /* 代碼段起始地址,SEP4020 Linux 內核是0xC0008000 ,‘. ’表示連接地址*/
       .init : {                  /* 內核初始化的代碼和數據 */
              _stext = .;     /* 標號_stext 表示的就是起始地址0xc0008000*/
                     _sinittext = .;
                     *(.init.text)
                     _einittext = .;
              __proc_info_begin = .;
                     *(.proc.info.init)
              __proc_info_end = .;
              __arch_info_begin = .;
                     *(.arch.info.init)
              __arch_info_end = .;
              __tagtable_begin = .;
                     *(.taglist.init)
              __tagtable_end = .;
              . = ALIGN(16);
              __setup_start = .;
                     *(.init.setup)
              __setup_end = .;
              __early_begin = .;
                     *(.early_param.init)
              __early_end = .;
              __initcall_start = .;
                     *(.initcall1.init)
                     *(.initcall2.init)
                     *(.initcall3.init)
                     *(.initcall4.init)
                     *(.initcall5.init)
                     *(.initcall6.init)
                     *(.initcall7.init)
              __initcall_end = .;
              __con_initcall_start = .;
                     *(.con_initcall.init)
              __con_initcall_end = .;
              __security_initcall_start = .;
                     *(.security_initcall.init)
              __security_initcall_end = .;
              . = ALIGN(32);
              __initramfs_start = .;
                     usr/built-in.o(.init.ramfs)
              __initramfs_end = .;
              . = ALIGN(64);
              __per_cpu_start = .;
                     *(.data.percpu)
              __per_cpu_end = .;
       }
       /DISCARD/ : {                     /* 內核退出的代碼和數據 */
              *(.exit.text)
              *(.exit.data)
              *(.exitcall.exit)
       }
       .text : {                 /* 真正的代碼段部分 */
              _text = .;        /* 代碼和只讀數據 */
                     *(.text)
                     SCHED_TEXT
                     LOCK_TEXT
                     *(.fixup)
                     *(.gnu.warning)
                     *(.rodata)
                     *(.rodata.*)
                     *(.glue_7)
                     *(.glue_7t)
              *(.got)                  /* Global offset table             */
       }
       RODATA
       _etext = .;                     /* 代碼段和只讀數據結束 */
       . = ALIGN(THREAD_SIZE);
       __data_loc = .;
       .data : AT(__data_loc) { /* 數據段起始 */
              __data_start = .;    /* 內存中的地址 */
              /*
              * first, the init task union, aligned
              * to an 8192 byte boundary.
              */
              *(.init.task)
              . = ALIGN(4096);
              __nosave_begin = .;
              *(.data.nosave)
              . = ALIGN(4096);
              __nosave_end = .;
              /*
              * then the cacheline aligned data
              */
              . = ALIGN(32);
              *(.data.cacheline_aligned)
              /*
                 /* 例外修正表(可能需要在運行時修正) */
              */
              . = ALIGN(32);
              __start___ex_table = .;
              *(__ex_table)
              __stop___ex_table = .;
              /*
                 /* 普通的數據段 */
              */
              *(.data)
              CONSTRUCTORS
              _edata = .;
       }
       .bss : {                                /* 未初始化的全局變量 */
              __bss_start = .;      /* BSS                         */
              *(.bss)
              *(COMMON)
              _end = .;
       }
                            /* 調試信息和數據段.*/
       .stab 0 : { *(.stab) }
       .stabstr 0 : { *(.stabstr) }
       .stab.excl 0 : { *(.stab.excl) }
       .stab.exclstr 0 : { *(.stab.exclstr) }
       .stab.index 0 : { *(.stab.index) }
       .stab.indexstr 0 : { *(.stab.indexstr) }
       .comment 0 : { *(.comment) }
}
/*
* These must never be empty
* If you have to comment these two assert statements out, your
* binutils is too old (for other reasons as well)
*/
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章