Linker Scripts3--简单的链接脚本命令1

本文介绍了链接脚本的基础概念,包括如何设置程序入口点(entrypoint),处理文件的命令,以及如何处理对象文件格式等内容。此外还详细说明了如何利用MEMORY命令创建存储区域并使用REGION_ALIAS为其创建别名,以实现输出section的灵活映射。

1.前言

这个部分我们描述了简单的链接脚本命令

2.设置entry point

程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数是一个符号名:

ENTRY(symbol)

有几种方法可以设置entry point,链接器会按照如下的顺序来try各种方法,只要任何一种方法成功则会停止:

  • the ‘-e’ entry command-line option;
  • the ENTRY(symbol) command in a linker script;
  • the value of the symbol start, if defined;
  • the address of the first byte of the ‘.text’ section, if present;
  • The address 0

3.Commands Dealing with Files

有几种处理文件的链接脚本命令:

  •  INCLUDE filename:这里包含了链接脚本文件名

这个文件会在当前目录搜索,或者在"-L"指定的目录搜索,可以嵌套调用INCLUDE达10级

即: 文件1内INCLUDE文件2, 文件2内INCLUDE文件3… , 文件10内INCLUDE文件11. 那么文件11内不能再出现 INCLUDE指令了.

可以把INCLUDE命令放到文件的最前面,也可以放到MEMORY或SECTIONS命令里面,或者放到输出section描述里面。

  •  INPUT(file, file, ...)
  • INPUT(file file ...)

INPUT命令指导链接器在链接时包含文件,否则它们必须出现在命令行

举例来说,如果你链接的时候总是想包含"subr.o",但是不想在每行命令行里输入,可以把‘INPUT (subr.o)’放到链接脚本里

事实上可以把所有的输入文件放到链接脚本里,然后通过-T选项来调用链接器

这种情况下,sysroot前缀被配置,文件名以“/”开始,被处理的脚本位于sysroot前缀,文件名将在sysroot前缀搜索。

否则链接器将在当前目录搜索,如果没有发现,将搜索archive库搜索路径,可以参考‘-L’ in Section 2.1 [Command Line Options], page 3.

如果使用‘INPUT (-lfile)’,则ld将转换文件名为libfile.a,与命令行参数"-l"一样

  •    GROUP(files) : 指定需要重复搜索符号定义的多个输入文件

除了file必须是库文件以外,该命令与INPUT相似, 且file文件作为一组被ld重复扫描,直到不在有新的未定义的引用出现。

  • OUTPUT(FILENAME) : 定义输出文件的名字

同ld的-o选项, 不过-o选项的优先级更高. 所以它可以用来定义默认的输出文件名. 如a.out

  • SEARCH_DIR(PATH) :定义搜索路径,

同ld的-L选项, 不过由-L指定的路径要比它定义的优先被搜索。

  • STARTUP(filename) : 指定filename为第一个输入文件

在链接过程中, 每个输入文件是有顺序的. 此命令设置文件filename为第一个输入文件。

就象这个文件是在命令行上第一个被指定的文件一样, 如果在一个系统中,,入口点总是存在于第一个文件中,那这个就很有用。

4.Commands Dealing with Object File Formats

  • OUTPUT_FORMAT(BFDNAME) : 设置输出文件使用的BFD格式

同ld选项-o format BFDNAME, 不过ld选项优先级更高.

  • OUTPUT_FORMAT(DEFAULT,BIG,LITTLE) : 定义三种输出文件的格式(大小端)

对于此命令,要在命令行中使用-EB或-EL选项来指定不同的输出文件格式

如果'-EB'和'-EL'都没有使用, 那输出格式会是第一个参数 DEFAULT,

如果使用了'-EB',输出格式会是第二个参数 BIG,

如果使用了'-EL', 输出格式会是第三个参数, LITTLE.

比如:缺省的基于 MIPS ELF 平台连接脚本使用如下命令:

OUTPUT_formAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)

这表示缺省的输出文件格式是'elf32-bigmips', 但是当用户使用'-EL'命令行选项的时候, 输出文件就会被以`elf32-littlemips'格式创建.

  • TARGET(BFDNAME):设置输入文件的BFD格式

同ld选项-b BFDNAME. 若使用了TARGET命令, 但未使用OUTPUT_FORMAT命令, 则最用一个TARGET命令设置的BFD格式将被作为输出文件的BFD格式.

5. Assign alias names to memory regions

别名可以被加到用MEMORY命令创建的存储区域.每个名称对应着最多一个存储区域

REGION_ALIAS函数创建了存储区域region的一个别名.这使得输出section可以灵活地映射到存储区域。后面有一个例子。

假设我们有一个具有各种存储设备的嵌入式系统的应用:

(1)各存储设备存储特性

易失性存储器RAM允许执行代码或存储数据;

非易失性存储器ROM允许执行代码和数据只读访问;

非易失性存储器ROM2,具有只读数据访问和不可运行代码的特性。

(2)我们有四个输出sections:

  .text 程序代码

 .rodata 只读数据

 .data 可读写初始化数据

 .bss 可读写初始化数据,但数据必须被初始化为0.

(3)目标是提供一个链接器命令文件,该文件包含定义输出sections的系统独立部分和映射输出sections到系统上有效的存储区域的系统非独立部分.我们的嵌入式系统带有三种不同的存储配置A,B和C:

SectionVariant AVariant BVariant C 
.textRAMROMROM 
.rodataRAMROMROM2 
.dataRAMRAM/ROMRAM/ROM2 
.bssRAMRAMRAM 

 

注:符号RAM/ROM 或 RAM/ROM2 表示这个section会被加载到相应的区域ROM 或 ROM2.请注意data section的加载地址是基于三个变量中.rodata section的末尾开始的.

(4)基本链接器脚本处理了如下输出section.它包含了系统非独立的linkcmds.memory文件,该文件用于描述存储分布:

INCLUDE linkcmds.memory
      
SECTIONS
{
    .text :
    {
        *(.text)
    } > REGION_TEXT
    .rodata :
    {
        *(.rodata)
        rodata_end = .;
    } > REGION_RODATA
    .data : AT (rodata_end)
    {
        data_start = .;
        *(.data)
    } > REGION_DATA
    data_size = SIZEOF(.data);
    data_load_start = LOADADDR(.data);
    .bss :
    {
        *(.bss)
    } > REGION_BSS
 }

 

(5)现在我们需要三个不同的 linkcmds.memory 文件来定义存储区域和别名。 针对A,B和C三种的linkcmds.memory的内容如下:

A Here everything goes into the RAM.
这里所有的都进入到RAM
 MEMORY
 {
     RAM : ORIGIN = 0, LENGTH = 4M
 }
          
 REGION_ALIAS("REGION_TEXT", RAM);
 REGION_ALIAS("REGION_RODATA", RAM);
 REGION_ALIAS("REGION_DATA", RAM);
 REGION_ALIAS("REGION_BSS", RAM);

 

B Program code and read-only data go into the ROM.   Read-write data goes into the RAM.   An image of the initialized data is loaded into the ROM and will be copied during system start into the RAM. 程序代码和只读数据进入的是ROM。可读写的数据进入的是RAM。初始化数据的一个镜像被加载到ROM并且当系统启动时会被拷贝到RAM。
MEMORY
{
        ROM : ORIGIN = 0, LENGTH = 3M
        RAM : ORIGIN = 0x10000000, LENGTH = 1M
} REGION_ALIAS(
"REGION_TEXT", ROM); REGION_ALIAS("REGION_RODATA", ROM); REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM);

C Program code goes into the ROM. Read-only data goes into the ROM2.

  Read-write data goes into the RAM.   An image of the initialized data is loaded into the ROM2 and will be copied during system start into the RAM.

程序代码进入的是ROM。只读数据进入的是ROM2。可读写的数据进入的是RAM。初始化数据的一个镜像被加载到ROM2并且当系统启动时被拷贝到RAM。

MEMORY
{
      ROM : ORIGIN = 0, LENGTH = 2M
      ROM2 : ORIGIN = 0x10000000, LENGTH = 1M
      RAM : ORIGIN = 0x20000000, LENGTH = 1M
}
          
REGION_ALIAS("REGION_TEXT", ROM);
REGION_ALIAS("REGION_RODATA", ROM2);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);

 

It is possible to write a common system initialization routine to copy the .data section from ROM or ROM2 into the RAM if necessary:

如果需要,请尽可能地写一个通用的系统初始化例程,实现把.data section从ROM/ROM2拷贝到RAM。

#include <string.h>
     
extern char data_start [];
extern char data_size [];
extern char data_load_start []; void copy_data(void) { if (data_start != data_load_start) { memcpy(data_start, data_load_start, (size_t) data_size); } }

 6. Other Linker Script Commands

  • ASSERT(exp, message)

确保exp是非0的
如果是0则退出链接,并返回错误码,打印message

  • EXTERN(symbol symbol ...)

强制未定义的符号链接进输出文件,这样可以触发链接器从标准库文件链接。
每个EXTERN可以列出几个symbol,也可以使用多个EXTERN,跟在命令行使用-u选项是一样的

  • FORCE_COMMON_ALLOCATION

 

  • INHIBIT_COMMON_ALLOCATION

 

  • INSERT [ AFTER | BEFORE ] output_section

 

  • NOCROSSREFS(section section ...)

让ld产生一个错误

  • OUTPUT_ARCH(bfdarch)

指定一个特别的输出机器结构,参数用的是BFD库的名字。你可以使用objdump程序的‘-f’选项查看目标文件的机器结构

 

参考文献

[1] http://blog.youkuaiyun.com/han22647/article/details/64920623

[2] http://blog.youkuaiyun.com/huiyuyang_fish/article/details/16884593

 

转载于:https://www.cnblogs.com/smartjourneys/p/8328240.html

<think> 我们正在处理一个编译错误:在文件 scripts/Kconfig.include 的第40行,出现了 &#39;linker &#39;aarch64-none-linux-gnu-ld&#39; not found&#39; 错误。 这个错误表明编译过程中找不到名为 &#39;aarch64-none-linux-gnu-ld&#39; 的链接器。 分析: 1. 这个链接器是用于交叉编译到aarch64架构的。通常,在x86主机上编译ARM64(aarch64)的程序时需要使用交叉编译工具链。 2. 错误信息提示系统在PATH环境变量或者指定的路径中找不到这个链接器。 可能的原因: - 没有安装交叉编译工具链。 - 安装的工具链名称不匹配(例如,安装的工具链可能是&#39;aarch64-linux-gnu-ld&#39;而不是&#39;aarch64-none-linux-gnu-ld&#39;)。 - 工具链的路径没有添加到环境变量PATH中。 解决方案: 步骤1:安装交叉编译工具链 对于Ubuntu/Debian系统,可以安装以下包: sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu 安装后,链接器的名称通常是&#39;aarch64-linux-gnu-ld&#39;。 步骤2:检查工具链名称 如果安装的工具链名称是&#39;aarch64-linux-gnu-ld&#39;,但脚本需要的是&#39;aarch64-none-linux-gnu-ld&#39;,我们可以通过创建符号链接来解决。 首先,确定安装的链接器路径: which aarch64-linux-gnu-ld 通常,它会出现在/usr/bin/aarch64-linux-gnu-ld。 然后,创建一个符号链接: sudo ln -s /usr/bin/aarch64-linux-gnu-ld /usr/bin/aarch64-none-linux-gnu-ld 步骤3:检查环境变量PATH 确保包含链接器的目录(通常是/usr/bin)在PATH环境变量中。 步骤4:修改Kconfig配置 如果上述方法不起作用,可能需要修改scripts/Kconfig.include文件,更改链接器的名称。 在第40行附近,可能有类似下面的设置: LDFLAGS = -fuse-ld=aarch64-none-linux-gnu-ld 或者 check_linker_flag()函数调用中指定了链接器名称。 我们可以将其更改为已安装的链接器名称,例如: -fuse-ld=aarch64-linux-gnu-ld 注意:修改配置脚本需要谨慎,最好备份原文件。 步骤5:指定工具链路径 在编译时,可以通过环境变量指定交叉编译工具链的路径,例如: export PATH=/path/to/toolchain/bin:$PATH 如果安装了工具链但不在默认路径,需要将其添加到PATH。 总结:首先尝试安装正确的工具链,然后通过符号链接解决名称不一致问题,或者修改脚本中的链接器名称。 引用说明:根据常见的交叉编译问题解决经验,以及Linux系统管理知识[^1][^2]。 相关问题: 1. 如何检查交叉编译工具链是否安装正确? 2. 在Linux中如何创建和使用符号链接3. 如何修改环境变量PATH? </think> ### 解决 `scripts/Kconfig.include` 文件第 40 行 `linker &#39;aarch64-none-linux-gnu-ld&#39; not found` 错误的方法 #### 问题分析 该错误表明编译系统在交叉编译环境中找不到指定的链接器 `aarch64-none-linux-gnu-ld`。通常由以下原因导致: 1. **交叉编译工具链未安装** - 系统中缺少 `aarch64-none-linux-gnu` 工具链组件。 2. **工具链名称不匹配** - 已安装的工具链可能使用不同命名(如 `aarch64-linux-gnu-ld`)。 3. **路径配置错误** - 工具链未添加到 `PATH` 环境变量。 4. **Kconfig 配置文件错误** - `scripts/Kconfig.include` 中硬编码了错误的工具链名称[^1]。 --- #### 逐步解决方案 ##### 步骤 1:安装交叉编译工具链 安装适配 `aarch64` 架构的工具链: ```bash sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu ``` 验证安装: ```bash aarch64-linux-gnu-ld --version # 检查链接器是否存在 ``` ##### 步骤 2:创建符号链接(若名称不匹配) 若工具链名称为 `aarch64-linux-gnu-ld` 而非 `aarch64-none-linux-gnu-ld`: ```bash sudo ln -s /usr/bin/aarch64-linux-gnu-ld /usr/bin/aarch64-none-linux-gnu-ld ``` ##### 步骤 3:检查环境变量 确保工具链路径在 `PATH` 中: ```bash echo $PATH | grep aarch64 # 检查路径 export PATH=$PATH:/usr/aarch64-linux-gnu/bin # 临时添加路径 ``` ##### 步骤 4:修改 Kconfig 文件 编辑 `scripts/Kconfig.include`: 1. 定位第 40 行附近(通常是 `ld-option` 函数定义)。 2. 将 `aarch64-none-linux-gnu-ld` 替换为实际链接器名称: ```diff - ld = aarch64-none-linux-gnu-ld + ld = aarch64-linux-gnu-ld # 或您系统中存在的链接器 ``` 3. 保存并重新编译[^2]。 --- #### 验证修复 重新运行编译命令: ```bash make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- # 根据项目调整 ``` 若无报错,则修复成功。 --- #### 相关问题 1. 如何检查 Linux 系统中已安装的交叉编译工具链? 2. 在 Kconfig 配置中如何自定义工具链路径? 3. 交叉编译时遇到 `undefined reference to symbol &#39;inflateEnd&#39;` 错误应如何解决[^2]? [^1]: 交叉编译工具链命名约定差异导致路径错误。 [^2]: 动态库缺失或链接顺序问题可能引发符号未定义错误。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值