链接脚本lds 相关的知识

链接脚本lds 相关的知识,第1张

链接脚本lds相关的知识

目录
  • 链接脚本lds相关的知识
    • 前言
    • 关于vmlinux.lds目标的生成与构建
    • 关于链接脚本的语法
      • sections 输出段
    • 关于vmlinux.lds链接脚本的解读
    • 参考资料

前言

本文主要记录与链接脚本相关的知识。文中内容多来自网上资料,或者书本内容。(解读的除外)。把重要的、常用的或容易忘记的知识点总结记录下来,供以后查询与巩固。

关于vmlinux.lds目标的生成与构建
  • 未经编译的内核源码是不存在vmlinux.lds链接脚本的,在arch/arm/kernel目录只有vmlinux.lds.S文件,以及在include/asm-generi目录有一个与之关联的vmlinux.lds.h文件。在内核编译的时候会根据一些宏定义和传入的参数构建出针对特定平台、特定架构的vmlinux.lds链接脚本。

  • 链接器在链接过程中需要使用链接脚本。如果没有通过 “-T” 参数指定链接脚本时,链接器会使用内置的链接脚本。

  • 链接脚本中有几种设置入口点的方法,请参考链接脚本说明手册。链接器将按顺序尝试以下每一种方法来设置入口点,当其中一种方法成功时停止:

1、 -e 命令行选项
2 、脚本中的entry(symbol)命令
3 、如定义了start的值,取其值为入口点
4 、text段的第一个字节的地址
5 、地址0

关于链接脚本的语法
  • 在链接脚本中,符号可以像高级语言比如C语言一样进行赋值和 *** 作,允许的 *** 作包括赋值、加减乘除、左移、右移、与、或等
  • foo = 0x100 链接脚本定义一个foo符号并赋值,0x100 表示地址的位置。对于符号foo并没有分配任何内存。
  • 在C语言中,符号可以通过"&"来获取符号的址,也可以将符号理解为数组在C语言中使用(具体怎么使用要看链接脚本中怎么定义)
    例如
SECTIONS
{
    start_of_text = . ;
    .text: {*(.text)}
    end_of_text = . ;

    start_of_data = . ;
    .data: {*(.data)}
    end_of_data = . ;
}

在C语言中,使用以下代码可以很方便地访问这些段的起始地址和结束地址。

extern char start_of_text[];
extern char end_of_text[];
extern char start_of_data[];
extern char end_of_data[];
  • “.” 代表的是当前计数器(Location Counter, LC)
SECTIONS
{
    .text :
    {
    *(.text)
    _etext = .;
    }
    /*设置_bdata 的起始地址为当前位置后下一个与4字节对齐的地方。*/
    _bdata = (. + 3 ) & ~ 3; 
    .data:( *(.data) )
}

上面注意注释的地方:从4字节对齐的设置方法

  • HIDDEN 语法HIDDEN(symbol = expression)为ELF目标的端口定义一个符号,符号将被隐藏并且不会被导出
HIDDEN(floating_point = 0);
SECTIONS
{
  .text :
    {
      *(.text)
      HIDDEN(_etext = .);
    }
  HIDDEN(_bdata = (. + 3) & ~ 3);
  .data : { *(.data) }
}

在本例中,这三个符号在此模块之外都不可见

  • PROVIDE 当程序文件(.c , .h , .S中) 没有定义变量,函数,但却引用(extern )了,这时才会用到链接脚本中的符号变量。 有点类似gcc 中的__weak 关键字定义的函数。
    例如
SECTIONS
{
  .text :
    {
      *(.text)
      _etext = .;
      PROVIDE(etext = .);
    }
}

在本例中,如果程序定义了’ _etext ‘(带有前导下划线),链接器将给出重复定义错误。另一方面,如果程序定义了’ etext ‘(没有前导下划线),链接器会默认使用程序中的定义。如果程序引用了’ etext '但没有定义它,链接器将使用链接器脚本中的定义。

sections 输出段

输出段的描述格式如下:

section [address] [(type)]:
    [AT(lma)]
    [ALIGN(section_align)]
    [constraint]
    {
      output-section-command
      output-section-command
      ...
    } [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]

section : 段的名字,输出段的描述,例如代码(.data)段、数据(.data)段等
address : 输出段虚拟内存地址。这个是可选参数。
AT[lam] lma 表示加载地址
region: 特定的内存区域

加载地址由 AT 或 AT> 关键字指定 AT 关键字经常出现在lds中

可以使用’=fillexp’为整个段设置填充模板。fillexp是一个表达式(参考Expressions)。任何其它的未被特殊指定的输出段的内存区域(例如,因为对其输入段产生的缝隙)将会被用fillexp的值填充

关于vmlinux.lds链接脚本的解读

待完成,后面有机会找个时间再完成。

参考资料

1.官方文档 https://sourceware.org/binutils/docs/ld/
2.https://blog.csdn.net/m0_47799526/article/details/108765403
3.https://blog.csdn.net/m0_47799526/article/details/106205109
4.https://zhuanlan.zhihu.com/p/521964756

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/3002865.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存