GNU链接脚本详解

news2024/9/30 13:19:17

0. 前言

每一个链接都是由链接脚本控制的,链接脚本是用链接命令语言编写的脚本。链接都会用到一个链接脚本,如果你没有指定自己的脚本,就会使用默认的链接脚本。可以用 "--verbose" 命令行选项显示默认的连接脚本。指定命令行参数,比如 '-r'、'-N'都会影响默认的链接脚本。也可以用 '-T' 来指定自己的链接脚本,也可以隐式地把自己的连接脚本当成链接输入文件,就像普通的链接文件一
样,参见链接文件说明。

如上图,链接器是将多个对象文件链接成可执行程序。

链接器输入文件:目标文件或链接脚本文件;

链接器输出文件:可执行文件;

目标文件(包括可执行文件) 具有固定的格式,在 Unix 或GNU/linux 平台下,一般为 ELF 格式。

1. 链接器脚本

链接器是由链接器脚本控制,该链接器脚本控制输入文件的链接方式。该脚本以连接器命令语言编写,控制一下链接属性:

  • 输入文件中的部分如何映射到输出文件;
  • 输出文件的文件格式和内存布局;
  • 已创建段的运行时加载属性;
  • 代码执行入口点;
  • 共享库版本;

链接器有一个内置脚本,它用作将代码和数据分配到内存的默认链接器脚本。用户不能修改默认脚本,但是,它可以通过两种方式进行更改:

  • 它可以完全由用户定义的脚本文件替换。在这种情况下,文件名在链接器命令行上指定为链接器选项 -T 的参数;
  • 可以通过将链接器命令上的用户定义脚本文件指定为普通链接器输入文件来扩充它;

指定为普通链接器输入文件的脚本称为隐式脚本。因为它们扩充了默认链接描述文件,所以隐式脚本通常只包含 symbol assignments(符号分配) 或INPUT、GROUP、VERSION 命令。

2. 基础知识 

2.1 分号

在连接器脚本中,分号通常仅出于美观用作分隔符,否则将被忽略。但一下地方是必需的:

  • 分号必需出现在 symbol assignments 的末尾;
  • 分号必需出现在 PHDRS 命令的末尾;

 

2.2 注释

可以使用标准 C 分隔符将注释包含在链接描述文件中:

/*   ...    */

2.3 字符串

文件或格式名称等字符串通常可以直接输入,无需分隔符。

如果文件名包含逗号等字符,否则该字符将用于分隔文件名,则文件名可以用双引号引起来。 文件名中不能使用双引号字符。

2.4 表达式

许多命令参数接受算术表达式。 表达式的语法与 C 中的表达式语法相同,具有以下特点:

  • 所有表达式都被计算为 long 或 unsigned long 类型的整数
  • 所有常量都是整数
  • 提供所有 C 算术运算符
  • 可以定义、创建和引用全局变量
  • 支持多种预定义功能

2.5 位置计数器

链接器中有个特殊变量:点号 ' . '

点号始终包含当前输出位置计数器,由于 点号 始终引入输出节中的位置,它必须始终出现在 SECTIONS 命令中的表达式中。

点号 可以出现在表达式中允许使用普通符号的任何位置,但它的赋值有副作用。

3. 脚本命令

3.1 指定入口地址命令

程序运行的第一条指令就是调用入口地址,可以使用 ENTRY 链接命令来指定程序的入口地址。

入口地址的指定方式有:

  • 通过命令行指定:gcc -e symbol;
  • 链接脚本指定:ENTRY(symbol)

4. 文件处理命令

4.1 INCLUDE

使用 INCLUDE 将其他链接脚本包含到当前脚本,链接器会在当前目录和用 -L 参数指定过的目录下查找被包含的文件。

链接脚本可以嵌套包含,最多层数为 10 层。

INCLUDE 既可以放在链接脚本的开始,也可以放在 MEMROY 或 SECTIONS 命令里面,或放在输出节的描述里面。

 

格式:INCLUDE filename
功能:包含其他脚本文件。
搜索路径:当前目录、-L添加的目录。
放置位置:链接脚本开始、MEMORY或SECTIONS中、输出节描述中。

4.2 INPUT

INPUT 命令直接链接指定的文件名,就像从命令行输入一样。

例如如果要包含subr.o,
但是又不想在每一条链接命令中都写上的话,就可以在链接脚本中使用 ‘INPUT(subr.o)’。实际上,还可以把所有输入文件 (*.o) 都写在链接脚本里面,然后只要用 ' -T ' 指定一下链接脚本就好了。

为了防止设置了根目录,文件名要用'/'开始,这样连接脚本就会从根目录开始检索文件,否则,链接器就会在当前目录下查找文件,如果找不到文件,链接器就会在所有归档库里面检索。根目录也可以在文件名一开始的时候用 ‘=’ 来强制指定,或者在文件名前面加上 $SYSROOT。

如果使用 ‘INPUT (-lfile)’,链接器会自动翻译成libfile.a,就好像使用命令行参数 "-l" 一样。如果使用INPUT命令在链接脚本中包含文件的话,文件会从链接脚本所在的目录开始检索。这会影响到归档文件的检索。

 

格式:
INPUT(file, file, …)
INPUT(file file …)
功能:指定要链接的输入文件(.o,.a)。 搜索路径:$SYSROOT、当前目录。
subr.o包含:INPUT(subr.o)
libfile.a包含:INPUT(-lfile)

4.3 GROUP

格式:

GROUP(file, file, …)

GROUP(file file …)

GROUP命令语法跟 INPUT 差不多,但是专门用来指定归档文件 (*.a),这个会不断的检索直到发现一个新的未定义的符号引用。参见命令行参数里面关于 '-(' 的描述。

4.4 OUTPUT

OUTPUT用来设置输出文件的名称,等价的命令行参数为-o filename。默认输出文件名称为a.out。

格式:OUTPUT(filename)
功能:设置输出文件名称。 等价命令行参数:-o filename

4.5 SEARCH_DIR

SEARCH_DIR命令用来添加链接器的搜索路径,等价的命令行参数是 -L path

如果即用了 -L 也用了SEARCH_DIR,那么链接器会优先使用 -L 设置的路径。

 

格式:SEARCH_DIR(path)
功能:添加链接器的搜索路径。
等价命令行参数:-L path

4.6 STARTUP

STARTUP命令用来指定第一个被链接的输入文件,等价于命令行中第一个输入文件,当目标操作系统的要求程序入口地址必须位于第一个输入文件的时候使用。

格式:STARTUP(filename)
功能:指定第一个被链接的输入文件。
使用场景:目标操作系统的要求程序入口地址必须位于第一个输入文件的时候。

5. 输出文件格式命令

5.1 OUTPUT_FORMAT

OUTPUT_FORMAT命令用来设置输出文件使用的BFD格式。等价的命令行参数为 --oformat bfdname。命令行参数优先。

OUTPUT_FORMAT可以设置三个格式,当命令行没有 -EB 和 -EL的时候,使用第一个格式,当有-EB的时候使用第二个参数,当有 -EL 的时候,使用第三个参数。

 

格式:
OUTPUT_FORMAT(bfdname)
OUTPUT_FORMAT(default, big, little)
功能:设置输出文件使用的BFD格式。 等价命令行:--oformat bfdname

5.2 TARGET

TARGET命令用来设置链接器读取输入文件的时候使用的BFD格式。等价命令行参数 -b bfdname。

格式:
TARGET(bfdname)

6. 其他命令

7. 符号赋值

7.1 像C 一样简单的赋值

symbol = expression ;
symbol += expression ;  
symbol -= expression ;  
symbol *= expression ;  
symbol /= expression ;  
symbol <<= expression ;  
symbol >>= expression ;  
symbol &= expression ;  
symbol |= expression ;  

符号被定义为在脚本中具有全局范围;

符号赋值语句在两方面与链接器脚本表达式中使用运算符不同:

  • 赋值只能在表达式的根部进行,例如, a = b+3; 是允许的,但 a+b=3; 是一个错误;
  • 赋值语句必须以尾部分号结束

赋值语句可以出现在下面位置:

  • 作为链接器脚本中的独立命令;
  • 作为 SECTIONS 命令中的独立语句;
  • 作为 SECTIONS 命令中某一节定义内容的一部分;

7.2 HIDDEN

格式:

HIDDEN(symbol = expression)


定义成 HIDDEN 的符号不会被输出到目标文件,如:

HIDDEN(floating_point = 0);  
SECTIONS
{
  .text :
    {
      *(.text)
      HIDDEN(_etext = .);
    }
   HIDDEN(_bdata = (. + 3) & ~ 3);
  .data : { *(.data) }
}

7.3 PROVIDE

格式:

PROVIDE(symbol = expression)


定义一个输入文件里面引用但未定义的符号,如:

SECTIONS
{
  .text :
    {
      *(.text)
      _etext = .;
      PROVIDE(etext = .);
    }
}

_etext 可以在输入文件中引用,如果输入文件中也定义了 _etext,那么优先使用输入文件中的,但是如果输入文件中定义了_etext,链接的时候就会报多重定义的错误。

 

7.4 PROVIDE_HIDDEN

跟 PROVIDE 功能类似,但不会输出到目标文件中。

8. SECTIONS 命令

SECTIONS
{
  sections-command
  sections-command
  …
}

在一个脚本文件中只能声明一条 SECTIONS 命令,但是该命令可以包含任意数量的语句来指定必要的映射和放置信息。

每一个SECTIONS 的组成都有:

  • ENTRY 命令;
  • 符号排列;
  • 输出section 的描述;
  • 覆盖描述;

如果链接文件中没有定义SECTIONS,那么输入文件中的节就会原封不动的输出到目标文件中。

8.1 输出section 描述

SECTIONS命令中最常用的语句是输出部分描述,它指定了输出部分的属性:它的位置、对齐方式、内容、填充模式和目标内存区域。

格式:

section [address] [(type)] :
  [AT(lma)]
  [ALIGN(section_align) | ALIGN_WITH_INPUT]
  [SUBALIGN(subsection_align)]
  [constraint]
  {
    output-section-command
    output-section-command
    …
  } [>region] [AT>lma_region] [:phdr :phdr …] [=fillexp] [,]
  • 一个输出section 的名称可以由任何字符序列组成;
  • section 名称声明周围需要留白,以确保名称的明确性;
  • 输出section 名称后面,冒号 ' : ' 和  ' { } ' 是必需的; 
  • ALIGN 强制输出section地址对齐,SUBALIGN 强制输入section 地址对齐;
  • 一个输出section 的描述,由一个或多个语句组成,包括:
    • 符号分配;
    • 输入section 描述;
    • 直接包含是输出section 的数据;
    • 特殊的输出section 关键字;

 

8.2 输入 section 描述

输入section 的描述指定了被映射到输出section 的输入部分。

*(.init.rodata .init.rodata.*)

这里使用了通配符,表示输入部分为:

  • * 代表所有目标文件;
  • 后面括号,是指.init.rodata 段 和 .init.rodata.* 段;

这句话意思是:将所有目标文件中的 .init.rodata 段和 .init.rodata.* 段都包含到输出 section 中。

8.2.1 输入 section 描述的通配符

* 号:任意数量的字符;

? 号:任何单个字符;

[CHARS] 号:匹配任意一个CHARS内的单个字符,可用 ' - ' 号表示范围。例如,[ A-Z ],表示匹配 A~Z之间的单个字符;

8.2.2 KEEP

KEEP(*(.initcallearly.init))

当链接命令行使用选项 --gc-secionts 后,链接器可能将某些它认为没用的 section 过滤掉。

KEEP 用来强制链接器保留一些特定的 section。

例如上面代码,其实可以看成:

*(.initcallearly.init)

加上KEEP,则要求链接器不能优化掉这个section,哪怕是没用。

 

参考:

https://blog.csdn.net/shenjin_s/article/details/88712249

https://zhuanlan.zhihu.com/p/516338675

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unreal Engine 学习笔记 (2)—— 走跑切换

1.创建并编辑混合空间 鼠标右击内容浏览器选中动画选中混合空间1D选择对应的骨骼重命名为1D双击1D的图标&#xff0c;进入混合空间的编辑界面鼠标点开水平坐标标签设置名称为Speed设置最大轴值为600拖放对应动画到采样点中 2.创建动画蓝图 鼠标右击内容浏览器选中动画选中动…

【NLP】特征提取: 广泛指南和 3 个操作教程 [Python、CNN、BERT]

什么是机器学习中的特征提取&#xff1f; 特征提取是数据分析和机器学习中的基本概念&#xff0c;是将原始数据转换为更适合分析或建模的格式过程中的关键步骤。特征&#xff0c;也称为变量或属性&#xff0c;是我们用来进行预测、对对象进行分类或从数据中获取见解的数据点的…

国自然中标越来越难,怎样才能赢在起跑线上?

众所周知&#xff0c;国自然在学术界的地位和影响力不容小觑。“国自然在手&#xff0c;天下我有”&#xff0c;对于科研人来说&#xff0c;成功申报国自然&#xff0c;有助于职称评审、职业升迁&#xff0c;同时&#xff0c;获得不菲的科研经费。据了解&#xff0c;有些高校还…

MCU常见通信总线串讲(一)—— UART和USART

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言一…

第七章 图【数据结构与算法】【精致版】

第七章 图【数据结构与算法】【精致版】 前言版权第七章 图7.1 应用实例7.2图的基本概念7.3图的存储结构7.3.1邻接矩阵**1-邻接矩阵.c****2-邻接矩阵plus.c** 7.3.2 邻接表**3-邻接表.c** **4-邻接表plus.c** 7.3.3 十字链表7.3.4多重链表 7.4图的遍历7.4.1深度优先搜索遍历**5…

每天一点python——day62

为了方便复制&#xff0c;我在下面附带了一个python文件。 C:\Users\Admin>python Python 3.9.13 (main, Aug 25 2022, 23:51:50) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32Warning: This Python interpreter is in a conda environment, but the environmen…

【蓝桥杯选拔赛真题13】C++最短距离 青少年组蓝桥杯C++选拔赛真题 STEMA比赛真题解析

C/C++最短距离 第十二届青少组蓝桥杯C++选拔赛真题 一、题目要求 1、编程实现 有一个居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为 1,2,3……,当排满一行时,从下一行相邻的楼往反方向排号。 例如:小区为 3 行 6 列,矩阵排列方式: 要求:已知小区…

python 之列表的常用方法

文章目录 1. **append()** 方法2. **extend()** 方法3. **insert()** 方法4. **pop()** 方法5. **remove()** 方法6. **clear()** 方法7. **index()** 方法8. **count()** 方法9. **reverse()** 方法10. **sort()** 方法 当操作 Python 列表时&#xff0c;常用的方法如下。以下…

Python学习笔记--模块简介

一、Python 模块简介 在开发过程中&#xff0c;随着程序代码越写越多&#xff0c;在一个文件里代码就会越来越长&#xff0c;越来越不容易维护。 后面我们学习了函数&#xff0c;知道函数是实现一项或多项功能的一段程序&#xff0c;这样就更方便我们重复使用代码。 紧接着&…

解析半导体测试系统及半导体的测试方法步骤

半导体如今在集成电路、通信系统、照明等领域被广泛应用&#xff0c;是一种非常重要的材料。在半导体行业中&#xff0c;半导体测试是特别关键的环节&#xff0c;以保证半导体器件及产品符合规定和设计要求&#xff0c;确保其质量和性能。 随着现代电子技术的发展&#xff0c;半…

移远EC600U-CN开发板 day02

1.QuecPythonLVGL显示图片 由于官方提供的显示图片函数使用失败&#xff0c;为了能在屏幕上显示图片&#xff0c;通过对出厂脚本的分析&#xff0c;成功使用LVGL显示图片 (1)代码 import lvgl as lv from tp import gt9xx from machine import LCD from machine import Pin …

别让噪声偷走你的听力

欢声笑语&#xff0c;音乐悠扬&#xff0c;燕语莺声&#xff0c;流水潺潺&#xff0c;和亲友畅所欲言…… 这些愉悦的声音让我们每天的生活更充实&#xff0c;他们也是美好记忆的重要组成部分。听力对于我们的身体健康、情感幸福和整体生活质量起着巨大的作用。 因此保护听力健…

华为fusionInsigtht集群es连接工具

华为fusionInsight为用户提供海量数据的管理及分析功能&#xff0c;快速从结构化和非结构化的海量数据中挖掘您所需要的价值数据。开源组件结构复杂&#xff0c;安装、配置、管理过程费时费力&#xff0c;使用华为FusionInsight Manager将为您提供企业级的集群的统一管理平台,在…

大数据管理平台有什么用?如何利用大数据管理平台优化企业运营?

在数字化时代&#xff0c;大数据管理平台已经成为了企业和组织不可或缺的工具。它不仅可以帮助企业跟踪和解决报修问题&#xff0c;还为数据分析提供了丰富的信息。通过合理利用大数据管理平台进行数据分析&#xff0c;企业可以更好地了解其运营情况&#xff0c;优化设备维修和…

攻防世界题目练习——Web引导模式(四)(持续更新)

题目目录 1. shrine2. very_easy_sql 1. shrine 打开网页题目内容如下&#xff1a; 是一段代码&#xff0c;我们把它还原一下&#xff1a; import flask import osapp flask.Flask(__name__) app.config[FLAG] os.environ.pop(FLAG) #这里应该是将config配置里的FLAG字段设…

Time series analysis of InSAR data: Methods and trends(NASA,2015)

文章目录 ISPRS J PHOTOGRAMMIntroductionPhase unwrapping相位解缠算法综述 Time series analysis of InSAR dataPersistent Scatterer Interferometry (PSI)--持久散射体☆☆☆☆PSInSAR && SBAS-InSAR☆☆☆☆PS-InSARSBAS-InSARDS-InSAR&#xff08;分布式散射体干…

金秋云创季——ECS爆品省钱攻略

阿里云双十一推出优惠活动——“金秋云创季”&#xff0c;其中&#xff0c;云服务ECS下的经济型e实例&#xff0c;低至99元/1年&#xff0c;新老用户都可购买&#xff0c;续费不涨价&#xff1b;轻量应用服务器&#xff0c;2核2G 低至87元1年……官方满减优惠享受折上折。惊喜不…

微服务架构——笔记(4)

微服务架构——笔记&#xff08;4&#xff09; 基于分布式的微服务架构 本次笔记为 此次项目的记录&#xff0c;便于整理思路&#xff0c;仅供参考&#xff0c;笔者也将会让程序更加完善 内容包括&#xff1a;8001集群构建&#xff0c;负载均衡&#xff0c;服务发现&#xff0…

day51

前端框架Booststrap 该框架已经帮我们写了很多页面样式&#xff0c;如果需要使用&#xff0c;只需要下载对应文件直接cv即可 在使用Booststrap的时候&#xff0c;所有发页面样式只需要通过修改class属性来调节即可 什么是Booststrap Bootstrap是一个开源的前端框架&#xff…

基于junit4搭建自定义的接口自动化测试框架

随着业务的逐步稳定&#xff0c;对于接口的改动也会逐渐变少。更多的是对业务逻辑的优化&#xff0c;功能实现的完善。对于测试来说&#xff0c;重复繁琐的功能测试不仅效率低下&#xff0c;而且耗费一定的人力资源。笔者支持的信息流业务下的一个图文管理平台就是一个功能较为…