美文网首页内核
ARM GCC中的Link File

ARM GCC中的Link File

作者: Love_Jane | 来源:发表于2019-06-14 06:53 被阅读0次

    所谓的Link File是指在GCC链接阶段用到的一个用于表示MCU内存分布的文件,这个文件是GCC连接器的一个输入文件,不同的链接文件会有不同的结果,比如我们常见的下载到RAM或者Flash中,这两种不同的地址就对应不同的连接文件。本篇文章我们就对链接文件做一个简单的描述。

    连接文件

    连接文件的基本概念

    在GCC中,连接文件扩展名一般是.ld, 是编译器链接阶段的输入文件,他主要用来表示我们编译的程序在目标系统里面的存储方式。在解释这个概念之前我们有必要在回顾一下程序编译的具体过程。

    很早之前我们就知道程序编译要经过编译和链接两个阶段,但是现在各种GUI工具的盛行,很多时候我们都是直接点一个按钮就搞定了,工具实际在后台做了什么操作我们并不是特别清楚。实际上编译器的编译主要经过的两个阶段主要做的事情如下:

    • 预处理阶段:这个阶段编译器会对我们的代码进行预处理,主要就是进行宏的替换和注释的删除,这样我们就会得到比较干脆的代码,很多编译器不在单独列出这个预处理阶段,而是直接和编译过程综合在一起。

    • 编译阶段:这个阶段主要将我们的C语言编译成机器语言,生成的目标文件是.o的object文件和.lst的连接文件,这个连接文件和我们今天要讲的连接文件有区别,他类似于机器语言,但是里面的地址信息都是符号和相对地址,而不是真正的地址。编译阶段是针对源代码中的C文件的,每个C文件都会单独编译,所以编译器也没法获得绝对地址。

    • 连接阶段:这个阶段生成最终的可执行程序,这个阶段的输入文件主要有我们今天要讲的ld链接文件和编译阶段生成的所有.o文件,连接过程因为得到了所有的程序信息,所以它会根据ld文件中的地址信息安排代码在处理器中的存放方式,比如代码放到什么位置,变量放到什么位置等等。

    连接文件中比较重要的几个部分

    连接文件中内存的分布是按照region来分布的:

    MEMORY
    {
      VECTORS (rwx)      : ORIGIN = 0x0,         LENGTH = 0x0410
      ITCM (rwx)         : ORIGIN = 0x00000410,  LENGTH = 128K- 0x410
      DTCM (rwx)         : ORIGIN = 0x20000000,  LENGTH = 128K
    }
    ENTRY(_reset_init)
    Heap_Size = 4K;
    Stack_Size =41K;
    
    SECTIONS
    {
        /* The startup code goes first into INTERNAL_FLASH */
        .isr_vector :
        {
            __vector_table = .;
            . = ALIGN(4);
            KEEP(*(.isr_vector))
            . = ALIGN(4);
        } > VECTORS
    
    
        .text :
        {
            *(.text)                 /* .text sections (code) */
            *(.text*)                /* .text* sections (code) */
            *(.rodata)               /* .rodata sections (constants, strings, etc.) */
            *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
            *(.srodata .srodata.*)
            *(.glue_7)               /* glue arm to thumb code */
            *(.glue_7t)              /* glue thumb to arm code */
            *(.eh_frame)
            *(.init)
            *(.fini)
        } > ITCM
    
    
        .data :
        {
            . = ALIGN(4);
            __DATA_RAM = .;
            __data_start__ = .;      /* create a global symbol at data start */
            __etext = .;
            *(.data)                 /* .data sections */
            *(.data*)                /* .data* sections */
            *(.sdata .sdata.*)
            *(.heapsram*)            /* This is only for the pulpino official test code. */
            __noncachedata_start__ = .;   /* create a global symbol at ncache data start */
            *(NonCacheable)
            __noncachedata_end__ = .;     /* define a global symbol at ncache data end */
            KEEP(*(.jcr*))
            . = ALIGN(4);
            __data_end__ = .;        /* define a global symbol at data end */
        } > DTCM
    
        .bss :
        {
            __bss_start__ = .;
            *(.bss*)
            *(COMMON)
            __bss_end__ = .;
        } > DTCM
    
        .heap :
        {
            __end__ = .;
            end = __end__;
            __heap_start = .;
            . = + Heap_Size;
            . = ALIGN(4);
            __heap_end = .;
        } > DTCM
    
        /* Set stack top to end of RAM */
        __StackTop = ORIGIN(DTCM) + LENGTH(DTCM) - 8;
        __StackLimit = __StackTop - Stack_Size;
        PROVIDE(__stack = __StackTop);
    
        /* Check if data + heap + stack exceeds RAM limit */
        ASSERT(__StackLimit >= __heap_end, "region RAM overflowed with stack")
    
    }
    

    上面是一个简单的RAM中分布的连接文件,可以看到我们主要将内存分成了VECTORS, ITCM, DTCM三个region,这三个部分中分别存放了不同的内容,比如*(.text*)就是代码段, *(.data*)就是内存中的变量,这些变量一般是需要初始化的全局变量,如果程序不是直接下载到RAM中而是Flash中,我们还需要通过AT关键字进行地址重定义。*(.bss*)是为初始化的全局变量,这些我们一般会在程序初始化的时候后将他们初始化为全零。

    堆和栈的定义是直接采用定义地址偏移和定义符号来实现的,我们直接在用到的DATA段和BSS段之后指定了Heap_Size大小的空间作为堆空间,这里可以通过ALIGN关键字进行地址对齐。栈则是直接将后面的剩余空间直接利用,最后会有一个判断,用来计算最终地址是否溢出。

    地址重定义

    连接文件中还有一个比较关键的AT关键字这里没有体现,这个关键字主要是实现一个地址映射的功能,我们知道变量我们一般是放到RAM中去的,对于一些有初始值的变量我们不能简单的放到RAM中,因为对于MCU而言,我们不可能每次都去下载程序之后在运行,当程序从flash直接启动的时候,RAM数据并不会自动初始化,常用的方法是将这些RAM变量的初始值放到flash中去,在程序启动的时候手动将这些值初始化到RAM中,AT关键字就是实现这个功能的,它的作用就是告诉连接器某个段连接的时候放到哪个地址,运行的时候在哪个地址运行。

    好了就酱吧,该去吃早饭了。

    相关文章

      网友评论

        本文标题:ARM GCC中的Link File

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