Linux源码学习三、vmlinux.lds.S、MRC/MCR协处理器寄存器指令和head.S文件分析

微笑、不失礼 提交于 2020-01-24 02:59:01

①vmlinux.lds.S文件在目录arch/arm/kernel/vmlinux.lds.S下

分析VMLINUX_SYMBOL(__proc_info_begin) = .;  


vmlinux.lds.S文件的内容为:

#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/page.h>

分别表示include文件夹里的<>目录下的内容。

#define PROC_INFO                            \
VMLINUX_SYMBOL(__proc_info_begin) = .;                \
*(.proc.info.init)                        \
VMLINUX_SYMBOL(__proc_info_end) = .;  

\表示连接符,一个句子太长分开连接的意思,相当于:

相当于PROC_INFO代表后面一长串,包含后面的分号。

VMLINUX_SYMBOL(__proc_info_begin) = .;    

因为vmlinux.lds.S文件引入:#include <asm-generic/vmlinux.lds.h>,在目录include/asm-generic/vmlinux.lds.h头文件中有部分内容为:

#ifndef SYMBOL_PREFIX
#define VMLINUX_SYMBOL(sym) sym
#else
#define PASTE2(x,y) x##y
#define PASTE(x,y) PASTE2(x,y)
#define VMLINUX_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
#endif

表示:如果没有定义SYMBOL_PREFIX#define VMLINUX_SYMBOL(sym) sym

           如果定义了SYMBOL_PREFIX#define PASTE2(x,y) x##y   #define PASTE(x,y) PASTE2(x,y)

           即PASTE(x,y) PASTE2(x,y)都是等于x##yx##y表示xy

           所以如果定义了SYMBOL_PREFIXPASTE(SYMBOL_PREFIX, sym)就是 SYMBOL_PREFIXsym

 

VMLINUX_SYMBOL(__proc_info_begin)   要么是__proc_info_begin,要么是SYMBOL_PREFIX__proc_info_begin
"."特殊符号点,代表定位计数器,表示目前的位置的地址。

VMLINUX_SYMBOL(__proc_info_begin) = .;  的意思是:__proc_info_begin=.  或者 

SYMBOL_PREFIX__proc_info_begin=.也就是把程序信息开头的地址赋值给变量__proc_info_begin或者SYMBOL_PREFIX__proc_info_begin

②vmlinux.lds.S文件在目录arch/arm/kernel/vmlinux.lds.S下

分析*(.proc.info.init)                        \
VMLINUX_SYMBOL(__proc_info_end) = .;  

*(.proc.info.init)  里面的.proc.info.init是段,*(XXXX)=5;*(XXXX)表示5这个值,XXXX表示存5这个值的地址

所以*(.proc.info.init) =某个值,然后.proc.info.init这个表示一个存放*(.proc.info.init) =某个值地址。即.proc.info.init这个,存放的是一个地址的值。

VMLINUX_SYMBOL(__proc_info_end) = .;  

因为vmlinux.lds.S文件引入:#include <asm-generic/vmlinux.lds.h>,在目录include/asm-generic/vmlinux.lds.h头文件中有部分内容为:

#ifndef SYMBOL_PREFIX
#define VMLINUX_SYMBOL(sym) sym
#else
#define PASTE2(x,y) x##y
#define PASTE(x,y) PASTE2(x,y)
#define VMLINUX_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
#endif

表示:如果没有定义SYMBOL_PREFIX#define VMLINUX_SYMBOL(sym) sym

           如果定义了SYMBOL_PREFIX#define PASTE2(x,y) x##y   #define PASTE(x,y) PASTE2(x,y)

           即PASTE(x,y) PASTE2(x,y)都是等于x##yx##y表示xy

           所以如果定义了SYMBOL_PREFIXPASTE(SYMBOL_PREFIX, sym)就是 SYMBOL_PREFIXsym

 

VMLINUX_SYMBOL(__proc_info_end)   要么是__proc_info_end,要么是SYMBOL_PREFIX__proc_info_end
"."特殊符号点,代表定位计数器,表示目前的位置的地址。

VMLINUX_SYMBOL(__proc_info_end) = .;  的意思是:__proc_info_end=.  或者 

SYMBOL_PREFIX__proc_info_end=.也就是把程序信息结束(末尾)的地址赋值给变量__proc_info_end或者SYMBOL_PREFIX__proc_info_end

③vmlinux.lds.S文件在目录arch/arm/kernel/vmlinux.lds.S下,分析:

#define PROC_INFO                            \
#define PROC_INFO                            \
VMLINUX_SYMBOL(__proc_info_begin) = .;                \
*(.proc.info.init)                        \
VMLINUX_SYMBOL(__proc_info_end) = .;  

表示PROC_INF这个宏表示一长串:

VMLINUX_SYMBOL(__proc_info_begin) = .;      *(.proc.info.init)       VMLINUX_SYMBOL(__proc_info_end) = .;  

__proc_info_begin=目前的地址值。

*(.proc.info.init) 加上一段以段.proc.info.init地址的内容。

__proc_info_end=加上一段内容后的地址值。

④协处理器寄存器(Coprocessor Register)和ARM寄存器(ARM Register)相互操作的指令说明:MCR和MRC

MCR指令:ARM寄存器(ARM Register)到协处理器寄存器(Coprocessor Register)的数据传送(R放入C)

MCR,其中M表示:Mov移动,C表示:协处理器寄存器(Coprocessor Register),R表示:ARM寄存器(ARM Register)

R放入C

MCR{<cond>} <p>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}

MCR{<cond>} p15,0,<Rd>,<CRn>,<CRm>{,<opcode_2>}

 

MRC指令:协处理器寄存器(Coprocessor Register)到ARM寄存器(ARM Register)的数据传送(C放入R)

MRC,其中M表示:Mov移动,C表示:协处理器寄存器(Coprocessor Register),R表示:ARM寄存器(ARM Register)

C放入R

MRC{<cond>} <p>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}

MRC{<cond>} p15,0,<Rd>,<CRn>,<CRm>{,<opcode_2>}

 

{<cond>}为指令执行的条件码。当忽略时指令为无条件执行。

<p>为CPXX协处理器,此处举例CP15协处理器,所以为p15。

<opcode_1>为协处理器将执行的操作的操作码。对于CP15协处理器来说,< opcode_1>永远为0b000,当< opcode_1>不为0b000时,该指令操作结果不可预知。

<Rd>为源寄存器的ARM寄存器(ARM Register),其值将被传送到协处理器寄存器(Coprocessor Register)中。

<CRn>为目标寄存器的协处理器寄存器,其编号可能是C0,C1,…,C15。(或者小写c0、c1,...,c15)。

<CRm>{,<opcode_2>}为两者组合决定对协处理器寄存器进行所需要的操作,如果没有指定,则将为为C0,opcode_2为0,否则可能导致不可预知的结果。

mrc    p15, 0, r9, c0, c0        @ get processor id

将CPU15的c即协处理寄存器的值即c0(可以是1~15号协处理寄存器)给r即arm寄存器即r9里面存放

⑤vmlinux.lds.S文件在目录arch/arm/kernel/vmlinux.lds.S下,分析:


#ifdef CONFIG_HOTPLUG_CPU  (如果定义了宏CONFIG_HOTPLUG_CPU则执行#define ARM_CPU_DISCARD(x)和          #define ARM_CPU_DISCARD(x)     #define ARM_CPU_KEEP(x)        x)
#define ARM_CPU_KEEP(x)        x
#else                                                 
  (如果没有定义宏CONFIG_HOTPLUG_CPU则执行#define ARM_CPU_DISCARD(x)    x
#define ARM_CPU_DISCARD(x)    x   #define ARM_CPU_KEEP(x)

#define ARM_CPU_KEEP(x)
#endif

#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)(如果定义了宏CONFIG_SMP_ON_UP
#define ARM_EXIT_KEEP(x)    x          且没有定义宏CONFIG_DEBUG_SPINLOCK 则定义宏#define ARM_EXIT_KEEP(x)  
#else                                                             x 否则 定义宏#define ARM_EXIT_KEEP(x)                                                                         #define ARM_EXIT_KEEP(x)
#endif

⑥vmlinux.lds.S文件在目录arch/arm/kernel/vmlinux.lds.S下,分析:

OUTPUT_ARCH(arm)
ENTRY(stext)

ARM链接脚本,vmlinux.lds.S文件就是一个链接脚本文件。

什么是链接脚本文件?就是用于告诉链接器如何把输入文件内的各个段(section)放到输出文件中,并控制输出文件中的各个段在此程序运行时的地址空间布局。一个程序由多个段组成,那么这些段是如何在文件中存放的(这些段的存放内容和存放段的地址),以及是如何加载到内存的相应位置进行执行的呢,这个就是通过链接脚本进行控制的。

链接脚本格式:链接脚本由一系列命令组成,每一个命令由一个关键字和相应的参数,或者一些赋值语句等组成。命令由分号进行分割。用/* */进行注释。

OUT_ARCH(arch);设置输出文件的体系架构。

OUTPUT_ARCH(arm)输出文件的体系架构是arm体系架构。arm体系架构x86体系架构是相对而说的。

ENTRY(SYMBOL);将SYMBOL的值设置成入口地址。一般设置为_start。

ENTRY(stext)stext的值设为入口地址的值。存放段的入口地址。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!