热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

linux内核如何创建链接,Linux内核链接文件分析(zz)

首先看一下顶层Makefile生成的vmlinux以及archarmbootcompressedmakefile生成的vmlinux的起始地址。1.1archarmkernelvm

首先看一下顶层Makefile生成的vmlinux以及arch/arm/boot/compressed/makefile生成的vmlinux的起始地址。

1.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 &#61; $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $&#64; $<

%.lds: %.lds.S FORCE

$(call if_changed_dep,cpp_lds_S)

1.2顶层vmlinux的起始地址

在arch/arm/kernel/vmlinux.lds.S的开始处有

#ifdef CONFIG_XIP_KERNEL

. &#61; XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);

#else

. &#61; PAGE_OFFSET &#43; TEXT_OFFSET; (即0xc0008000)

#endif

我们这里的起始地址就是PAGE_OFFSET &#43; 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是一个符号&#xff0c;链接到asm-arm上的

在arch/arm/Makefile第140行&#xff0c;有

TEXT_OFFSET :&#61; $(textofs-y)

第90行有

textofs-y :&#61; 0x00008000

所以TEXT_OFFSET :&#61; 0x00008000

在153行有export TEXT_OFFSET将此变量输出。这样arch/arm/kernel/vmlinux.lds.S也就获得了PAGE_OFFSET &#43; TEXT_OFFSET的值。

1.3SEP4020的虚实地址;

(1)在arch/arm/mach-sep4020/Makefile.boot文件定义了一个压缩内核镜像zImage的起始地址

zreladdr-$(CONFIG_ARCH_4020)   :&#61; 0x30008000

这个地址在制作boot目录下面的zImage&#xff0c;uImage时候会用到的&#xff0c;这可以在arch/arm/boot/Makefile中的21行有定义

ZRELADDR    :&#61; $(zreladdr-y)

PARAMS_PHYS :&#61; $(params_phys-y)

INITRD_PHYS :&#61; $(initrd_phys-y)

(2)在/include/asm-arm/arch-sep4020/memory.h中定义了一个物理的页偏移地址&#xff0c;即sdram的地址

/*

* Page offset: 3GB

*/

#define PHYS_OFFSET        UL(0x30000000)

这个地址在启动代码arch/arm/kernel/head.s中会用到的&#xff1a;

#define KERNEL_RAM_ADDR (PAGE_OFFSET &#43; TEXT_OFFSET)  &#xff20;其中TEXT_OFFSET &#xff1d; 0x8000

//swapper_pg_dir是放启动时的临时页表的页表基址(虚地址)

.globl swapper_pg_dir

.equ swapper_pg_dir, KERNEL_RAM_ADDR - 0x4000

在这部分要建立页表的时候会用到这个地址的。

1.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生成&#xff0c;在这个文件的开始处有

. &#61; TEXT_START;

现在看arch/arm/boot/compressed/Makefile&#xff0c;在110行有

$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config

&#64;sed "$(SEDFLAGS)" <$ $&#64;

这就是由vmlinux.lds.in生成vmlinux.lds的规则&#xff0c;在它的命令中有个变量SEDFLAGS&#xff0c;在74行定义

SEDFLAGS    &#61; s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/

这里就把TEXT_START换成了ZTEXTADDR。再往上看从arch/arm/boot/compressed/makeflie的66行起

ifeq ($(CONFIG_ZBOOT_ROM),y)

ZTEXTADDR :&#61; $(CONFIG_ZBOOT_ROM_TEXT)

ZBSSADDR    :&#61; $(CONFIG_ZBOOT_ROM_BSS)

else

ZTEXTADDR :&#61; 0

ZBSSADDR    :&#61; ALIGN(4)

endif

如果zImage是从ram中启动ZTEXTADDR      :&#61; 0&#xff0c;否则从rom或flash启动时ZTEXTADDR :&#61; $(CONFIG_ZBOOT_ROM_TEXT)&#xff0c;这里要在配置时设定CONFIG_ZBOOT_ROM_TEXT的值。

1.5 /arch/arm/kernel/vmlinux.lds.s链接文件的分析

下面先看下这个文件&#xff1a;

#include

#include

#include

#include

OUTPUT_ARCH(arm)                /*指定目标板体系结构*/

ENTRY(stext)                             /*代码段入口*/

jiffies &#61; jiffies_64;                       /*在/kernel/Timer.c中定义的*/

SECTIONS                                /*代码段各部分*/

{

. &#61; PAGE_OFFSET &#43; TEXT_OFFSET;    /*代码段起始地址&#xff0c;SEP4020 Linux内核是0xC0008000&#xff0c;‘.’表示连接地址*/

.init : {                  /*内核初始化的代码和数据*/

_stext &#61; .;     /*标号_stext表示的就是起始地址0xc0008000*/

_sinittext &#61; .;

*(.init.text)

_einittext &#61; .;

__proc_info_begin &#61; .;

*(.proc.info.init)

__proc_info_end &#61; .;

__arch_info_begin &#61; .;

*(.arch.info.init)

__arch_info_end &#61; .;

__tagtable_begin &#61; .;

*(.taglist.init)

__tagtable_end &#61; .;

. &#61; ALIGN(16);

__setup_start &#61; .;

*(.init.setup)

__setup_end &#61; .;

__early_begin &#61; .;

*(.early_param.init)

__early_end &#61; .;

__initcall_start &#61; .;

*(.initcall1.init)

*(.initcall2.init)

*(.initcall3.init)

*(.initcall4.init)

*(.initcall5.init)

*(.initcall6.init)

*(.initcall7.init)

__initcall_end &#61; .;

__con_initcall_start &#61; .;

*(.con_initcall.init)

__con_initcall_end &#61; .;

__security_initcall_start &#61; .;

*(.security_initcall.init)

__security_initcall_end &#61; .;

. &#61; ALIGN(32);

__initramfs_start &#61; .;

usr/built-in.o(.init.ramfs)

__initramfs_end &#61; .;

. &#61; ALIGN(64);

__per_cpu_start &#61; .;

*(.data.percpu)

__per_cpu_end &#61; .;

}

/DISCARD/ : {                     /*内核退出的代码和数据*/

*(.exit.text)

*(.exit.data)

*(.exitcall.exit)

}

.text : {                 /*真正的代码段部分*/

_text &#61; .;        /*代码和只读数据*/

*(.text)

SCHED_TEXT

LOCK_TEXT

*(.fixup)

*(.gnu.warning)

*(.rodata)

*(.rodata.*)

*(.glue_7)

*(.glue_7t)

*(.got)                  /* Global offset table             */

}

RODATA

_etext &#61; .;                     /*代码段和只读数据结束*/

. &#61; ALIGN(THREAD_SIZE);

__data_loc &#61; .;

.data : AT(__data_loc) { /*数据段起始*/

__data_start &#61; .;    /*内存中的地址*/

/*

* first, the init task union, aligned

* to an 8192 byte boundary.

*/

*(.init.task)

. &#61; ALIGN(4096);

__nosave_begin &#61; .;

*(.data.nosave)

. &#61; ALIGN(4096);

__nosave_end &#61; .;

/*

* then the cacheline aligned data

*/

. &#61; ALIGN(32);

*(.data.cacheline_aligned)

/*

/*例外修正表(可能需要在运行时修正)*/

*/

. &#61; ALIGN(32);

__start___ex_table &#61; .;

*(__ex_table)

__stop___ex_table &#61; .;

/*

/*普通的数据段*/

*/

*(.data)

CONSTRUCTORS

_edata &#61; .;

}

.bss : {                                /*未初始化的全局变量*/

__bss_start &#61; .;      /* BSS                         */

*(.bss)

*(COMMON)

_end &#61; .;

}

/*调试信息和数据段.*/

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



推荐阅读
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • APKAnalyzer(1):命令行操作体验与功能解析
    在对apkChecker进行深入研究后,自然而然地关注到了Android Studio中的APK分析功能。将APK文件导入IDE中,系统会自动解析并展示其中各类文件的详细信息。官方文档提供了详细的命令行工具使用指南,帮助开发者快速上手。本文以一个RecyclerView的Adapter代理开源库为例,探讨了如何利用这些工具进行高效的APK分析。 ... [详细]
  • 掌握DSP必备的56个核心问题,我已经将其收藏以备不时之需! ... [详细]
  • 对于以压缩包形式发布的软件,其目录中通常包含一个配置脚本 `configure`。该脚本的主要功能是确定编译所需的各项参数,如头文件的位置和链接库的路径,并生成相应的 `Makefile` 以供编译使用。通过运行此脚本,开发者可以确保软件在不同环境下的正确编译与安装。此外,该脚本还能够检测系统依赖项,进一步提高编译过程的可靠性和兼容性。 ... [详细]
  • 求助高手:下载的压缩包中包含CMake文件,如何在Windows环境下使用已安装的CMake GUI进行运行?
    从GitHub仓库 `https://github.com/vonmax007/RobotSimulation` 下载的代码包含多种算法,其中算法1的文件目录中包含了CMake文件。为了在Windows环境下使用已安装的CMake GUI运行这些文件,需要先确保CMake已正确安装,并按照以下步骤操作:打开CMake GUI,设置源代码路径和构建路径,点击“Configure”配置项目,然后点击“Generate”生成构建文件。最后,在生成的构建目录中使用命令行或IDE进行编译和运行。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • 深入解析Gradle中的Project核心组件
    在Gradle构建系统中,`Project` 是一个核心组件,扮演着至关重要的角色。通过使用 `./gradlew projects` 命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project` 对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。 ... [详细]
  • Go语言实现Redis客户端与服务器的交互机制深入解析
    在前文对Godis v1.0版本的基础功能进行了详细介绍后,本文将重点探讨如何实现客户端与服务器之间的交互机制。通过具体代码实现,使客户端与服务器能够顺利通信,赋予项目实际运行的能力。本文将详细解析Go语言在实现这一过程中的关键技术和实现细节,帮助读者深入了解Redis客户端与服务器的交互原理。 ... [详细]
  • 本文探讨了将PEBuilder转换为DIBooter.sh的方法,重点介绍了如何将DI工具集成到启动层,实现离线镜像引导安装。通过使用DD命令替代传统的grub-install工具,实现了GRUB的离线安装。此外,还详细解析了bootice工具的工作原理及其在该过程中的应用,确保系统在无网络环境下也能顺利引导和安装。 ... [详细]
  • PJSIP 编译与开发指南:深入解析 PJSIP 库的应用与优化
    PJSIP 编译与开发指南:深入解析 PJSIP 库的应用与优化 ... [详细]
  • Android开发常见问题汇总(含Gradle解决方案)第二篇
    本文继续深入探讨Android开发中常见的问题及其解决方案,特别聚焦于Gradle相关的挑战。通过详细分析和实例演示,帮助开发者高效解决构建过程中的各种难题,提升开发效率和项目稳定性。 ... [详细]
  • 在上篇文章的基础上,本文将继续探讨 Linux 设备驱动中的设备模型与 `devicedriverbus` 机制。在将设备注册到总线之前,需要先创建 `device` 对象。可以通过静态定义 `device` 结构体变量,并调用 `device_register` 函数来完成这一过程。此外,文章还将详细解析设备模型的内部工作机制,以及 `devicedriverbus` 机制如何实现设备与驱动的自动匹配和管理。 ... [详细]
  • 本文详细解析了 `ulimit` 命令的使用方法及其在实际场景中的应用。`ulimit` 是一个 Shell 内置命令,用于控制 Shell 启动的进程所能使用的系统资源。文章介绍了 `ulimit` 的基本语法格式,包括 `-a`、`-c`、`-d`、`-f`、`-H`、`-l`、`-m`、`-n`、`-p`、`-s`、`-S`、`-t`、`-v` 和 `-w` 等参数的含义和用法。通过具体示例,读者可以更好地理解和应用这些参数,以优化系统性能和资源管理。 ... [详细]
  • 进程(Process)是指计算机中程序对特定数据集的一次运行活动,是系统资源分配与调度的核心单元,构成了操作系统架构的基础。在早期以进程为中心的计算机体系结构中,进程被视为程序的执行实例,其状态和控制信息通过任务描述符(task_struct)进行管理和维护。本文将深入探讨进程的概念及其关键数据结构task_struct,解析其在操作系统中的作用和实现机制。 ... [详细]
  • IIS 7及7.5版本中应用程序池的最佳配置策略与实践
    在IIS 7及7.5版本中,优化应用程序池的配置是提升Web站点性能的关键步骤。具体操作包括:首先定位到目标Web站点的应用程序池,然后通过“应用程序池”菜单找到对应的池,右键选择“高级设置”。在一般优化方案中,建议调整以下几个关键参数:1. **基本设置**: - **队列长度**:默认值为1000,可根据实际需求调整队列长度,以提高处理请求的能力。此外,还可以进一步优化其他参数,如处理器使用限制、回收策略等,以确保应用程序池的高效运行。这些优化措施有助于提升系统的稳定性和响应速度。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有