linux内核空间分布解析
SECTIONS
{
. = TEXTADDR; /* 表示内核编译后链接的首地址,由arch/arm/makefile编译选项指定,如果是armv版本,则一般指定为0xc0008000,这是linux内核起来后,mmu起作用时的内核空间地址,这个值跟具体的处理器体系有关,需要额外指定的.*/
.init : { /* Init code and data */
_stext = .; /* 段名称,在c函数中可以通过此名称来访问这段存储器上的变量,此段名称被head_armv.s文件引用,用于记录起始程序段的地址。*/
__init_begin = .; /* 初始化代码和数据的开始名称,c函数可以通过此名称来访问其中的变量*/
*(.text.init) /* 用于初始化的代码段,一般是指定head_armv.s和其他*.s文件到这里,在c语言中以"__init"作为前缀的函数也将被摆放在这个区间中,然后在kernel启动时,按照摆放的先后顺序依次执行一次。*/
__proc_info_begin = .; /* 此处存放的是此kernel所支持的处理器列表c函数可以通过此名称来访问其中的变量,以便获得处理器信息,在setup_processor()函数中调用。*/
*(.proc.info) /* 此列表一般在arch/arm/mm/proc-arm926.S文件中指定变量内容,具体内容见后面的结构体介绍,在嵌入式系统中,一般此处只有一个结构体。*/
__proc_info_end = .; /* 处理器列表结构体结束标志,可以通过c函数访问此变量*/
__arch_info_begin = .; /* 架构信息开始结构体变量,可以通过c函数访问此结构体,在setup_machine()函数中调用*/
*(.arch.info) /* 汇编文件中没有使用,而是在mach/arch.h文件中使用,用于定义MACHINE_START这个宏的属性,此宏定义了machine_desc结构体的初始化信息,此结构体的具体信息参加下面的描述。*/
__arch_info_end = .; /* 架构信息结束变量*/
__tagtable_begin = .; /* tag表开始变量,在setup.c文件的parse_tag()函数中调用,具体结构体参数列表如下面所述*/
*(.taglist) /* c文件中所有含有__tag前缀的结构体将存储器这个区域中。主要是setup.c文件中定义了若干处理tag的函数,用于分析linux启动参数,这个已经是老的启动参数传递和处理模式了。tag号是一组宏,固定了每个tag的意义。*/
__tagtable_end = .; /* tag表结束变量*/
*(.data.init) /* 初始化的数据区,c文件中所有表示“__initdata”前缀的数据都将存储在这个地方,例如default_command_line等数组都是存储在这个地方的。*/
. = ALIGN(16);
__setup_start = .; /* 此变量在init/main.c文件中被使用,主要用来处理commandline变量的*/
*(.setup.init) /* c函数中所有含有"__initsetup"前缀的函数将都存储在这个区域中*/
__setup_end = .; /* 这个区域是为了保持对老版本的兼容,在新版本中,此结构体已经基本不再使用了,即处理commandline的函数由上面的其他函数替代了。*/
__initcall_start = .; /* 此变量在init/main.c文件中被使用,主要是在初始进程init起来后作一些基础设备配置时调用的,do_basic_setup()此函数调用do_initcalls()实现对此区域中的函数的调用。*/
*(.initcall.init)/* c函数中所有含有"__init_cal"前缀的函数都将被摆放在这个区域中。*/
__initcall_end = .; /* 在现在的kernel中,这个部分的init函数也基本没有了。*/
. = ALIGN(4096); /* 页对齐*/
__init_end = .; /* 初始函数和数据结束。*/
}
/DISCARD/ : { /* Exit code and data */
*(.text.exit) /* c函数中所有含有"__exit"前缀的函数都存放在这个区域,当函数退出或者系统关机时将自动被调用,在driver程序中被广泛使用*/
*(.data.exit) /* c函数中所有含有"__exitdata"前缀的数据都摆放爱这个区域。系统中很少使用这个区域存放信息。*/
*(.exitcall.exit) /* c函数中所有含有"__exit_call"前缀的数据都摆放爱这个区域。系统中很少使用这个区域存放此类函数。*/
}
.text : { /* Real text segment */
_text = .; /* Text and read-only data */
*(.text) /* 所有其他普通代码都放在此区域*/
*(.fixup) /* 驱动和.s文件中定义的一些fixup类型的函数*/
*(.gnu.warning) /* gnu的warning信息*/
*(.rodata) /* read-only 数据*/
*(.rodata.*) /* 所有其他read-only数据*/
*(.glue_7) /* */
*(.glue_7t)
*(.got) /* Global offset table */
_etext = .; /* End of text section */
}
.kstrtab : { *(.kstrtab) } /* kstrtab类型的函数放置在此区域,主要是在insmod.c函数中注册驱动时使用的.*/
/* Kernel string table*/
. = ALIGN(16);
__ex_table : { /* Exception table */
__start___ex_table = .; /* 异常处理函数组开始变量*/
*(__ex_table)
__stop___ex_table = .; /* 异常处理函数组结束变量*/
}
__ksymtab : { /* Kernel symbol table */
__start___ksymtab = .; /* 内核符号表开始变量*/
*(__ksymtab)
__stop___ksymtab = .; /* 内核符号表结束变量*/
}
. = ALIGN(8192);
.data : { /* 数据段*/
/*
* first, the init task union, aligned
* to an 8192 byte boundary.
*/
*(.init.task) /* 进程初始化时的一些数据常数和全局变量*/
/*
* then the cacheline aligned data
*/
. = ALIGN(32);
*(.data.cacheline_aligned) /* cacheline对齐相关的数据常数和全局变量*/
/*
* and the usual data section
*/
*(.data) /* 普通数据常数和全局变量*/
CONSTRUCTORS
_edata = .;
}
.bss : { /* 变量段*/
__bss_start = .; /* BSS 变量段开始标志 */
*(.bss) /* 普通变量段*/
*(COMMON) /* common段*/
_end = . ; /* 此处一般就是代码段的结尾了.*/
}
/* Stabs debugging sections. */
.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) }
}
kernel所支持的处理器信息结构体如下:
struct proc_info_list {
unsigned int cpu_val; /* 处理器特征值*/
unsigned int cpu_mask; /* 处理器特征值掩码*/
unsigned long __cpu_mmu_flags; /* used by head-armv.S */
unsigned long __cpu_flush; /* used by head-armv.S */
const char *arch_name; /* 处理器体系名称变量地址*/
const char *elf_name; /* elf名称变量地址*/
unsigned int elf_hwcap; /* elf标志字*/
struct proc_info_item *info; /* 处理器结构信息变量地址,包括处理器名称,体系等可以供人阅读的信息*/
struct processor *proc; /* 处理器函数变量地址,此处定义了一组用汇编编写的处理此体系处理器的底层函数列表*/
};
此结构体一般是在arch/arm/mm/proc-arm926.S中固定赋值。即编译时支持哪个体系的处理器结构,就会在列表中指名此值。
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head-armv.S
*/
unsigned int nr; /* architecture number 架构号,在mach-types.h中统一定义的*/
unsigned int phys_ram; /* start of physical ram 物理存储器开始地址*/
unsigned int phys_io; /* start of physical io 物理io空间开始地址*/
unsigned int io_pg_offst; /* byte offset for io io空间页表入口地址的偏移量
* page tabe entry */
const char *name; /* architecture name 架构名称数组地址*/
unsigned int param_offset; /* parameter page 参数页地址偏移量*/
unsigned int video_start; /* start of video RAM 视频缓冲区RAM的开始地址*/
unsigned int video_end; /* end of video RAM 视频缓冲区RAM的结束地址*/
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot 软件启动*/
void (*fixup)(struct machine_desc *,
struct param_struct *, char **,
struct meminfo *); /* fixup函数实现的地址*/
void (*map_io)(void);/* IO mapping function iomap函数,在mm中实现*/
void (*init_irq)(void); /* 初始化irq函数地址,在irq.c文件中实现*/
};
此结构体是通过MACHINE_START这一组宏来初始化的,一般是在\arch\arm\mach-fv13xx\arch.c文件中实现。
u32 tag; /* tag号*/
int (*parse)(const struct tag *); /* tag分析处理函数*/
};