1.前言

本章继续讲述简单脚本命令的后半部分

2.Assigning Values to Symbols

你可以给一个符号(symbol)赋值,它会把这些定义的符号放入全局符号表(symbols table)中

2.1 Assigning Values to Symbols

可以使用下面的C操作为一个符号指定值:

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

注:[1]第一条语句为symbol赋值,其它情况symbol必需提前定义。

[2]特别的符号名:"."代表位置计数符,只能在SECTIONS命令中使用

[3]赋值语句后面必需跟一个;

[4]可以把符号赋值作为一个命令写在它的右侧;也可以作为声明写在SECTIONS命令里面;或者作为SECTIONS命令中输出section的一部分

如下示例显示了赋值语句位于不同的位置:

floating_point = ;
SECTIONS
{
.text :
{ The GNU linker
*(.text)
_etext = .;
}
_bdata = (. + ) & ~ ;
.data : { *(.data) }
}

在这个例子中,‘floating_point’符合被定义为0。‘_etext’符号被定义为‘.text’输入段最后的地址。‘_bata’符号被定义为‘.text’输出段最后按4字节对齐的地址

2.2 PROVIDE

很多情况下,脚本中定义的符号任何对象只能对其引用而不能定义它,比如传统链接器定义的'etext'符号。

然而,ANSI C要求用户使用‘etext’符号作为函数名而不能报错,在程序仅仅是引用某个符号而非定义时,RPOVIDE关键字可以定义一个符号,比如‘etext’,语法是PROVIDE(symbol = expression)

下面是一个‘etext’使用的例子:

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

在这个例子中,如果程序定义‘_etext’(带有前导下划线),链接器会报很多重定义错误。

另一方面,如果程序定义‘etext’(没有前导下划线),那么链接器会默默地使用程序中的定义,如果程序中只是引用了‘etext’而没有定义它,链接器则使用脚本中的定义

2.3 PROVIDE_HIDDEN

类似PROVIDE的用法。对于ELF目标文件,定义的符号会被隐藏不会被导出

补充:如果你查看链接后的文件的符号表,会发现它的符号绑定信息是LOCAL,即内部可见的

2.4 Source Code Reference

从源代码来访问链接脚本中定义的变量其实并不直观,脚本中的符号和高级语言中定义的变量不能等同,它是一个符号而不是一个值

在进一步讨论之前,需要注意的是当源代码中的符号名字被放入符号表(symbol table)中时,编译器通常会把它们进行转换。

举例来说,Fortran语言编译器通常会加前导或后接一个下划线,C++编译器会进行扩展的‘name mangling’。

因此在源代码中的使用的变量和在链接脚本中定义的变量是可能有差异的。举例来说,C语言中引用脚本中的变量像这样:

extern int foo;  

但是在链接脚本中它被定义为这样:

_foo = ; 

不过,在下面的例子中我们假设没有名称转换

当一个符号被声明,比如用C语言,那么会有两件事情发生,第一件事情是编译器会保留一块内存空间来存储这个符号的值,

第二件事情是编译器会在符号表中创建一个符号并存储好该符号的地址,符号表中包含的是存储该符号的值的地址,比如在文件中这样一个C语言的声明:

int foo = ;

会做如下两件事情:

(1)在内存中留出4字节空间,存储1000

(2)在符号表中创建一个‘foo’的符号,符号的地址为整数型数字1000存储在内存中的地址

当一个程序要引用一个符号时,编译器首先会生成一段去符号表中找到该符号内存块地址的代码,然后在生成一段读取内存块值的代码,比如:

foo = ;

去符号表中查询‘foo’符号的地址值,然后往这个地址里写值1,然而:

int * a = & foo; 

去符号表中查询‘foo’符号的地址值,然后将地址直接拷贝到变量‘a’的内存块里面

对比一下链接脚本中的符号声明,它会在符号表中创建一个符号,但是不会给它分配任何内存,所以它们仅仅是一个地址没有值,比如脚本中这样定义:

foo = ;  

在符号表中创建一个‘foo’的符号,然后存储它的地址值为1000,但地址1000指向的存储位置没有任何意义。

这就意味着你不能访问链接脚本中定义的符号的值(它没有值),你唯一能做的就是访问符号的地址

注:foo并不是一个变量,它只是一个值,并不需要在内存中留出一段空间来保存它;
在C语言中,符号表中会有一个名为foo的项,这个项目中的值(地址值)是1000;
注意,这个1000并没有实际存在的内存

因此,当你在源代码中使用一个链接脚本定义的符号时,你应该使用它的地址,而不去尝试使用它的值。

举例,假设你想拷贝一个叫.ROM段的内容到.FLASH段中,链接脚本这样声明的:

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

你的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);  
 

注意,使用‘&’操作也是完全正确的,使用取址符号&去得到它在符号表中的值

Linker Scripts3--简单的链接脚本命令2-Assigning Values to Symbols的更多相关文章

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

    1.前言 这个部分我们描述了简单的链接脚本命令 2.设置entry point 程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数 ...

  2. Linux链接脚本学习--lds

    一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制 ...

  3. Linux链接脚本学习--lds(转)

    Linux链接脚本学习--lds 一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 ...

  4. arm链接脚本

    一. 为什么需要链接脚本 1.1. 从源码到可执行程序(主要有三个步骤:预编译.编译.链接) 1.1.1. 预编译 a. 预编译器执行.譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的. ...

  5. win7 cmd终端连接android手机运行adb shell脚本命令

    win7 cmd终端连接android手机运行adb shell脚本命令 (2013-03-22 20:13:57) 转载▼ 标签: android it shell 连接 linux 分类: 嵌入式 ...

  6. 链接脚本(Linker Script)用法解析(二) clear_table & copy_table

    可执行文件中的.bss段和.data段分别存放未赋初值的全局变量和已赋初值的全局变量,两者的特点分别为: (1).bss段:①无初值,所以不占ROM空间:②运行时存储于RAM:③默认初值为0 (2). ...

  7. GNU linker script,ld script,GNU链接脚本

    https://blog.csdn.net/itxiebo/article/details/50937412 https://blog.csdn.net/itxiebo/article/details ...

  8. 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY

    1.MEMORY关键字用于描述一个MCU ROM和RAM的内存地址分布(Memory Map),MEMORY中所做的内存描述主要用于SECTIONS中LMA和VMA的定义. 2.SECTIONS关键字 ...

  9. 链接脚本(Linker Script)应用实例(一)使用copy table将函数载入到RAM中运行

    将函数载入到RAM中运行需要以下三个步骤: (1)用编译器命令#pragma section "<section name>" <user functions&g ...

随机推荐

  1. CentOS 7 的安装

    CentOS 7的安装 --------------------------- 安装前的准备: 1.去官网或是去网上下载好CentOS 7的镜像文件 下载主页: https://www.centos. ...

  2. 2017-12-15python全栈9期第二天第七节之练习题

    #!/user/bin/python# -*- coding:utf-8 -*-print(6 or 2 > 1)print(3 or 2 >1 )print(0 or 5 <4)p ...

  3. Windows/Linux用户态监控进程启动事件方法

    catalogue . windows wmi监控进程启动 . linux netlink监控进程启动 1. windows wmi监控进程启动 from threading import Threa ...

  4. MySql笔记二:命令简介

    从笔记二开始讲解一些简单的命令,这些我在SQL Server里面都讲过了,什么主键,约束啥的数据库这些都是相通的,所以MySql这里,不讲,粗略过一遍. 使用命令框登录MySql mysql -u r ...

  5. 使用 python -m SimpleHTTPServer 快速搭建http服务

    摘要: 在 Linux 服务器上或安装了 Python 的机器上,可以使用 nohup python -m SimpleHTTPServer [port] & 快速搭建一个http服务. 在 ...

  6. std::rotate使用

    1. 进行元素范围上的左旋转 first - 原范围的起始 n_first - 应出现在旋转后范围起始的元素 last - 原范围的结尾 原来:1 2 3 左旋转后(起始元素是2) : 2 3 1

  7. 复杂sql查询语句

    视图也叫虚表 1.表中保存实际数据,视图保存从表中取出数据所使用的SELECT语句,视图也是一张表,之间区别是是否保存实际数据. 2.使用视图可以完成跨多表查询数据.可以将常用SELECT语句做成视图 ...

  8. 设置 Visual Studio IIS Express 站点局域网访问

    Ø  Visual Stuido 的 IIS Express运行一个网站时,默认地址是这样的:http://localhost:23167/Cache/Three,其中 localhost 表示本机, ...

  9. 什么是CMD

    cmd是command的缩写.命令提示符是在操作系统中,提示进行命令输入的一种工作提示符.在不同的操作系统环境下,命令提示符各不相同. 在windows环境下,命令行程序为cmd.exe,是一个32位 ...

  10. Weex Ui - Weex Conf 2018 干货分享

    本文是2018年 Weex Conf 中议题<Weex + Ui>的内容文档整理,主要给大家介绍飞猪 Weex 技术体系从无到有的过程,包括 Weex Ui 组件库的开发和发展,重点分享在 ...