美文网首页
04.链接 & 重定位

04.链接 & 重定位

作者: 柏666 | 来源:发表于2019-06-06 09:30 被阅读0次

一、编译之后的操作是链接,编译的顺序依照 makefile 里的文件顺序。SOC中可以使用ld命令指定,一般使用链接脚本。(http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html

        1. 链接脚本是个规则文件,用来指挥链接器工作,扩展名位lds。主要用来描述如何把输入文件中的节(sections)映射到输出文件中,并控制输出文件的存储布局。链接器参考链接脚本中的规则,并将其链接成可执行的程序(UNIX或GNU/Linux下, 一般为ELF格式)。

其描述在汇编指令中有说明

        2. 链接先后顺序,默认以makefile里面文件的先后顺序做依据。否则先后顺序由链接脚本指定。

        3. Linux应用程序,运行时默认的链接地址为0x0。它运行在操作系统的一个进程中,此进程独享4G的内存栈空间。Linux中每个进程都是从0地址开始,所以应用程序可以链接到0地址。

        4. 裸机中程序链接地址为内存集合中的地址,一般不为0。程序运行地址由下载时指定(由CPU设计候决定)。编译链接时应该指定地址。如果使用位置无关码,链接地址可以是0。

        5. 加载器会把可执行程序加载到内存的运行地址运行。裸板的加载器是JTAG调试工具,但JTAG等调试器一般只支持一体式链接脚本。Linux中应用程序加载器也是应用程序。

        6. 操作流程:①设置入口函数 ==> ②定义一个变量并赋值 ==> ③描述输入输出文件的链接规则。

                ①. 对于arm-gcc-ld脚本,设置入口函数和定义变量可以在SECTIONS命令大括号里,也可以在外面。下列入口定义方式优先级递减:1和2显示的指明入口(推荐)。4和5,有.text段的话就从它开始执行,连.text都没有的就从0地址开始执行。

                            1️⃣. 在连接的时候使用-e参数。

                            2️⃣. 在脚本里使用ENTRY(begin)。begin指定程序的入口点为begin标记。

                            3️⃣. (汇编文件里)定义过的start入口。

                            4️⃣. SECTION中.text的第一个入口函数。

                            5️⃣. 地址为0的指令。

                ②. 提供变量并使用伪汇编指令赋值。其值为汇编代码的启动地址。例如" .= 0x30000000; "。必须注意,链接脚本中对地址的赋值语句末尾需要添加" ; "分号。

                ③. 描述输入输出文件的链接规则:" SECTIONS "和 " MEMORY "。" SECTIONS "描述输出文件的布局,不可缺省。" MEMORY "补充SECTIONS。如果缺省,LD会认为" SECTIONS "描述的相邻内存块之间有足够的可用空间。SECTIONS中分布的段,不会考虑寻址范围里的ROM、RAM、FLASH是否连续。如果不连续,MEMORY命令就设置各个区的起始位置、大小、属性。一个脚本中只能有一个属性。

SECTIONS 格式 MEMORY 格式

        7. 变量有2种赋值方式:直接赋值(_start、_end等)。取址赋值(用链接脚本手册里的函数获取地址。例如LOADADDR等)。其用于之后的代码重定位。使用C语言取得变量的地址时


二、两种链接脚本:

        1. 分体链接脚本适合单片机。单片机自带flash,不需要再将代码复制到内存占用空间。嵌入式系统内存非常大,没必要节省这点空间。并且有些嵌入式系统没有可以直接运行代码的Flash(Nor Flash等),需要从Nand Flash或者SD卡复制整个代码到内存。

        2. JTAG等调试器一般只支持一体式链接脚本。

两种链接脚本

三、重定位

        1.大部分程序是从存储介质拷贝到内存中执行 - 重定位。链接脚本指定和获取程序各段地址,供程序拷贝数据段,和清除bss段。重定位完毕后,需要用 ldr 跳转到 sdram 中执行代码。

        2. 重定位分位静态重定位和动态重定位。

        静态:在程序执行前重定位。根据装配模块将要装入的内存起始位置,直接修改装配模块的有关使用地址的指令。由代码段实现。

        动态:在程序执行时重定位。访问内存单元前才变换地址。装配模块不加任何修改的装入内存,但需要定位寄存器的指出。

        3. uboot启动分为2部分,分别依次加载到内存运行。第一部分是拷贝uboot前面一段到SRAM中运行,第二部分初始化DDR并将uboot搬到DDR中执行。程序的链接地址和运行地址会发生改变,但代码中又存在位置有关码。需要进行代码重定位。(例如裸机中,DRAM还未进行初始化,但代码又必须在DRAM上运行)。

        4. 汇编代码分为位置无关码和位置有关码。

        位置无关码:运行时与代码在内存中的地址无关。代码使用相对地址而非绝对地址。(使用相对跳转指令B、BL、MOV等)

        位置有关码:链接地址和运行地址必须一致。(ldr r1, = xxx等指令)。

        运行地址:代码执行时的地址(指定方式:实际运行时被加载到内存的地址)。

        链接地址:链接时指定的地址(指定方式:makefile中用T-text,或链接脚本)。

        5. 重定位copy完代码后,某些代码会存在2份。重定位后如果想在SDRAM上运行代码(runtime address),必须用ldr指定绝对地址(ldr pc = xxx)。相对跳转则只会跳转到pc + offset的地址(仍然运行在SRAM或者nor flash上)。重定位前的代码必须使用相对地址跳转指令,不能使用绝对地址。

        6. 全局变量、静态变量、有初始值的数组,其读取时的跳转指令在反汇编中显示为ldr而不是b或者bl,属于绝对地址。必须在重定位之后访问。

        7. 必须注意,重定位之前一定要初始化完毕 sdram,否则呵呵。。。


四、如何重定位

        1、Nand Flash 启动步骤: 

        ①、硬件复制 Nand Flash 前面一段内容到片内 SRAM。 

        ②、从片内 RAM 运行,其基地址为0。

        ③、此状态下 Nor Flash 不可访问。

        ④、程序如果大于 SRAM,则前面一段拷贝到SRAM中的代码需要把整个程序读出来放到SDRAM(即代码重定位)。

        重定位方法:重定位数据段和代码段。通过链接脚本等,让文件链接到SDRAM起始位置,全局变量紧随其后。烧写到flash的0地址处。上电后程序会把代码段数据段(整个程序)从0地址复制到SDRAM的起始地址。

        2. Nor Flash 启动步骤:

        ①、Nor Flash 基地址为0。

        ②、CPU从 Nor Flash 上读出指令执行。

        ③、内存(4K RAM)基地址为 0x40000000(2440为例)。

        ④、把全局变量和静态变量重定位到 SDRAM 里。

        ⑤、初始化bss段。全部清零。

        重定位方法一:和nand flash相同。因为SDRAM较大,所以常用此方法。

        重定位方法二:仅重定位数据段。通过链接脚本等,让数据段链接到代码段之后。烧写运行时会把数据段复制到SDRAM的起始地址。

                Ⅰ、链接脚本指定链接地址:设定程序运行的起始地址、各段的起始和链接地址、供后续程序使用的地址变量。

                Ⅱ、代码的重定位拷贝:判断运行地址和链接地址,手动编写代码拷贝程序(复制代码到指定的链接地址处)。

                Ⅲ、初始化变量:从链接脚本中,读取bss段运行时的起始和结束地址,手动清零。

                Ⅳ、使用长转移指令跳转到SDRAM上运行。(ldr pc, = main)

运行时区域图

        3. 以方法一为例,实现copy和clean:

拷贝代码 清除bss段

       4. 注意,用C语言从链接脚本中获取地址时,为了规范必须类型转换,且要加上取址符号" & "。C语言使用"extern"声明外部变量时,会在编译该文件生成的符号表"symtab"中生成对应的存储。类似键值对(name:xxx -- addr:xxx)。从链接脚本中获取到的变量是一个值(不是地址),没有在内存中对应的值,所以需要手动添加取址符号来取出其值。

相关文章

  • 静态链接(四)

    重定位 重定位表 链接器为了知道有哪些指令需要被重定位,所以需要这样的一个表 一个重定位表往往就是ELF文件中的一...

  • 深入理解计算机系统第七章

    为了构 造可执 行文件 ,链接 器必须完成两个主要任务 符合解析 重定位 目标文件的三种形式 1.可重定位目标文件...

  • 静态链接

    静态链接 静态链接涉及的内容包含如下 空间地址的分配 符号解析和重定位 静态库链接 本文的测试代码以及其他文件存在...

  • 04.超链接标签a

    一、超链接标签 在 HTML 标签中, 标签用于定义超链接,作用是从一个页面链接到另一个页面。 单词 ancho...

  • 动态链接的步骤和实现

    动态链接的步骤基本上分为3步: 启动动态链接器本身 装载所有需要的共享对象 重定位和初始化 动态链接器自举 动态链...

  • 《程序员的自我修养》读书笔记——动态链接

    之前介绍过静态链接,动态链接相对于静态链接稍微要麻烦一些。总体来说,两者的过程都复杂,步骤太多,涉及到重定位,符号...

  • 【19.02.25复盘day72/365】

    【今日回顾】 01.听猫叔定位模块分享 02.上午完成定位模块的打卡 03.给家人做了顿饭(今日休息) 04.下午...

  • C链接2 -目标文件

    链接器的任务 在上一篇文章中,我们提到链接是将多个可重定位目标文件链接成一个可执行目标文件。必须要完成2件事 符号...

  • Checksec

    1.Relro:Full Relro(重定位表只读)Relocation Read Only, 重定位表只读。重定...

  • 汇编知识汇总

    ELF文件 重定位表 查看方法 表结构 偏移量可重定位文件:该重定位入口要修正的位置的第一个字节 重定位入口类型R...

网友评论

      本文标题:04.链接 & 重定位

      本文链接:https://www.haomeiwen.com/subject/engfxctx.html