您的位置:首页 > 财经 > 产业 > 找人做网站需要注意什么_广西传导网络科技有限公司_南昌seo方案_郑州外语网站建站优化

找人做网站需要注意什么_广西传导网络科技有限公司_南昌seo方案_郑州外语网站建站优化

2025/1/10 15:50:36 来源:https://blog.csdn.net/u014100559/article/details/144951783  浏览:    关键词:找人做网站需要注意什么_广西传导网络科技有限公司_南昌seo方案_郑州外语网站建站优化
找人做网站需要注意什么_广西传导网络科技有限公司_南昌seo方案_郑州外语网站建站优化

GNU链接器简介-2

  • 1 简单链接器脚本命令
    • 1.1 Setting the Entry Point
    • 1.2 Commands Dealing with Files
    • 1.3 Commands Dealing with Object File Formats
    • 1.4 Assign alias names to memory regions
    • 1.5 Other Linker Script Commands
  • 2 Assigning Values to Symbols
    • 2.1 Simple Assignments
    • 2.2 HIDDEN
    • 2.3 PROVIDE
    • 2.4 PROVIDE_HIDDEN
    • 2.5 Source Code Reference

该篇文章是基于对 The GNU linker的翻译,并添加了部分自己的理解。

1 简单链接器脚本命令

In this section we describe the simple linker script commands.
在本节中,我们描述了简单的链接器脚本命令。

  • Setting the Entry Point
  • 设置入口点
  • Commands Dealing with Files
  • 文件处理命令
  • Commands Dealing with Object File Formats
  • 处理对象文件格式的命令
  • Assign alias names to memory regions
  • 为内存区域分配别名
  • Other Linker Script Commands
  • 其他链接脚本命令

1.1 Setting the Entry Point

The first instruction to execute in a program is called the entry point. You can use the ENTRY linker script command to set the entry point. The argument is a symbol name:
程序中要执行的第一个指令被称为入口点。你可以使用ENTRY链接脚本命令来设置入口点。参数是一个符号名称:

ENTRY(symbol)

There are several ways to set the entry point. The linker will set the entry point by trying each of the following methods in order, and stopping when one of them succeeds:
有几种方法可以设置入口点。链接器将按顺序尝试以下每种方法来设置入口点,并在其中一种方法成功时停止:

  • the ‘-e’ entry command-line option;
  • “-e”命令行选项;
  • the ENTRY(symbol) command in a linker script;
  • 链接脚本中的ENTRY(symbol)命令;
  • the value of a target-specific symbol, if it is defined; For many targets this is start, but PE- and BeOS-based systems for example check a list of possible entry symbols, matching the first one found.
  • 目标特定符号的值,如果已定义;对于许多目标来说这是start符号,但是基于PE-和BeOS的系统会检查一系列可能的入口符号列表,匹配到的第一个符号。
  • the address of the first byte of the code section, if present and an executable is being created - the code section is usually ‘.text’, but can be something else;
  • 代码段的第一个字节的地址,如果存在并且可执行属性被创建,这个代码段一般是‘.text’,但是也有可能是其他的部分。
  • The address 0.
  • 地址0

1.2 Commands Dealing with Files

Several linker script commands deal with files.
有几条链接器脚本命令与文件有关。

  • INCLUDE filename
    Include the linker script filename at this point. The file will be searched for in the current directory, and in any directory specified with the -L option. You can nest calls to INCLUDE up to 10 levels deep.
    在此处包含链接器脚本文件名。该文件将在当前目录以及使用‘-L’选项指定的任何目录中搜索。你可以嵌套调用INCLUDE,最多可达10层深度。

You can place INCLUDE directives at the top level, in MEMORY or SECTIONS commands, or in output section descriptions.
你可以把INCLUDE放在MEMORY或SECTIONS命令中的顶层、,或在输出部分描述中放置INCLUDE指令。

  • INPUT(file, file, …)
  • INPUT(file file …)

The INPUT command directs the linker to include the named files in the link, as though they were named on the command line.
INPUT命令指示链接器将指定的文件包含在链接中,就好像它们在命令行上被命名了一样。
For example, if you always want to include subr.o any time you do a link, but you can’t be bothered to put it on every link command line, then you can put ‘INPUT (subr.o)’ in your linker script.
例如,如果你总是希望在进行链接时包含‘subr.o’,但你又不想每次都在链接命令行中添加它,那么你可以在链接器脚本中加入‘INPUT (subr.o)’
In fact, if you like, you can list all of your input files in the linker script, and then invoke the linker with nothing but a ‘-T’ option.
实际上,如果你愿意,你可以在链接器脚本中列出你所有的输入文件,然后仅使用一个‘-T’选项来调用链接器。
In case a sysroot prefix is configured, and the filename starts with the ‘/’ character, and the script being processed was located inside the sysroot prefix, the filename will be looked for in the sysroot prefix. The sysroot prefix can also be forced by specifying = as the first character in the filename path, or prefixing the filename path with $SYSROOT.
如果配置了sysroot前缀,并且文件名以‘/’字符开头,且正在处理的脚本位于sysroot前缀内,那么链接器将在sysroot前缀中查找该文件名。否则,链接器将在当前目录中尝试打开文件。如果未找到,链接器将通过归档库搜索路径进行搜索。也可以通过在文件名路径的开头指定=字符,或者在文件名路径前加上$SYSROOT来强制使用sysroot前缀。
If a sysroot prefix is not used then the linker will try to open the file in the directory containing the linker script. If it is not found the linker will then search the current directory. If it is still not found the linker will search through the archive library search path.
如果sysroot前缀没有使用,那么链接器将会尝试去打开链接器脚本所在的目录。如果没有发现,那么链接器将会搜索当前的目录。如果仍未找到,链接器将通过归档文件库搜索路径进行搜索。

If you use ‘INPUT (-lfile)’, ld will transform the name to libfile.a, as with the command-line argument ‘-l’.
如果你使用 'INPUT (-lfile)',ld 将会像处理命令行参数 '-l' 一样,将名称转换为 libfile.a
When you use the INPUT command in an implicit linker script, the files will be included in the link at the point at which the linker script file is included. This can affect archive searching.
当你在隐式链接脚本中使用INPUT命令时,文件将在链接器脚本文件被包含的那一点被包含在链接过程中。这可能会影响归档搜索。

  • GROUP(file, file, …)
  • GROUP(file file …)

The GROUP command is like INPUT, except that the named files should all be archives, and they are searched repeatedly until no new undefined references are created.
GROUP命令类似于INPUT命令,不同之处在于指定的文件应该是归档文件,并且会反复搜索这些文件,直到不再产生新的未定义引用为止。

  • AS_NEEDED(file, file, …)
  • AS_NEEDED(file file …)

This construct can appear only inside of the INPUT or GROUP commands, among other filenames. The files listed will be handled as if they appear directly in the INPUT or GROUP commands, with the exception of ELF shared libraries, that will be added only when they are actually needed. This construct essentially enables --as-needed option for all the files listed inside of it and restores previous --as-needed resp. --no-as-needed setting afterwards.
这个构造只能出现在INPUTGROUP命令中,以及其他文件名中。列出的文件将被处理,就像它们直接出现在INPUT或GROUP命令中一样,除了ELF共享库,只有在实际需要时才会添加。这个构造基本上为其中列出的所有文件启用了‘--as-needed’选项,并在之后恢复之前的‘--as-needed’‘--no-as-needed’设置。

  • OUTPUT(filename)

The OUTPUT command names the output file. Using OUTPUT(filename) in the linker script is exactly like using ‘-o filename’ on the command line (see Command Line Options). If both are used, the command-line option takes precedence.
OUTPUT 命令为输出文件命名。在链接器脚本中使用 OUTPUT(filename) 与在命令行中使用“-o filename ”完全相同(请参阅命令行选项)。如果两者同时使用,命令行选项优先。
You can use the OUTPUT command to define a default name for the output file other than the usual default of a.out.
您可以使用OUTPUT命令来定义一个默认的输出文件名,而不是通常的默认文件名‘a.out’。

  • SEARCH_DIR(path)

The SEARCH_DIR command adds path to the list of paths where ld looks for archive libraries. Using SEARCH_DIR(path) is exactly like using ‘-L path’ on the command line. If both are used, then the linker will search both paths. Paths specified using the command-line option are searched first.
SEARCH_DIR命令将路径添加到ld查找存档库的路径列表中。使用SEARCH_DIR(path)与在命令行上使用‘-L path’完全相同。如果两者都使用,链接器将搜索这两个路径。使用命令行选项指定的路径首先被搜索。

  • STARTUP(filename)

The STARTUP command is just like the INPUT command, except that filename will become the first input file to be linked, as though it were specified first on the command line. This may be useful when using a system in which the entry point is always the start of the first file.
STARTUP命令与INPUT命令类似,不同之处在于filename将成为第一个链接的输入文件,就好像它在命令行中首先被指定一样。当系统的入口点总是第一个文件的起点时,这条命令可能很有用。

1.3 Commands Dealing with Object File Formats

A couple of linker script commands deal with object file formats.
几个链接器脚本命令处理对象文件格式。

  • OUTPUT_FORMAT(bfdname)
  • OUTPUT_FORMAT(default, big, little)

The OUTPUT_FORMAT command names the BFD format to use for the output file. Using OUTPUT_FORMAT(bfdname) is exactly like using ‘–oformat bfdname’ on the command line. If both are used, the command line option takes precedence.
OUTPUT_FORMAT 命令命名输出文件要使用的 BFD 格式。使用 OUTPUT_FORMAT(bfdname)与在命令行中使用“--oformat bfdname ”完全相同。如果同时使用这两个选项,则以命令行选项为准。

You can use OUTPUT_FORMAT with three arguments to use different formats based on the ‘-EB’ and ‘-EL’ command-line options. This permits the linker script to set the output format based on the desired endianness.
您可以使用带有三个参数的 OUTPUT_FORMAT,根据“-EB ”“-EL ”命令行选项使用不同的格式。这允许链接器脚本根据所需的字节序设置输出格式。
If neither ‘-EB’ nor ‘-EL’ are used, then the output format will be the first argument, default. If ‘-EB’ is used, the output format will be the second argument, big. If ‘-EL’ is used, the output format will be the third argument, little.
如果既未使用“-EB ”也未使用“-EL”,则输出格式将是第一个参数,即默认值。如果使用“-EB”,输出格式将是第二个参数 big。如果使用“-EL”,输出格式将是第三个参数,即 little
For example, the default linker script for the MIPS ELF target uses this command:
例如,MIPS ELF 目标机的默认链接器脚本就使用了该命令:

OUTPUT_FORMAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)

This says that the default format for the output file is ‘elf32-bigmips’, but if the user uses the ‘-EL’ command-line option, the output file will be created in the ‘elf32-littlemips’ format.
这表示输出文件的默认格式是 “elf32-bigmips”,但如果用户使用“-EL ”命令行选项,输出文件将以 “elf32-littlemips ”格式创建。

  • TARGET(bfdname)

The TARGET command names the BFD format to use when reading input files. It affects subsequent INPUT and GROUP commands. This command is like using ‘-b bfdname’ on the command line. If the TARGET command is used but OUTPUT_FORMAT is not, then the last TARGET command is also used to set the format for the output file.
TARGET 命令用于命名读取输入文件时使用的 BFD 格式。它会影响后续的 INPUTGROUP 命令。该命令类似于在命令行中使用“-b bfdname”。如果使用了 TARGET 命令,但没有使用 OUTPUT_FORMAT,那么最后一条 TARGET 命令也将用于设置输出文件的格式。

1.4 Assign alias names to memory regions

Alias names can be added to existing memory regions created with the MEMORY Command command. Each name corresponds to at most one memory region.
别名可以添加到使用 MEMORY 命令创建的现有内存区域中。每个名称最多对应一个内存区域。

REGION_ALIAS(alias, region)

The REGION_ALIAS function creates an alias name alias for the memory region region. This allows a flexible mapping of output sections to memory regions. An example follows.
REGION_ALIAS函数为内存区域region创建一个别名alias。这允许灵活地将输出段映射到内存区域。下面是一个例子。
Suppose we have an application for embedded systems which come with various memory storage devices. All have a general purpose, volatile memory RAM that allows code execution or data storage. Some may have a read-only, non-volatile memory ROM that allows code execution and read-only data access. The last variant is a read-only, non-volatile memory ROM2 with read-only data access and no code execution capability. We have four output sections:
假设我们有一个嵌入式系统的应用程序,它配备了各种存储设备。所有设备都有一般用途的易失性内存RAM,允许代码执行或数据存储。一些设备可能具有只读的非易失性内存ROM,允许代码执行和只读数据访问。最后一种变体是一种只读的非易失性内存ROM2,它具有只读数据访问功能,但不允许代码执行。我们有四个输出部分:

  • .text program code;
  • .rodata read-only data;
  • .data read-write initialized data;
  • .bss read-write zero initialized data.

The goal is to provide a linker command file that contains a system independent part defining the output sections and a system dependent part mapping the output sections to the memory regions available on the system. Our embedded systems come with three different memory setups A, B and C:
目标是提供一个链接器命令文件,其中包含一个系统独立部分定义输出段,以及一个系统依赖部分将输出段映射到系统上可用的内存区域。我们的嵌入式系统有三种不同的内存配置A、B和C:

Section	Variant A	Variant B	Variant C
.text	RAM	          ROM	ROM
.rodata	RAM	          ROM	ROM2
.data	RAM	       RAM/ROM	RAM/ROM2
.bss	RAM	          RAM	RAM

The notation RAM/ROM or RAM/ROM2 means that this section is loaded into region ROM or ROM2 respectively. Please note that the load address of the .data section starts in all three variants at the end of the .rodata section.
标记RAM/ROM或RAM/ROM2意味着这一部分分别被加载到ROM或ROM2区域。请注意,.data段的加载地址在所有三种变体中都始于.rodata段的末端。
The base linker script that deals with the output sections follows. It includes the system dependent linkcmds.memory file that describes the memory layout:
处理输出段的基链接脚本如下。它包括描述内存布局的系统依赖的linkcmds.memory文件:

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

Now we need three different linkcmds.memory files to define memory regions and alias names. The content of linkcmds.memory for the three variants A, B and C:
现在我们需要三个不同的linkcmds.memory文件来定义内存区域和别名名称。三个变体A、B和C的linkcmds.memory内容如下:

  • A

Here everything goes into the 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 = 3MRAM : 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 = 2MROM2 : ORIGIN = 0x10000000, LENGTH = 1MRAM : 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段从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);}
}

1.5 Other Linker Script Commands

There are a few other linker scripts commands.
还有一些其他的链接器脚本命令

  • ASSERT(exp, message)

Ensure that exp is non-zero. If it is zero, then exit the linker with an error code, and print message.
确保 exp 不为零。如果为零,则以错误代码退出链接器,并打印信息。

Note that assertions are checked before the final stages of linking take place. This means that expressions involving symbols PROVIDEd inside section definitions will fail if the user has not set values for those symbols. The only exception to this rule is PROVIDEd symbols that just reference dot. Thus an assertion like this:
请注意,断言会在链接的最后阶段之前进行检查。这就意味着,如果用户没有为部分定义中的 PROVIDEd 符号设置值,那么涉及这些符号的表达式就会失败。这一规则的唯一例外是仅引用 dot 的 PROVIDEd 符号。因此,像这样的断言

  .stack :{PROVIDE (__stack = .);PROVIDE (__stack_size = 0x100);ASSERT ((__stack > (_end + __stack_size)), "Error: No room left for the stack");}

will fail if __stack_size is not defined elsewhere. Symbols PROVIDEd outside of section definitions are evaluated earlier, so they can be used inside ASSERTions. Thus:
如果__stack_size在任何地方都没有定义将会失败。在部分定义之外提供的符号会提前被评估,因此可以在 ASSERTions 中使用。

  PROVIDE (__stack_size = 0x100);.stack :{PROVIDE (__stack = .);ASSERT ((__stack > (_end + __stack_size)), "Error: No room left for the stack");}

will work.

  • EXTERN(symbol symbol …)

Force symbol to be entered in the output file as an undefined symbol. Doing this may, for example, trigger linking of additional modules from standard libraries. You may list several symbols for each EXTERN, and you may use EXTERN multiple times. This command has the same effect as the ‘-u’ command-line option.
强制将符号作为未定义符号输入输出文件。例如,这样做可能会触发链接标准库中的其他模块。您可以为每个 EXTERN 列出多个符号,也可以多次使用 EXTERN。该命令与命令行选项“-u ”的效果相同。

  • FORCE_COMMON_ALLOCATION

This command has the same effect as the ‘-d’ command-line option: to make ld assign space to common symbols even if a relocatable output file is specified (‘-r’).
该命令与命令行选项“-d ”的作用相同:即使指定了可重置输出文件(“-r”),ld 也会为常用符号分配空间。

  • INHIBIT_COMMON_ALLOCATION

This command has the same effect as the ‘–no-define-common’ command-line option: to make ld omit the assignment of addresses to common symbols even for a non-relocatable output file.
该命令与“--no-define-common ”命令行选项的作用相同:使 ld 即使在输出文件不可重定位的情况下,也不为常用符号分配地址。

  • FORCE_GROUP_ALLOCATION

This command has the same effect as the ‘–force-group-allocation’ command-line option: to make ld place section group members like normal input sections, and to delete the section groups even if a relocatable output file is specified (‘-r’).
此命令与‘--force-group-allocation’命令行选项具有相同的效果:使ld像处理普通输入段一样放置段组成员,并且即使指定了可重定位输出文件(‘-r’),也会删除段组。

  • INSERT [ AFTER | BEFORE ] output_section

This command is typically used in a script specified by ‘-T’ to augment the default SECTIONS with, for example, overlays. It inserts all prior linker script statements after (or before) output_section, and also causes ‘-T’ to not override the default linker script. The exact insertion point is as for orphan sections. See The Location Counter. The insertion happens after the linker has mapped input sections to output sections. Prior to the insertion, since ‘-T’ scripts are parsed before the default linker script, statements in the ‘-T’ script occur before the default linker script statements in the internal linker representation of the script. In particular, input section assignments will be made to ‘-T’ output sections before those in the default script. Here is an example of how a ‘-T’ script using INSERT might look:
这个命令通常在由‘-T’指定的脚本中使用,以增加默认的SECTIONS,例如,添加覆盖层。它会在输出部分之后(或之前)插入所有先前的链接器脚本语句,并且还会导致‘-T’不覆盖默认的链接器脚本。确切的插入点与孤儿部分相同。链接器在将输入段映射到输出段之后进行插入操作。在插入之前,由于‘-T’脚本在默认链接器脚本之前被解析,因此‘-T’脚本中的语句会在默认链接器脚本的语句之前出现在脚本的内部链接器表示中。特别是,输入段的分配将先于默认脚本中的分配被分配给‘-T’输出段。下面是一个使用INSERT的‘-T’脚本可能看起来的例子:

SECTIONS
{OVERLAY :{.ov1 { ov1*(.text) }.ov2 { ov2*(.text) }}
}
INSERT AFTER .text;
  • NOCROSSREFS(section section …)

This command may be used to tell ld to issue an error about any references among certain output sections.
此命令可用于指示ld在某些输出部分之间存在任何引用时发出错误。
In certain types of programs, particularly on embedded systems when using overlays, when one section is loaded into memory, another section will not be. Any direct references between the two sections would be errors. For example, it would be an error if code in one section called a function defined in the other section.
在某些类型的程序中,特别是在嵌入式系统中使用覆盖技术时,当一个部分被加载到内存中时,另一个部分则不会被加载。两个部分之间的任何直接引用都会是错误的。例如,如果一个部分中的代码调用了在另一个部分中定义的函数,这将是一个错误。
The NOCROSSREFS command takes a list of output section names. If ld detects any cross references between the sections, it reports an error and returns a non-zero exit status. Note that the NOCROSSREFS command uses output section names, not input section names.
NOCROSSREFS命令接受一个输出段名称列表。如果ld检测到这些段之间存在任何交叉引用,它会报告错误并返回一个非零的退出状态。请注意,NOCROSSREFS命令使用的是输出段名称,而不是输入段名称。

  • NOCROSSREFS_TO(tosection fromsection …)

This command may be used to tell ld to issue an error about any references to one section from a list of other sections.
此命令可用于指示ld在从其他节列表中引用一个节时发出错误。
The NOCROSSREFS command is useful when ensuring that two or more output sections are entirely independent but there are situations where a one-way dependency is needed. For example, in a multi-core application there may be shared code that can be called from each core but for safety must never call back.
NOCROSSREFS命令在确保两个或多个输出部分完全独立时非常有用,但在某些情况下需要单向依赖。例如,在多核应用程序中,可能存在可以从每个核心调用的共享代码,但出于安全考虑,它绝不能回调。
The NOCROSSREFS_TO command takes a list of output section names. The first section can not be referenced from any of the other sections. If ld detects any references to the first section from any of the other sections, it reports an error and returns a non-zero exit status. Note that the NOCROSSREFS_TO command uses output section names, not input section names.
NOCROSSREFS_TO命令接受一个输出段名称列表。第一个段不能被其他任何段引用。如果ld检测到任何其他段对第一个段的引用,它会报告一个错误并返回一个非零的退出状态。请注意,NOCROSSREFS_TO命令使用的是输出段名称,而不是输入段名称。

  • OUTPUT_ARCH(bfdarch)

Specify a particular output machine architecture. The argument is one of the names used by the BFD library (see BFD). You can see the architecture of an object file by using the objdump program with the ‘-f’ option.
指定一个特定的输出机器架构。参数是BFD库使用的名称之一(参见 [BFD])。你可以使用带有‘-f’选项的objdump程序查看对象文件的架构。

  • LD_FEATURE(string)

This command may be used to modify ld behavior. If string is "SANE_EXPR" then absolute symbols and numbers in a script are simply treated as numbers everywhere. See The Section of an Expression.
此命令可用于修改ld的行为。如果字符串是"SANE_EXPR",那么脚本中的绝对符号和数字将被简单地视为数字。

2 Assigning Values to Symbols

You may assign a value to a symbol in a linker script. This will define the symbol and place it into the symbol table with a global scope.
你可以在链接器脚本中给一个符号赋值。这将定义该符号,并将其放入具有全局作用域的符号表中。

  • Simple Assignments
  • HIDDEN
  • PROVIDE
  • PROVIDE_HIDDEN
  • Source Code Reference

2.1 Simple Assignments

You may assign to a symbol using any of the C assignment operators:
你可以使用C语言的任何赋值运算符给符号赋值:

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

The first case will define symbol to the value of expression. In the other cases, symbol must already be defined, and the value will be adjusted accordingly.
第一个案例将定义符号为表达式的值。在其他情况下,符号必须已经定义,且值将相应地进行调整。
The special symbol name ‘.’ indicates the location counter. You may only use this within a SECTIONS command.
特殊符号名称‘.’表示位置计数器。你只能在SECTIONS命令中使用它。
The semicolon after expression is required.
表达式后面的分号是必需的。
Expressions are defined below; see Expressions in Linker Scripts.
表达式定义如下;参考Expressions in Linker Scripts
You may write symbol assignments as commands in their own right, or as statements within a SECTIONS command, or as part of an output section description in a SECTIONS command.
你可以将符号赋值作为独立的命令来写,或者作为SECTIONS命令中的语句,或者作为SECTIONS命令中输出部分描述的一部分。
The section of the symbol will be set from the section of the expression; for more information, see The Section of an Expression.
符号的部分将从表达式部分设置;更多信息,请参见[表达式部分]。
Here is an example showing the three different places that symbol assignments may be used:
这里有一个示例,展示了符号赋值可能使用的三个不同位置:

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

In this example, the symbol ‘floating_point’ will be defined as zero. The symbol ‘_etext’ will be defined as the address following the last ‘.text’ input section. The symbol ‘_bdata’ will be defined as the address following the ‘.text’ output section aligned upward to a 4 byte boundary.
在这个例子中,符号‘floating_point’将被定义为零。符号‘_etext’将被定义为最后一个‘.text’输入段之后的地址。符号‘_bdata’将被定义为‘.text’输出段之后的地址,并向上对齐到4字节边界。

2.2 HIDDEN

For ELF targeted ports, define a symbol that will be hidden and won’t be exported. The syntax is HIDDEN(symbol = expression).
对于针对ELF目标端口,定义一个将被隐藏且不会被导出的符号。语法是 HIDDEN(symbol = expression)
Here is the example from Simple Assignments, rewritten to use HIDDEN:
这里是从[简单赋值],重写使用HIDDEN的例子:

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

In this case none of the three symbols will be visible outside this module.
在这种情况下,这三个符号都不会在模块外部可见。

2.3 PROVIDE

In some cases, it is desirable for a linker script to define a symbol only if it is referenced and is not defined by any object included in the link. For example, traditional linkers defined the symbol ‘etext’. However, ANSI C requires that the user be able to use ‘etext’ as a function name without encountering an error. The PROVIDE keyword may be used to define a symbol, such as ‘etext’, only if it is referenced but not defined. The syntax is PROVIDE(symbol = expression).
在某些情况下,链接器脚本定义一个符号是有益的,前提是该符号被引用且在链接过程中没有被任何对象定义。例如,传统的链接器定义了符号‘etext’。然而,ANSI C要求用户能够将‘etext’用作函数名而不遇到错误。可以使用PROVIDE关键字来定义一个符号,如‘etext’,仅当它被引用但未被定义时。语法是PROVIDE(symbol = expression)
Here is an example of using PROVIDE to define ‘etext’:
这里是一个使用PROVIDE定义‘etext’的例子:

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

In this example, if the program defines ‘_etext’ (with a leading underscore), the linker will give a multiple definition diagnostic. If, on the other hand, the program defines ‘etext’ (with no leading underscore), the linker will silently use the definition in the program. If the program references ‘etext’ but does not define it, the linker will use the definition in the linker script.
在本例中,如果程序定义了“_etext”(带下划线),链接器将给出多重定义诊断。另一方面,如果程序定义了 “etext”(不带前导下划线),链接器将默认使用程序中的定义。如果程序引用了 “etext ”但没有定义它,链接器将使用链接器脚本中的定义。
Note - the PROVIDE directive considers a common symbol to be defined, even though such a symbol could be combined with the symbol that the PROVIDE would create. This is particularly important when considering constructor and destructor list symbols such as ‘CTOR_LIST’ as these are often defined as common symbols.
注意 - PROVIDE指令认为一个通用符号已被定义,即使这样的符号可以与PROVIDE将要创建的符号组合。当考虑构造函数和析构函数列表符号,如‘__CTOR_LIST__’时,这一点尤为重要,因为这些符号通常被定义为通用符号。

2.4 PROVIDE_HIDDEN

Similar to PROVIDE. For ELF targeted ports, the symbol will be hidden and won’t be exported.
类似于PROVIDE。对于针对ELF端口,符号将被隐藏且不会被导出。

2.5 Source Code Reference

Accessing a linker script defined variable from source code is not intuitive. In particular a linker script symbol is not equivalent to a variable declaration in a high level language, it is instead a symbol that does not have a value.
从源代码访问链接器脚本定义的变量并不直观。特别是,链接器脚本符号并不等同于高级语言中的变量声明,它实际上是一个没有值的符号。
Before going further, it is important to note that compilers often transform names in the source code into different names when they are stored in the symbol table. For example, Fortran compilers commonly prepend or append an underscore, and C++ performs extensive ‘name mangling’. Therefore there might be a discrepancy between the name of a variable as it is used in source code and the name of the same variable as it is defined in a linker script. For example in C a linker script variable might be referred to as:
在继续之前,重要的是要注意编译器通常会将源代码中的名称转换为不同的名称,当它们存储在符号表中时。例如,Fortran编译器通常会在前面或后面添加一个下划线,而C++会进行广泛的“名称混淆”。因此,源代码中使用的变量名称和链接器脚本中定义的相同变量的名称之间可能存在差异。例如,在C语言中,链接器脚本变量可能被引用为:

  extern int foo;

But in the linker script it might be defined as:
但在链接器脚本中,它可能被定义为:

  _foo = 1000;

In the remaining examples however it is assumed that no name transformation has taken place.
然而,在剩余的例子中,我们假设没有发生名称转换。
When a symbol is declared in a high level language such as C, two things happen. The first is that the compiler reserves enough space in the program’s memory to hold the value of the symbol. The second is that the compiler creates an entry in the program’s symbol table which holds the symbol’s address. ie the symbol table contains the address of the block of memory holding the symbol’s value. So for example the following C declaration, at file scope:
当在如C这样的高级语言中声明一个符号时,会发生两件事。首先,编译器会在程序的内存中保留足够的空间来存储符号的值。其次,编译器会在程序的符号表中创建一个条目,该条目保存了符号的地址。也就是说,符号表包含了存储符号值的内存块的地址。因此,例如以下的C语言声明,在文件作用域中:

  int foo = 1000;

creates an entry called ‘foo’ in the symbol table. This entry holds the address of an ‘int’ sized block of memory where the number 1000 is initially stored.
在符号表中创建一个名为‘foo’的条目。这个条目保存了一个‘int’大小的内存块的地址,其中最初存储了数字1000。
When a program references a symbol the compiler generates code that first accesses the symbol table to find the address of the symbol’s memory block and then code to read the value from that memory block. So:
当程序引用一个符号时,编译器生成的代码首先访问符号表以找到符号内存块的地址,然后生成读取该内存块中值的代码。所以:

  foo = 1;

looks up the symbol ‘foo’ in the symbol table, gets the address associated with this symbol and then writes the value 1 into that address. Whereas:
在符号表中查找符号‘foo’,获取与该符号相关联的地址,然后将值1写入该地址。而:

  int * a = & foo;

looks up the symbol ‘foo’ in the symbol table, gets its address and then copies this address into the block of memory associated with the variable ‘a’.
在符号表中查找符号‘foo’,获取其地址,然后将这个地址复制到与变量‘a’相关联的内存块中。
Linker scripts symbol declarations, by contrast, create an entry in the symbol table but do not assign any memory to them. Thus they are an address without a value. So for example the linker script definition:
链接器脚本符号声明,相比之下,会在符号表中创建一个条目,但不为它们分配任何内存。因此,它们是一个没有值的地址。例如,链接器脚本定义如下:

  foo = 1000;

creates an entry in the symbol table called ‘foo’ which holds the address of memory location 1000, but nothing special is stored at address 1000. This means that you cannot access the value of a linker script defined symbol - it has no value - all you can do is access the address of a linker script defined symbol.
创建一个名为‘foo’的符号表条目,它保存了内存位置1000的地址,但地址1000处没有存储任何特殊内容。这意味着你不能访问链接器脚本定义的符号的值——它没有值——你所能做的只是访问链接器脚本定义的符号的地址。
Hence when you are using a linker script defined symbol in source code you should always take the address of the symbol, and never attempt to use its value. For example suppose you want to copy the contents of a section of memory called .ROM into a section called .FLASH and the linker script contains these declarations:
因此,当你在源代码中使用链接器脚本定义的符号时,你应该总是取该符号的地址,而永远不要尝试使用它的值。例如,假设你想将一个名为.ROM的内存区域的内容复制到一个名为.FLASH的区域,并且链接器脚本包含以下声明:

  start_of_ROM   = .ROM;end_of_ROM     = .ROM + sizeof (.ROM);start_of_FLASH = .FLASH;

Then the C source code to perform the copy would be:
然后执行复制操作的C语言源代码将是:

  extern char start_of_ROM, end_of_ROM, start_of_FLASH;memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);

Note the use of the ‘&’ operators. These are correct. Alternatively the symbols can be treated as the names of vectors or arrays and then the code will again work as expected:
注意‘&’运算符的使用。这些是正确的。或者,这些符号可以被视为向量或数组的名称,然后代码将再次按预期工作:

  extern char start_of_ROM[], end_of_ROM[], start_of_FLASH[];memcpy (start_of_FLASH, start_of_ROM, end_of_ROM - start_of_ROM);

Note how using this method does not require the use of ‘&’ operators.
注意,使用这种方法不需要使用‘&’运算符。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com