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")