ld文件

深入剖析 GD32 LD文件 LD 文件作为链接器脚本文件,在整个嵌入式开发流程中占据着举足轻重的地位。当编译器将我们编写的源代码转化为目标文件后,这些目标文件就如同零散的零件,而链接器的使命就是将这些零件以及所需的库文件巧妙地组合成一个完整且可执行的文件。在这个过程中,LD 文件就为链接器提供了详尽的操作指南。它会明确告知链接器如何对这些文件进行整合,怎样合理地分配内存空间,以及程序启动的入口点应设置在何处等核心信息。 阅读详情

OUTPUT_FORMAT("elf32-tradlittlemips")
OUTPUT_ARCH(mips)
ENTRY(_start)
SECTIONS
{
  . = 0x80100000;
  .text:
  {
      _ftext = . ;
      *(.text)
      *(.rodata)
      *(.rodata1)
      *(.reginfo)
      *(.init)
      *(.stub)   
      *(.gnu.warning)
  }=0
  _etext = .;
  PROVIDE (etext = .);
  .fini: { *(.fini) } =0
  .data:
  {
      _fdata = . ;
      *(.data)
      CONSTRUCTORS
  }
  .data1 : { *(.data1) }
  .ctors :
  {
      __CTOR_LIST__ = .;
      LONG((__CTOR_END__ -__CTOR_LIST__) / 4 - 2)
      *(.ctors)
      LONG(0)
      __CTOR_END__ = .;
  }
  .dtors :
  {
      __DTOR_LIST__ = .;
      LONG((__DTOR_END__ -__DTOR_LIST__) / 4 - 2)
      *(.dtors)
      LONG(0)
      __DTOR_END__ = .;
  }
  _gp = ALIGN(16) + 0x7ff0;
  .got           :
  {
      *(.got.plt) *(.got)
  }
 
  .sdata     : { *(.sdata) }
  .lit8 : { *(.lit8) }
  .lit4 : { *(.lit4) }
  _edata  =  .;
  PROVIDE (edata = .);
  __bss_start = .;
  _fbss = .;
  .sbss      : { *(.sbss) *(.scommon) }
  .bss       :
  {
      *(.dynbss)
      *(.bss)
      *(COMMON)
  }
  . = ALIGN(16);
  __bss_end = .;
  _end = .;__end = .; end = .;
  PROVIDE (end = .);
 
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
 
  .debug          0 : { *(.debug) }
  .debug_srcinfo   0 : {*(.debug_srcinfo) }
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : {*(.debug_pubnames) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  .line            0 : { *(.line) }
 
  .gptab.sdata : {*(.gptab.data) *(.gptab.sdata) }
  .gptab.sbss : { *(.gptab.bss)*(.gptab.sbss) }
}
 
下面逐句解释。
 
OUTPUT_FORMAT("elf32-tradlittlemips")
OUTPUT_ARCH(mips)
 
OUTPUT_FORMAT 和 OUTPUT_ARCH 都是 ld 脚本的保留字命令。
OUTPUT_FORMAT 说明输出二进制文件的格式。
OUTPUT_ARCH 说明输出文件在平台。
 
 
ENTRY(_start)
ENTRY 命令的作用是,将后面括号中的符号值设置成入口地址。入口地址(entry point)的定义是这样的──进程执行的第一条用户空间的指令在进程地址空间中的地址。
 
ld 有多种方法设置进程入口地址,通常它按以下顺序:(编号越前, 优先级越高)
1.        ld命令行的-e选项
2.        连接脚本的 ENTRY(SYMBOL) 命令
3.        如果定义了 start 符号, 使用 start 符号值
4.        如果存在 .text section, 使用 .text section 的第一字节的位置值
5.        使用值 0
 
 
SECTIONS{
然后,接下来是一大段的SECTIONS,对应的右大括号直到脚本的末尾。
SECTIONS 命令告诉 ld 如何把输入文件的sections 映射到输出文件的各个section:即是如何将输入section 合为输出 section;如何把输出 section 放入程序地址空间 (VMA) 和进程地址空间 (LMA) 。该命令格式如下:
SECTIONS
{
….
}
 
  . = 0x80100000;
 
 
这句把定位器符号置为0x80100000 (若不指定,则该符号的初始值为 0)。
.是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置(或某section内的偏移,如果它在SECTIONS命令内的某section描述内),该符号只能在SECTIONS命令内使用。
 
.text      :
  {
    _ftext = . ;
    *(.text)
    *(.rodata)
    *(.rodata1)
    *(.reginfo)
    *(.init)
    *(.stub)
    *(.gnu.warning)
  } =0
 
 
.text : 表示text段开始。
_ftext
*(.text) 将所有(*符号代表任意输入文件)输入文件的.text section合并成一个.text section, 该section的地址由定位器符号的值指定, 即0x80100000.
*(.rodata)
*(.rodata1)
*(.reginfo)
*(.init)
*(.stub)
*(.gnu.warning)
} =0 表示合并时留下的空隙用 0 填充;
 
 
_etext = .;
    PROVIDE (etext = .);
    _etext = .; 我们看到,很多变量都定义成等于这个 . 符,实际上这个符号所代表的值是在变化的,随着越往后走,值越增加,根据前面填充的多少自动往后加。
    PROVIDE关键字用于定义这类符号:在目标文件内被引用,但没有在任何目标文件内被定义的符号。
    这里就定义了一个etext 符号,当目标文件内引用了etext符号,却没有定义它时,etext符号对应的地址被定义为.text section 之后的第一个字节的地址。
 
 
.fini      : { *(.fini)    } =0
意思与前面一样,但 fini 这名字是哪个段,我还搞不太清楚(???)。
 
 
.data    :
  {
    _fdata = . ;
    *(.data)
    CONSTRUCTORS
  }
  .data1   : { *(.data1) }
数据段终于来到了,意思很容易理解的了。
CONSTRUCTORS 是一个保留字命令。与 c++ 内的(全局对象的)构造函数和(全局对像的)析构函数相关。
 
.ctors         :
  {
                __CTOR_LIST__= .;
               LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
               *(.ctors)
                LONG(0)
                __CTOR_END__ =.;
  }
  .dtors         :
  {
                __DTOR_LIST__= .;
               LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
               *(.dtors)
                LONG(0)
                __DTOR_END__ =.;
  }
 
 
对于支持任意section名的目标文件格式,比如COFF、ELF格式,GNU C++将全局构造和全局析构信息分别放入 .ctors section 和 .dtors section 内
当 连接器生成的目标文件格式不支持任意section名字时,比如说ECOFF、XCOFF格式,连接器将通过名字来识别全局构造和全局析构,对于这些文件 格式,连接器把与全局构造和全局析构的相关信息放入出现CONSTRUCTORS 关键字的输出section内。
 
符号__CTORS_LIST__表示全局构造信息的的开始处,__CTORS_END__表示全局构造信息的结束处。
符号__DTORS_LIST__表示全局构造信息的的开始处,__DTORS_END__表示全局构造信息的结束处。
这两块信息的开始处是一字长的信息,表示该块信息有多少项数据,然后以值为零的一字长数据结束。
一般来说,GNU C++在函数__main内安排全局构造代码的运行,而__main函数被初始化代码(在main函数调用之前执行)调用。
 
 
_gp = ALIGN(16) + 0x7ff0;
_gp是一个重要的全局变量,好像是用作全局引用的一个指针。
 
 
.got           :
  {
    *(.got.plt) *(.got)
   }
 
  .sdata     : { *(.sdata) }
  .lit8 : { *(.lit8) }
  .lit4 : { *(.lit4) }
意义类似。


_edata  =  .;
  PROVIDE (edata = .);
  
意义与前面的 etext 类似。edata 符号也较为重要。
 
__bss_start = .;
  _fbss = .;
  .sbss      : { *(.sbss) *(.scommon) }
  .bss       :
  {
   *(.dynbss)
   *(.bss)
   *(COMMON)
  }
  . = ALIGN(16);
  __bss_end = .;
  _end = .;__end = .; end = .;
  PROVIDE (end = .);
BSS段开始了。
COMMON 这个保留字的意义:
通用符号(common symbol)的输入section:
在许多目标文件格式中,通用符号并没有占用一个section。连接器认为:输入文件的所有通用符号在名为COMMON的section内。
上例中将所有输入文件的所有通用符号放入输出.bss section内。
 
这里,定义了几个重要的符号
__bss_start = .;
__bss_end = .;
_end = .;
__end = .;
end = .;
在代码中可能会用到的。
 
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
 
  .debug          0 : { *(.debug) }
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : {*(.debug_pubnames) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  .line           0 : { *(.line) }
 
  .gptab.sdata : {*(.gptab.data) *(.gptab.sdata) }
  .gptab.sbss : {*(.gptab.bss) *(.gptab.sbss) }
}
 
 
余下的这几个意义也类似,看英文注释应该能明白。
 
对初步编译出来的一个二进制文件进行 nm 解析,得到如下内容
 
80100200 D __CTOR_END__
801001f8 D __CTOR_LIST__
80100208 D __DTOR_END__
80100200 D __DTOR_LIST__
80100220 A __bss_end
80100208 A __bss_start
80100220 A __end
80100208 A _edata
80100220 A _end
801001f8 A _etext
80100208 A _fbss
80100200 A _fdata
80100000 T _ftext
80108200 A _gp
80100000 T _start
80100038 t cleanpipe
80100220 A end
80100210 b flag_initialized.1263
80100158 T inbFrCom
801000b4 T initBss
80100060 T initConstructor
80100100 T initMips
801001a4 T outbToCom
80100140 T readComReg
801000f8 T showVersion
800fc000 T stack
80100000 T start
80100120 T writeComReg
 
可以看到,所有的地址全是从 0x80100000 开始的。
 
三个起始符号(T表示在text段中)
80100000 T _start
80100000 T start
80100000 T _ftext
 
几个函数都在代码段内
80100038 t cleanpipe
80100060 T initConstructor
801000b4 T initBss
801000f8 T showVersion
80100100 T initMips
80100120 T writeComReg
80100140 T readComReg
80100158 T inbFrCom
801001a4 T outbToCom
 
栈底地址果然是在 start 下方 0x4000 处
800fc000 T stack
 
(A 表示绝对不变)
801001f8 A _etext
80100200 A _fdata
80100208 A _edata
80100208 A _fbss
80100208 A __bss_start
80100220 A __bss_end
80100220 A __end
80100220 A _end
80100220 A end
 
全局构造和析构变量段(D表示在已初始化过的数据段中)
801001f8 D __CTOR_LIST__
80100200 D __CTOR_END__
80100200 D __DTOR_LIST__
80100208 D __DTOR_END__
 
还有一个是用 B 标记的,表示在未初始化的数据段中
80100210 b flag_initialized.1263
对应的代码是
static int flag_initialized = 0;
可以看出,这是个局部静态变量。
 
令其按地址排序
 
nm -n bamboo
 
800fc000 T stack
80100000 T _ftext
80100000 T _start
80100000 T start
80100038 t cleanpipe
80100060 T initConstructor
801000b4 T initBss
801000f8 T showVersion
80100100 T initMips
80100120 T writeComReg
80100140 T readComReg
80100158 T inbFrCom
801001a4 T outbToCom
801001f8 D __CTOR_LIST__
801001f8 A _etext
80100200 D __CTOR_END__
80100200 D __DTOR_LIST__
80100200 A _fdata
80100208 D __DTOR_END__
80100208 A __bss_start
80100208 A _edata
80100208 A _fbss
80100210 b flag_initialized.1263
80100220 A __bss_end
80100220 A __end
80100220 A _end
80100220 A end
80108200 A _gp
 
结合这些数据,去理解前面的 ld.script 的讲解,会有一个清晰的印象

ARM LD链接文件说明 对于ARM LD链接文件,有很详细的解释。 立即下载

相关推荐

mips-sde-elf-i686-pc-linux-gnu.tar.bz2

mips-sde-elf-i686-pc-linux-gnu.tar.bz2 下载这里来编译mips

MIPS ld脚本的见解

   Mips的ld脚本会随着Ecos的编译进行。OUTPUT_FORMAT("elf32-bigmips", "elf32-tradbigmips",    "elf32-tradlittlemips")OUTPUT_ARCH(mips:isa32)STARTUP(vectors.o)ENTRY(reset_vector) 启动到reset_vector段执行    

sxx1728的专栏 2134

x86架构Linux下的MIPS交叉编译工具链 mips-mti-elf-*

Codescape.GNU.Tools.Package.2017.10-05.for.MIPS.MTI.Bare.Metal.CentOS-5.x86_64

u-boot.lds分析

u-boot.lds代码如下:      简要说明该文件作用,该文件是链接脚本文件,在编译uboot时指定uboot可执行镜像文件链接方式,指定个段的装载地址与执行地址 /* /*指定输出文件格式elf,32位mips指令,大端*/ OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") */ OUTPU

Linux_Spirit的专栏 868

链接脚本详解

非常详尽的链接脚本语法讲解,学习脚本的好文档。

rk3588s-摄像头适配gc8034

若还打开失败,需要看下XML中文件配置是否与DTS配置信息一致,或者XML参数配置是否有异常;MIPI摄像头是有上电时序要求,具体时序要查看sensor芯片对应的datasheet进行修改,如果时序不满足,sensor无法正常,此时用i2ctool去查看设备可能无法扫面到设备,即是i2c设备找不到。RK3588或者RK3588S有路MIPI-PHY,驱动开发工程师需要根据对应的硬件原图进行配置,以下会讲解分别使用MIPI-DPHY和MIPI-D/CPHY如何在DTS配置mipi摄像头的回环链路。

Yxx8066的博客 2200

linux二进制反编译,mips 纯二进制反汇编(bin文件)

Usage: mipsel-linux-objdump Display information from object .At least one of the following switches must be given:-a, --archive-headers Display archive header information-f, --file-headers Display the...

weixin_28877739的博客 840

Simulink中扩张状态观测器ESO搭建与参数整定实战

扩张状态观测器(ESO)是自抗扰控制(ADRC)的核心,用于估计系统总扰动并实时补偿。其原理是将扰动扩张为状态变量,通过观测器带宽配置增益,实现扰动估计。在Simulink中搭建ESO可直观验证连续与离散域性能,解决参数整定与噪声折中问题。典型应用包括运动控制、电力电子和机器人驱动。本文基于MATLAB/Simulink,详细讲解线性ESO的模型结构、参数计算、离散化实现及常见问题排查,帮助读者从零搭建并调试ESO仿真。

weixin_34116482的博客 221

链接文件的编写语法

您可以使用任何C赋值运算符创建全局符号,并为全局符号赋值(地址):在ld表达式中,赋值和其他运算符有两个区别。赋值只能在表达式的根处使用a=b+3;'是允许的,但a+b=3;'是一个错误。必须在赋值语句的末尾加一个尾随分号(“;”)。分配语句可能出现:作为ld脚本中的命令;或作为SECTIONS命令中的独立语句;或作为SECTIONS命令中节定义内容的一部分。前两种情况实际上是等效的——都定义了一个具有绝对地址的符号。

ptw1992的博客 2235

3dMax效率翻倍!用Octopus章鱼插件打造你的专属快捷菜单(附MaxScript入门指南)

本文详细介绍了如何利用Octopus插件和MaxScript脚本在3dMax中打造高效快捷菜单,显著提升三维建模与动画制作的工作效率。通过饼状菜单系统、自动化宏录制和脚本控制,用户可实现个性化工作流,节省大量操作时间。文章还提供了MaxScript入门指南,帮助开发者快速掌握这一强大工具。

weixin_30920853的博客 151

STM32 CubeMX实战:手把手教你用I2C驱动IST8310磁力计(附完整代码)

本文详细介绍了如何使用STM32 CubeMX和I2C驱动IST8310磁力计,从硬件连接到代码实现的完整流程。重点讲解了I2C通信异常处理、传感器初始化序列优化以及中断驱动数据采集方案,帮助开发者快速搭建可靠的地磁场数据采集系统。

weixin_42531163的博客 189

链接脚本基本语法

本文绝大部分翻译自https://users.informatik.haw-hamburg.de/~krabat/FH-Labor/gnupro/5_GNUPro_Utilities/c_Using_LD/ldLinker_scripts.html 最后一小部分翻译自:Builtin Functions (LD) 加上了一些我自己的备注。 链接脚本控制每次链接。这样的脚本是用链接器命令语言编写的。链接脚本的主要目的是描述如何将输入文件中的各个section(节)映射到输出文件中,并控制输出文件的内存布

团长的专栏 4189

保姆级教程:用Arduino+MPU6050自制寻北仪(附MEMS陀螺精度测试报告)

本文提供了一份详细的Arduino与MPU6050自制寻北仪的保姆级教程,包括硬件选型、卡尔曼滤波算法优化、地磁场补偿及真北计算等关键技术。通过实测数据展示了MEMS陀螺仪在民用领域的高精度性能,帮助读者低成本实现1°以内的寻北精度。

weixin_42522964的博客 364

LD 文件:规则详解

Contents 概论 基本概念 脚本格式 简单例子 简单脚本命令 对符号的赋值 SECTIONS命令 MEMORY命令 PHDRS命令 VERSION命令 脚本内的表达式 暗含的连接脚本 概论 每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section...

申小白 6万+

信息安全-入侵检测技术原理与应用

入侵检测技术原理与应用、入侵检测概述、入侵检测技术、入侵检测系统组成与分类、入侵检测系统主要产品与技术指标、入侵检测系统应用

我的个人博客 1万+

从代码仓库到知识库:自动化构建与RAG技术实践

在软件工程领域,代码库的规模与复杂性日益增长,如何高效管理和利用其中的知识成为关键挑战。传统文档工具主要依赖注释提取API信息,而现代知识构建技术则通过抽象语法树(AST)解析、自然语言处理等手段,深入理解代码结构、调用关系和业务逻辑。其核心价值在于将非结构化代码转化为机器可理解、可检索的结构化知识,显著提升代码资产的可维护性和团队协作效率。这一过程通常涉及代码解析、信息提取、向量化表示和存储索引四个关键阶段,其中向量化技术将代码语义转化为高维向量,为语义搜索奠定基础。结合检索增强生成(RAG)架构,开发者

weixin_42545292的博客 412

LD文件详解

DEFINED(__heap_size__) 检查__heap_size__是否已经被定义,如果有定义就返回1,没定义就返回0。但是这里后面跟着?意义就变了,变成了像C语言一样“DEFINED(__heap_size__)?__heap_size__ : 0x00000400”成了一个整体。如果__heap_size__有定义就返回__heap_size__的值,没定义就返回0x00000400。

qiu421的博客 2266

23、电生理与CSD分析:探索大脑活动的前沿技术

本文介绍了电生理与电流源密度(CSD)分析在探索大脑活动中的前沿应用。从电生理技术的发展现状,到局部场电位(LFPs)的起源与解释,重点阐述了CSD分析的原理、实验方法及其在绘制皮层兴奋流、解析突触输入和研究自发振荡中的广泛应用。文章还总结了该领域的优势与挑战,并展望了技术改进、多模态融合、数据分析创新及临床拓展的未来方向,展示了这些技术在揭示大脑功能机制中的关键作用。

Apple的专栏 119

ld、ld.so命令和ld.so.conf配置文件

ld.so.conf配置文件 动态装载器(dynamic loader) 程序如何进行动态链接呢?在/etc/ld.so.conf文件中存放着需要动态加载的目录,使用ldconfig就可以将ld.so.conf中的指定目录的库文件加载到内存中,并记录/etc/ld.so.cache中。ld.so.1文件就可以在高速缓存中训中动态库文件,提高访问速度。 例子: 在ld.so.conf文件中包含ld...

SundayO的博客 8904

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

链接脚本 ld文件 和 sct 文件的介绍

ld文件(GNU 链接器脚本)和sct文件(ARM 分散加载描述文件)都是用来的关键配置文件。

weixin_46158019的博客 1767

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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

LD组合了许多对象文件和归档文件,重新定位它们的数据并绑定符号引用。通常编译程序的最后一步是运行LD。LD(Linker)文件是一个负责将目标文件和库文件链接成可执行文件或共享库的程序。每个可加载或可分配的输出section都有两个地址。第一个是VMA,即虚拟内存地址。这是运行输出文件时该节所拥有的地址。第二个是LMA,即加载内存地址。在大多数情况下,这两个地址将是相同的。

千月星跡 3895

S32DS中.ld(链接)文件学习

程序代码(.s 和 .c)源文件会经过预编译、编译、汇编、链接最后生成目标可执行文件,.ld文件是作用在链接过程。链接的作用是:合并各个.obj文件的section,合并符号表,进行符号解析;符号地址重定位;生成可执行文件。linker_flash.ld:Flash和SRAM内存分配,为Flash构建目标分配代码段和数据段;linker_ram.ld:SRAM内存分配,为RAM构建目标分配代码段和数据段。可以利用.ld文件将函数和变量放置到自定义的地址中。ENTRY命令:运行一个程序时第一个被执行到的指令的

studyingdda的博客 1万+

assert ld文件_LD 文件:规则详解

LD 文件:规则详解概论基本概念脚本格式简单例子简单脚本命令对符号的赋值SECTIONS命令MEMORY命令PHDRS命令VERSION命令脚本内的表达式暗含的连接脚本1. 概论每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名) 控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局. 但你也...

weixin_36478445的博客 851

【FreeRTOS】ld链接文件

本文介绍了STM32F407vg芯片的链接文件组成与功能,通过精确的内存规划和段管理,确保程序正确初始化和高效。

从事20多年的嵌入式系统开发与软件开发工作,愿意与同学们分享各种开发经验!搞技术,没有年龄限制,限制你的是你的技术能力一直举步不前... ... 1152

使用 ld 命令链接目标文件生成可执行文件

使用ld链接目标文件生成可执行文件,用于取代命令g++,仅仅用于学习ld命令的使用,不用于实际的项目编译。 首先看一个简单的C++源文件main.cpp。 // //@file:main.cpp // #include <iostream> using namespace std; int main() { cout<&l

Doublelv 的博客专栏。 8188
上一篇: 禁用 baloo_file_extractor 加速 ubuntu 14.04 (KDE)
下一篇: ld中文使用手册完全版
coo1fish
博客等级 码龄14年 22粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值