GNU链接脚本详解

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-commandsections-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-commandoutput-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.mzph.cn/news/133605.shtml

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

相关文章

微服务之初始微服务

文章目录 一、服务架构演变1.单体架构2.分布式架构 二、认识微服务三、总结四、微服务技术对比五、SpringCloud注意 一、服务架构演变 1.单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署。 优点&#xff1a; 架构简单部署成本…

G-LAB IT实验室【11月】网工公开课 即将开始~

带你一起走进网工的世界&#xff01;G-LAB网工入门免费公开课即将开讲&#xff01;无论是想学习基础网络组网还是网络互通技术实施&#xff0c;这个公开课都是你不容错过的&#xff01; 公开课课程为期两天&#xff0c;11月7日&#xff06;11月8日晚20&#xff1a;00 分享主题…

MFC-网络编程TCP服务端(NBlockSocket)

目录 1、NBlockSocket.h类&#xff1a; &#xff08;1&#xff09;、Init接口函数 &#xff08;2&#xff09;、Register接口函数 &#xff08;3&#xff09;、Send接口函数 &#xff08;4&#xff09;、Accept接口函数 &#xff08;5&#xff09;、Recv接口函数 2、实现…

分布式任务调度(00)--Quartz

1 任务调度整体流程 2 组件 调度器 &#xff1a;工厂类创建Scheduler&#xff0c;根据触发器定义的时间规则调度任务任务&#xff1a;Job表示被调度的任务触发器&#xff1a;Trigger 定义调度时间的元素&#xff0c;按啥时间规则执行任务。一个Job可被多个Trigger关联&#xf…

AI 绘画 | Stable Diffusion 图生图

图生图简介 Stable Diffusion 不仅可以文生图&#xff0c;还可以图生图。文生图就是完全用提示词文本去生成我们想要图片&#xff0c;但是很多时候会有词不达意的感觉。就像我们房子装修一样&#xff0c;我们只是通过文字描述很难表达出准确的想要的装修效果&#xff0c;如果能…

基于element-ui封装可配置表单组件

“vue”: “^2.7.13” “element-ui”: “^2.15.7” 代码地址 【说明】 该组件时使用vue3&#xff08;vue2.7&#xff09;语法封装&#xff0c;使用时可用vue2语法使用也可以使用vue3语法使用 一、vue2语法使用案例 基础用法 <template><div class"form-demo…

Freeswitch代码

1.引入依赖 Freeswitch依赖版本 <dependency><groupId>org.freeswitch.esl.client</groupId><artifactId>esl-client</artifactId><version>0.10.1</version> </dependency> 2.代码 import org.freeswitch.esl.client.inbound…

VR全景如何助力乡村振兴,乡村发展在哪些方面用到VR全景技术

引言&#xff1a; 乡村振兴是当今中国发展的重要战略&#xff0c;也是推动农村经济社会全面发展的关键举措。在这一过程中&#xff0c;虚拟现实&#xff08;VR&#xff09;全景技术正逐渐崭露头角&#xff0c;为乡村振兴提供了机遇。 一&#xff0e;VR全景技术的概念和应用 1…

[科研图像处理]用matlab平替image-j,有点麻烦,但很灵活!

做材料与生物相关方向的同学应该对image-j并不陌生&#xff0c;前几天有个师兄拜托我用image-j分析一些图片&#xff0c;但使用过后发现我由于不了解image-j的工作流程而对结果并不确信&#xff0c;而且image-j的功能无法拓展&#xff0c;对有些图片的处理效果并不好&#xff0…

在Google Kubernetes集群创建分布式Jenkins(一)

因为项目需要&#xff0c;在GKE的集群上需要创建一个CICD的环境&#xff0c;记录一下安装部署一个分布式Jenkins集群的过程。 分布式Jenkins由一个主服务器和多个Agent组成&#xff0c;Agent可以执行主服务器分派的任务。如下图所示&#xff1a; 如上图&#xff0c;Jenkins Ag…

ASO优化之为应用创建屏幕截图的技巧(下)

屏幕截图可以激发潜在用户对我们的应用程序的好奇心和兴趣。我们可以使用它们来吸引用户对产品页面的关注&#xff0c;解释应用程序&#xff0c;并强调其解决用户问题的能力。 1、美化屏幕截图背景。 为了使我们的屏幕截图更加有趣和美观&#xff0c;需要考虑使用背景。设计不…

【微服务】一体化智慧工地管理平台源码

智慧工地系统是一种利用人工智能和物联网技术来监测和管理建筑工地的系统。它可以通过感知设备、数据处理和分析、智能控制等技术手段&#xff0c;实现对工地施工、设备状态、人员安全等方面的实时监控和管理。 一、智慧工地让工程施工智能化 1、内容全面&#xff0c;多维度数…

Day1 ARM基础

【ARM课程认知】 1.ARM课程的作用 承上启下 基础授课阶段&#xff1a;c语言、数据结构、linux嵌入式应用层课程&#xff1a;IO、进程线程、网络编程嵌入式底层课程&#xff1a;ARM体系结构、系统移植、linux设备驱动c/QT 2.ARM课程需要掌握的内容 自己能够实现简单的汇编编…

登录Tomcat控制台,账号密码输入正确但点击登录没反应不跳转到控制台页面

在tomcat-users.xml里面可以查看登录tomcat控制台的账号密码&#xff0c;如果账号密码输入正确还是登录不进去&#xff0c;则很有可能是tomcat的账号被锁了&#xff08;可在catalina.xxx.log里面查看&#xff09;。tomcat账号被锁定后默认情况是不访问控制台后5分钟自动解锁&am…

持续集成交付CICD:安装Jenkins Slave(从节点)

目录 一、实验 1.安装Jenkins Slave&#xff08;从节点&#xff09; 二、问题 1.salve节点启动jenkins报错 2.终止命令行后jenkins从节点状态不在线 一、实验 1.安装Jenkins Slave&#xff08;从节点&#xff09; &#xff08;1&#xff09;查看jenkins版本 Version 2.…

Elasticsearch:搜索架构

Elasticsearch 全文检索的复杂性 为了理解为什么全文搜索是一个很难解决的问题&#xff0c;让我们想一个例子。 假设你正在托管一个博客发布网站&#xff0c;其中包含数亿甚至数十亿的博客文章&#xff0c;每个博客文章包含数百个单词&#xff0c;类似于 CSDN。 执行全文搜索…

11月7日 mybatis缓存

mybatis的缓存 缓存的条件&#xff1a;必须要有存在的数据 一级缓存: SqlSession级别缓存.存储的数据.只能在同一个SalSession有效.默认开启 二级缓存: SqlSessionFactory级别的缓存. SqlSessionFactory只有一个的,单例,全局共享的,不同的 SqlSession共享&#xff0c;默认没有…

基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI 失物招领小程序 设计与实现

一.项目介绍 失物招领小程序 用户登录、忘记密码、退出系统 发布失物 和 发布招领 查看我发布的失物和招领信息 失捡物品模块可以查看和搜索所有用户发布的信息。 二.环境需要 1.运行环境&#xff1a;java jdk1.8 2.ide环境&#xff1a;IDEA、Eclipse、Myeclipse都可以&#…

Linux系统下一些配置建议整理

1. 【推荐】高并发服务器建议调小 TCP 协议的 time_wait 超时时间。 说明&#xff1a;操作系统默认 240 秒后&#xff0c;才会关闭处于 time_wait 状态的连接&#xff0c;在高并发访问下&#xff0c;服 务器端会因为处于 time_wait 的连接数太多&#xff0c;可能无法建立新的…

总结Kibana DevTools如何操作elasticsearch的常用语句

一、操作es的工具 ElasticSearch HeadKibana DevToolsElasticHQ 本文主要是总结Kibana DevTools操作es的语句。 二、搜索文档 1、根据ID查询单个记录 GET /course_idx/_doc/course:202、term 匹配"name"字段的值为"6789999"的文档 类似于sql语句中的等…