嵌入式C语言–LD文件的概念

嵌入式C语言–LD文件的概念

嵌入式C语言--LD文件的概念

  • 嵌入式C语言--LD文件的概念
    • 一. 什么是LD文件
    • 二. LD文件的作用
    • 三. LD文件的工作步骤
      • 1)读取输入文件
      • 2)符号解析
      • 3)符号重定位
      • 4)生成输出文件
    • 四. ld文件的几部分
      • 1)指令(Directives)
      • 2)命令(Commands)
      • 4)段(Sections)
      • 5)符号(Symbols)
      • 6)段地址(Address)
      • 7)镜像(Image)
    • 六. LD文件举例
      • 1)第一个例子
      • 2)第二个例子
    • 七. 什么是MAP文件
    • 八.什么是目标文件
    • 九. 关于LD文件的总结

一. 什么是LD文件

LD组合了许多对象文件和归档文件,重新定位它们的数据并绑定符号引用。通常编译程序的最后一步是运行LD。
LD(Linker)文件是一个负责将目标文件和库文件链接成可执行文件或共享库的程序。

每个可加载或可分配的输出section都有两个地址。第一个是VMA,即虚拟内存地址。这是运行输出文件时该节所拥有的地址。第二个是LMA,即加载内存地址。
在大多数情况下,这两个地址将是相同的。当它们可能不同时的一个例子是当一个数据段加载到ROM,然后在程序启动时复制到 RAM (这种技术通常用于在基于ROM的系统中初始化全局变量)。在这种情况下,ROM 地址是LMA,RAM地址是VMA。

二. LD文件的作用

程序代码(.s 和 .c)源文件会经过预编译、编译、汇编、链接最后生成目标可执行文件,.ld文件是作用在链接过程。
分配堆空间大小、栈空间大小、然后根据应用的请求设置栈的位置,ROMRAM内存地址的分配方式,可以按LD文件中的规则分配程序或RAM占用的空间。
LD文件的主要作用是解决目标文件之间的符号引用关系,将所有目标文件中的符号引用和符号定义进行匹配,最终生成可执行文件。

三. LD文件的工作步骤

LD(链接器)把一个或多个输入文件合成一个输出文件。
输入文件: 目标文件或链接脚本文件。
输出文件: 共享库或可执行文件。

1)读取输入文件

LD文件首先会读取所有需要链接的目标文件和库文件,这些文件包括目标文件、静态库文件和动态库文件。

2)符号解析

LD文件会对每个目标文件中的符号进行解析,将符号引用和符号定义进行匹配。

3)符号重定位

LD将所有符号引用和符号定义进行匹配后,会对所有未解析的符号进行重定位,将其指向正确的地址。

4)生成输出文件

最后,LD将所有目标文件链接成一个可执行文件或共享库,并生成输出文件。

四. ld文件的几部分

LD文件的语法是基于脚本语言的,主要包括以下几个部分:

1)指令(Directives)

指令是LD文件的基本语法单元,用于控制链接器的行为。指令以“.”开头,例如“.text”、“.data”等。

2)命令(Commands)

命令是指令的具体实现,用于指示链接器如何处理目标文件和库文件。命令包括输入命令、输出命令、符号命令、重定位命令等。### 3)表达式(Expressions)
表达式用于计算地址和大小等数值,可以包括常量、符号、运算符等。

4)段(Sections)

段是目标文件中的一段内存区域,包括代码段、数据段、BSS段等。段可以包含多个节(Section),每个节包含一组相同类型的数据。

5)符号(Symbols)

符号是目标文件中的标识符,包括函数名、变量名、常量等。符号可以被定义和引用,链接器会根据符号的定义和引用关系进行符号解析和重定位。

6)段地址(Address)

段地址是指目标文件中的段在内存中的起始地址。

7)镜像(Image)

镜像是指可执行文件或共享库在内存中的映像,包括代码段、数据段等

六. LD文件举例

1)第一个例子

ENTRY(_start)

SECTIONS {
    .text  : { *(.text) }
    .data  : { *(.data) }
    .bss   : { *(.bss) }
}
INPUT(-lc -lm)
OUTPUT(main)

该ld文件包含了一个入口点(ENTRY)、三个节(SECTIONS)、一个输入命令(INPUT)和一个输出命令(OUTPUT)。在每个节中,使用通配符“*”匹配所有同名节中的内容。输入命令用于指定需要链接的库文件,输出命令用于指定生成的可执行文件名。

2)第二个例子

ENTRY(_start)

MEMORY {
    rom (rx)  : ORIGIN = 0x00000000, LENGTH = 0x100000
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x100000
}

SECTIONS {
    .text : {
        *(.text)
    } > rom

    .rodata : {
        *(.rodata)
    } > rom

    .data : {
        *(.data)
    } > ram AT > rom

    .bss : {
        *(.bss)
    } > ram

    .stack : {
        . = ALIGN(4);
        _estack = .;
        . = . + 0x1000;
        . = ALIGN(4);
    } > ram

    /DISCARD/ : {
        *(.note.*)
        *(.comment)
    }
}

该ld文件定义了两个内存区域:rom和ram。rom区域用于存放只读数据和代码,ram区域用于存放可读写数据。其中,rom区域的起始地址为0x00000000,长度为0x100000,ram区域的起始地址为0x20000000,长度为0x100000。
该ld文件将目标文件中的代码和只读数据放置在rom区域,可读写数据放置在ram区域。其中,代码段和只读数据段使用了“.text”和“.rodata”节,可读写数据段使用了“.data”节,BSS段使用了“.bss”节。在链接时,代码段和只读数据段被放置在rom区域,可读写数据段被放置在ram区域,BSS段被放置在ram区域。
该ld文件还定义了一个栈区(.stack),用于存放程序的运行时栈。栈区的起始地址为ram区域的末尾,大小为0x1000字节。
最后,该ld文件使用“/DISCARD/”命令将目标文件中的“.note.*”和“.comment”节丢弃,这些节通常包含调试信息,不需要放置在最终的可执行文件中。

七. 什么是MAP文件

map.txt主要是按LD文件链接完后的一个结果。程序或buf均可以在map.txt中找到(注意:定义为static的函数或变量不会显示在map文件中)
它里面表示着链接之后的最终结果,简单理解就是运行LD文件之后生成目标程序,同时生成的一个结果表示。

八.什么是目标文件

(包括可执行文件)具有固定的格式, 在UNIX或GNU/Linux平台下, 一般为ELF格式
目标文件的每个section至少包含两个信息: 名字和大小。 大部分section还包含与它相关联的一块数据, 称为section contents(section内容). 一个section可被标记为“loadable(可加载的)”或“allocatable(可分配的)”

九. 关于LD文件的总结

LD文件用于将多个目标文件和库文件链接成一个可执行文件。