内核链接脚本

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")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值