Linux下的lds连接脚本简介(四)

11、 表达式
lds中表达式的文法与C语言的表达式文法一致,表达式的值都是整型,若是ld的运行主机和生成文件的目标机都是32位,则表达式是32位数据,不然是64位数据
如下是一些经常使用的表达式:
_fourk_1 = 4K; /* K、M单位 */
_fourk_2 = 4096; /* 整数 */
_fourk_3 = 0×1000; /* 16 进位 */
_fourk_4 = 01000; /* 8 进位 */
注意:1K=1024 1M=1024*1024
11.一、符号名
没有被引号”"包围的符号,以字母、下划线或’.'开头,可包含字母、下划线、’.'和’-'。当符号名被引号包围时,符号名能够与关键字相同。如,
“SECTION”=9;
“with a space” = “also with a space” + 10;
11.二、定位符号’.'
只在SECTIONS命令内有效,表明一个程序地址空间内的地址。
注意:在链接时, 当定位符用在SECTIONS命令的 输出section描述内 时,它表明的是该section的当前** 偏移**,而不是程序地址空间的绝对地址。固然当程序载入后,符号最后的地址仍是程序地址空间的绝对地址。
示例11.2_1:
SECTIONS
{
output :
{
file1(.text)
. = . + 1000;
file2(.text)
. += 1000;
file3(.text)
} = 0×1234;
}
其中因为对定位符的赋值而产生的空隙由0×1234填充。其余的内容应该容易理解吧。
示例11.2_2:
SECTIONS
{
. = 0×100
.text : {
*(.text)
. = 0×200
}
. = 0×500
.data : {
*(.data)
. += 0×600
}
}
.text section在程序地址空间的开始位置是 0x100
示例11.2_3
文件src\a.c
#include <stdio.h>
int a = 100;
int b=0;
int c=0;
int d=1;
int main()
{
printf( "&a=%p\n", &a );
printf( "&b=%p\n", &b );
printf( "&c=%p\n", &c );
printf( "&d=%p\n", &d );
return 0;
}
文件lds\a.lds
a = 10; /* 全局位置 */
SECTIONS
{
b = 11;
.text :
{
*(.text)
c = .; /* section描述内 */
. = 10000 ;
d = .;
}
_bdata = (. + 3) & ~ 4; /* SECTIONS命令内 */
.data : { *(.data) }
}
在没有使用 a.lds状况下编译
gcc -Wall -o a-without-lds.exe ./src/a.c
运行 ./a-without-lds.exe
结果:
&a=0x601020
&b=0x601038
&c=0x60103c
&d=0x601024
在使用 a.lds状况下编译
gcc -Wall -o a-with-lds.exe ./src/a.c ./lds/a.lds
运行 ./a-with-lds.exe
结果:
&a=0xa
&b=0xb
&c=0x400638
&d=0x402b20
10.三、表达式的操做符
在lds中,表达式的操做符与C语言一致。
优先级 结合顺序 操做符
1 left ! – ~ (1)
2 left * / %
3 left + -
4 left >>  =
5 left &
6 left |
7 left &&
8 left ||
9 right ? :
10 right &= += -= *= /= (2)
(1)表示前缀符, (2)表示赋值符。
10.四、表达式的计算
链接器延迟计算大部分表达式的值。
可是,对待与链接过程紧密相关的表达式,链接器会当即计算表达式,若是不能计算则报错。好比, 对于section的VMA地址、内存区域块的开始地址和大小,与其相关的表达式应该当即被计算。
例子,
SECTIONS
{
.text 9+this_isnt_constant :
{ *(.text) }
}
这个例子中,9+this_isnt_constant表达式的值用于设置.text section的VMA地址,所以须要当即运算,可是因为this_isnt_constant变量的值不肯定,因此此时链接器没法确立表达式的值,此时链接器会报错。
10.五、相对值与绝对值
在输出 section描述内 的表达式,链接器取其 相对值 ,相对与该section的开始位置的偏移
SECTIONS命令内且非输出section描述内 的表达式,链接器取其 绝对值
经过ABSOLUTE关键字能够将相对值转化成绝对值,即在原来值的基础上加上表达式所在section的VMA值。
示例
SECTIONS
{
.data : { *(.data) ;_edata = ABSOLUTE ( . ); }
}
该例子中,_edata符号的值是.data section的末尾位置(绝对值,在程序地址空间内)。
10.六、内建函数
lds中有如下一些内建函数:
ABSOLUTE(EXP) :转换成绝对值
ADDR(SECTION) :返回某section的VMA值。
ALIGN(EXP) :返回定位符’ .'的按照EXP进行对齐后的修调值,对齐后的修调值算法为: (. + EXP – 1) & ~(EXP – 1)
BLOCK(EXP) :如同ALIGN(EXP),为了向前兼容。
DEFINED(SYMBOL) :若是符号SYMBOL在全局符号表内,且被定义了,那么返回1,不然返回0。
示例
SECTIONS { …
.text : {
begin = DEFINED ( begin ) ? begin : . ;
}
}
LOADADDR(SECTION) :返回三SECTION的LMA
MAX(EXP1,EXP2) :返回大者
MIN(EXP1,EXP2) :返回小者
NEXT(EXP) :返回下一个能被使用的地址,该地址是 EXP的倍数,相似于ALIGN(EXP)。除非使用了 MEMORY命令定义了一些非连续的内存块,不然NEXT(EXP)与ALIGH(EXP)必定相同。
SIZEOF(SECTION) :返回SECTION的大小。当SECTION没有被分配时,即此时SECTION的大小还不能肯定时,链接器会报错。
SIZEOF_HEADERS :返回输出文件头部的字节数。这些信息出如今输出文件的开始处。当设置第一个段的开始地址时,你可使用这个数字。若是你选择了加速分页,当产生一个ELF输出文件时,若是连接器脚本使用SIZEOF_HEADERS内建函数,链接器必须在它
算出全部段地址和长度以前计算程序头部的数值。若是链接器后来发现它须要附加程序头,它将报告一个“not enough room for
program headers”错误。为了不这样的错误,你必须避免使用SIZEOF_HEADERS函数,或者你必须修改你的链接器脚本去避免强制
链接器去使用附加程序头,或者你必须使用PHDRS命令去定义你本身的程序头
12、 暗含的链接脚本
输入文件能够是目标文件,也能够是链接脚本,此时的链接脚本被称为 暗含的链接脚本
若是链接器不认识某个输入文件,那么该文件被看成链接脚本被解析。更进一步,若是发现它的格式又不是链接脚本的格式,那么链接器报错。
一个暗含的链接脚本不会替换默认的链接脚本,仅仅是增长新的链接而已。
通常来讲,暗含的链接脚本符号分配命令,或INPUT、GROUP、VERSION命令。
在链接命令行中,每一个输入文件的顺序都被固定好了,暗含的链接脚本在链接命令行内占住一个位置,这个位置决定了由该链接脚本指定的输入文件在链接过程当中的顺序
典型的暗含的链接脚本是libc.so文件,在GNU/linux内通常存在/usr/lib目录下。
相关文章
相关标签/搜索