Linker Scripts3--简单的链接脚本命令2-Assigning Values to Symbols
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的更多相关文章
- Linker Scripts3--简单的链接脚本命令1
1.前言 这个部分我们描述了简单的链接脚本命令 2.设置entry point 程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数 ...
- Linux链接脚本学习--lds
一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制 ...
- Linux链接脚本学习--lds(转)
Linux链接脚本学习--lds 一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 ...
- arm链接脚本
一. 为什么需要链接脚本 1.1. 从源码到可执行程序(主要有三个步骤:预编译.编译.链接) 1.1.1. 预编译 a. 预编译器执行.譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的. ...
- win7 cmd终端连接android手机运行adb shell脚本命令
win7 cmd终端连接android手机运行adb shell脚本命令 (2013-03-22 20:13:57) 转载▼ 标签: android it shell 连接 linux 分类: 嵌入式 ...
- 链接脚本(Linker Script)用法解析(二) clear_table & copy_table
可执行文件中的.bss段和.data段分别存放未赋初值的全局变量和已赋初值的全局变量,两者的特点分别为: (1).bss段:①无初值,所以不占ROM空间:②运行时存储于RAM:③默认初值为0 (2). ...
- GNU linker script,ld script,GNU链接脚本
https://blog.csdn.net/itxiebo/article/details/50937412 https://blog.csdn.net/itxiebo/article/details ...
- 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY
1.MEMORY关键字用于描述一个MCU ROM和RAM的内存地址分布(Memory Map),MEMORY中所做的内存描述主要用于SECTIONS中LMA和VMA的定义. 2.SECTIONS关键字 ...
- 链接脚本(Linker Script)应用实例(一)使用copy table将函数载入到RAM中运行
将函数载入到RAM中运行需要以下三个步骤: (1)用编译器命令#pragma section "<section name>" <user functions&g ...
随机推荐
- NorFlash 学习
目录 NorFlash 学习 NOR/NAND Flash的差别 引脚接口 命令 参数识别(CFI) 写数据 程序设计 程序优化 其他设计点 title: NorFlash 学习 tags: ARM ...
- 删除mysql数据库中表分区数据
删除mysql数据库中表分区数据 zabbix 几个大表创建了分区,由于磁盘空间告警,特将3月前的分区给予删除. 1.查看表的数据占用磁盘空间情况 2.登录mysql中,查看表的分区情况. 3.删除表 ...
- 网络编程基础【day09】:socket接收大数据(五)
本节内容 1.概述 2.socket接收大数据 3.中文字符的坑 一.概述 上篇博客写到了,就是说当服务器发送至客户端的数据,大于客户端设置的数据,则就会把数据服务端发过来的数据剩余数据存在IO缓冲区 ...
- Java面试题全集(上)转载
Java面试题全集(上) 2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是 ...
- PL/SQL Developer连接本地Oracle 11g 64位数据库和快捷键设置
1.登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ...
- 1、JPA-HelloWorld
/** * JPA 是 hibernate 的一个抽象(就像JDBC和JDBC驱动的关系) * JPA 本质上是一种 ORM 规范,不是 ORM 框架,因为 JPA 并未提供 ORM 实现,只是制订了 ...
- java用流的方式加载图片
前端: <img ng-show="photo" class="vertical_b" id="photoImg" src=" ...
- mssql的 for xml path 与 mysql中的group_concat类似MSSQL For xml Path
/****** Script for SelectTopNRows command from SSMS ******/ SELECT D_ID,[D_Name] as Name FROM [LFBMP ...
- JavaScript中调皮的undefined
JavaScript中调皮的undefined 在JavaScript中undefined只是一个标识符,不是关键字,这个很不靠谱的标识符还不能像其他符号一样随意使用,一方面是需要它的原始值保持不变, ...
- Kudu系列-基础
Apache Kudu 支持Insert/Update/Delete 等写操作(Kudu 随机写效率也很高, 实测对一个窄表做全字段update, 其速度达到了Insert速度的88%, 而verti ...