当前位置: 首页 > news >正文

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 名称后面,冒号 ' : ' 和  ' { } ' 是必需的; 
  • 每个输出section 都有一个虚拟地址和加载地址,虚拟地址 VMA就是 section 加载到内存中的地址,加载地址 LMA 就是在目标文件中的地址。LMA 可以通过 AT(lma) 来设置;
  • 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

相关文章:

GNU链接脚本详解

0. 前言 每一个链接都是由链接脚本控制的&#xff0c;链接脚本是用链接命令语言编写的脚本。链接都会用到一个链接脚本&#xff0c;如果你没有指定自己的脚本&#xff0c;就会使用默认的链接脚本。可以用 "--verbose" 命令行选项显示默认的连接脚本。指定命令行参数…...

酷柚易汛ERP-账户管理操作指南

1、应用场景 对账户进行管理&#xff0c;可设置账户当前余额、期初余额和设置是否为默认账户。 2、主要操作 2.1 新增支付账户 打开【资料】-【账款管理】&#xff0c;点击【新增】添加账户类别&#xff0c;输入相关信息并保存&#xff0c;账户编号和名称为必录项。&#x…...

函数的连续性

函数在某一点极限存在&#xff0c;不一定连续 函数的左极限 函数的右极限 函数在某点连续需要满足三个条件 1、左右极限存在 2、左右极限相等 3、函数在该点的极限值等于在该点的函数值 满足1、2两个条件函数在该点极限存在。...

Pandas groupby方法中的group_keys属性

pandas版本1.5.3中groupby方法&#xff0c;当设置group_keysTrue时&#xff0c;会以groupby的字段为第一级索引&#xff0c;如下述代码中time_id作为第一级索引&#xff0c;同时保留了原dataframe&#xff08;df&#xff09;中的索引作为第二级索引。 >>> df.groupby…...

win 命令替代鼠标的操作

操作方式都是在 winR 输入框输入或者终端输入 1、快速打开 控制面板 运行control 2、快速打开 电源选项 运行powercfg.cpl 3、快速打开 网络连接 运行ncpa.cpl 4、快速打开 程序和功能 运行appwiz.cpl 5、快速打开 Windows Defender防火墙 运行Firewall.cpl 6、快速打开 鼠标 …...

Shopee活动取消规则是什么?shopee官方促销活动怎么取消?

作为一家知名的电商平台&#xff0c;shopee官方对于消费者取消促销活动的请求给予了相应的规定和处理流程。 shopee活动取消规则是什么&#xff1f; 首先&#xff0c;消费者应该明确了解虾皮的促销活动取消规则。根据虾皮的官方规定&#xff0c;消费者在参与促销活动之前&…...

安卓常见设计模式2------构建者模式(Kotlin版)

1. W1 是什么&#xff0c;什么是构建者模式&#xff1f; 构建者模式&#xff08;Builder Pattern&#xff09;是一种创建复杂对象的设计模式。它通过使用链式调用的方式&#xff0c;逐步构建对象&#xff0c;使得代码更易读、可维护&#xff0c;并且可以处理许多可选参数的情况…...

redis主从复制+哨兵

1.主从复制 redis配置文件redis.conf master机器&#xff1a;IP 192.168.1.5 &#xff0c;端口 6379 设置配置参数 daemonize yes #bind 127.0.0.1 -::1 protected-mode no port 6379 dbfilename "dump.rdb" dir "/root/redis/my_redis_conf/dumpdir" l…...

html动态爱心超文本标记代码,丝滑流畅有特效,附源码

没想到现在看个剧&#xff08;点燃我&#xff0c;温暖你&#xff09;要的同款居然是代码&#xff0c;李峋 这盛世如你所愿啊&#xff01;李峋的同款爱心代码来啦&#xff0c;拿走试试吧&#xff5e; <!DOCTYPE html> <html><head><title></title&g…...

力扣:162. 寻找峰值(Python3)

题目&#xff1a; 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回 任何一个峰值 所在位置即可。 你可以假设 nums[-1] nums[n] -∞ 。 你必须实现时…...

【Python】20大报告生成词云

这个我其实写过一篇类似的博客&#xff0c;但是那个的文件对象是.csv&#xff0c;对应到.docx文件的话&#xff0c;就不太适用了。如下&#xff1a; Python生成词云-CSDN博客 代码&#xff1a; import jieba import os import wordcloud import numpy as np from PIL import…...

目标检测YOLO实战应用案例100讲-基于无人机的轻量化目标检测系统设计

目录 前言 国内外研究现状 国外研究现状 国内研究现状...

ansible-第二天

ansible 第二天 以上学习了ping、command、shell、script模块&#xff0c;但一般不建议使用以上三个&#xff0c;因为这三个模块没有幂等性。举例如下&#xff1a; [rootcontrol ansible]# ansible test -a "mkdir /tmp/1234"[WARNING]: Consider using the file …...

【测试工具】UnixBench 测试

一、UnixBench 简介 UnixBench 原本叫做 BYTE UNIX benchmark suite。软件为 Unix 类的系统提供了一些基本的性能指标。通过不同的测试来测试系统不同方面的性能&#xff08;2D&#xff0c;3D&#xff0c;CPU&#xff0c;内存等等&#xff09;。这些测试的结果将和一些标准的系…...

软件测试金融项目,在测试的时候一定要避开的一些雷区

软件测试金融项目需要格外谨慎和专注&#xff0c;因为这些项目通常涉及大量的交易、用户隐私和其他敏感信息。以下是一些软件测试金融项目时需要关注的方面&#xff1a; 1. 数据保护 在测试金融项目时&#xff0c;必须确保用户数据和投资信息得到保护。测试人员必须确保测试环…...

顺序图——画法详解

百度百科的定义&#xff1a; 顺序图是将交互关系表示为一个二维图。纵向是时间轴&#xff0c;时间沿竖线向下延伸。横向轴代表了在协作中各独立对象的类元角色。类元角色用生命线表示。当对象存在时&#xff0c;角色用一条虚线表示&#xff0c;当对象的过程处于激活状态时&…...

easyexcel==省市区三级联动

省市区三级联动&#xff0c;不选前面的就没法选后面的 package com.example.demoeasyexcel.jilian2; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import org.apache.poi.ss.use…...

Linux进程控制(二)--进程等待(一)

前言&#xff1a;之前我们讲过&#xff0c;子进程退出&#xff0c;父进程如果不管不顾&#xff0c;就可能造成‘僵尸进程’的问题&#xff0c;进而造成内存泄漏。 另外&#xff0c;进程一旦变成僵尸状态&#xff0c;那就刀枪不入&#xff0c;就连 kill -9 也无能为力&#xff0…...

【C++】C++11常用特性梳理

C11特性梳理 1. 列表初始化2. auto & decltype3. 右值引用3.1. 左右值引用比较3.2. 右值引用的意义3.3. 万能引用与完美转发3.4. 移动构造与移动赋值 4. default & delete5. 可变参数模板6. push_back 与 emplace_back7. lambda表达式7.1. 捕捉列表 8. function包装器8…...

修改iframe生成的pdf的比例

如图想要设置这里的默认比例 在iframe连接后面加上#zoom50即可&#xff0c;50是可以随便设置的&#xff0c;设置多少就是多少比例 <iframe src"name.pdf#zoom50" height"100%" width"100%"></iframe>...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...