ld链接器脚本(三)

给符号赋值

可以给脚本中的符号赋予一个值。这样会定义一个符号,并且将这个符号放入全局符号表中,并且具有全局符号作用域。

简单赋值

可以使用c中的任何赋值运算符,进行赋值:

symbol = expression ;
symbol += expression ;
symbol -= expression ;
symbol *= expression ;
symbol /= expression ;
symbol <<= expression ;
symbol >>= expression ;
symbol &= expression ;
symbol |= expression ;
  1. 第一个定义一个符号,然后赋值。

  2. 而后续的赋值之前,这个符号必须已经定义,则值会根据相应的表达式进行相应的调整。

  3. 特殊符号’.'表示,位置计数器。你可能只会在SECTION命令中使用它。

  4. 表达式后面的分号是必须的。

表达式的定义见后续部分。
您可以将符号赋值作为命令单独编写,也可以作为SECTIONS命令中的语句编写,或者作为SECTIONS命令中输出节描述的一部分编写。
下面是一个示例,显示了可以使用符号赋值的三个不同位置:

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

上面例子中,floating_point被定义为0.

_etext定义为.text section之后的地址。

_bdata将被定义为.text输出sectoin之后的地址,并且4字节对齐。

PROVIDE

某些情况下,我们希望,链接器提供符号的引用,而不提供任何定义。例如:传统的链接器定义了一个etext的符号。但是,ANSI C要求用户能够使用’etext’作为函数名而不会遇到错误。PROVIDE关键字可用来定义符号,例如etext,但是只会有对他的引用,不会有对他的定义。语法如下:

PROVIDE(symbol = expression)

下面是PROVIDE定义etext的一个例子:

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

在这个例子中,如果程序定义了_etext,链接器将报一个多个定义的错误。另外,如果,程序定义了etext,链接器将使用程序中的定义。如果程序没有定义etext,链接器将使用脚本中的定义。

PROVIDE_HIDDEN

跟PROVIDE相似。对于ELF目标端口,这个符号将被隐藏并且不会被导出。

源代码引用

从源代码中访问脚本中定义的变量不太直观。尤其是链接器脚本符号不等同于高级语言中的变量声明,而是一个没有值的符号。

在进一步讨论之前,应该注意到,编译器将源码中的名字放进符号表时,名字会有不同。例如,Fortran编译器常常在前面或者后面加上一个下划线。c++编译器执行一个扩展的名称修改。

因此,源代码中使用的变量名与链接器脚本中定义的变量名之间可能存在差异

例如,在c中,链接器脚本变量可以被称为:

extern int foo;

但是在链接器脚本中,它可能被定义成如下:

_foo = 1000;

但是,在其余的例子中,假设没有发生名称转换.

当用高级语言(如c)声明符号时,会发生两件事 .首先,编译器在程序内存中保留足够的空间来保存符号的值。第二个是编译器在程序的符号表中创建一个包含符号地址的条目。即符号表包含保存符号值的内存块的地址。

例如下面的c声明:

int foo = 1000;

在符号表中创建名为“foo”的项。此项保存“int”大小的内存块的地址,其中数字1000最初存储在该内存块中

当程序引用一个符号时,编译器生成一段代码:这段代码首先访问符号表以找到该符号的内存块的地址,从该块内存中读取该值。因此:

foo = 1;

在符号表中寻找foo项,然后获取相应的地址,然后向这个地址中写入1.反之:

int * a = & foo;

符号表中查找foo,获取到它的地址,然后复制这个地址到一个内存中,这个内存的符号为a

相反,链接器脚本符号声明在符号表中创建一个条目,但不为它们分配任何内存。

因此,它们是一个没有值的地址。例如,链接器脚本定义:

foo = 1000;

在符号表中创建一个名为“foo”的条目,该条目保存内存位置1000的地址.这意味着您无法访问链接器脚本定义的符号的值(它没有值)您只能访问链接器脚本定义的符号的地址

因此,当您在源代码中使用链接器脚本定义的符号时,您应该始终获取该符号的地址,而不要试图使用其值。

例如,假设要将名为.rom的内存的内容复制到名为.flash内存中,并且链接器脚本包含以下声明:

start_of_ROM = .ROM;
end_of_ROM = .ROM + sizeof (.ROM) - 1;
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); 

注意&运算符的用法。这是正确的

下面将介绍SECTIONS命令的细节

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要书写一个连接Oracle并执行一段代码的Shell脚本,需要以下步骤: 1. 安装并配置Oracle客户端:首先,需要安装适当版本的Oracle客户端。安装完成后,设置正确的环境变量(例如ORACLE_HOME和LD_LIBRARY_PATH),以确保Shell脚本能够找到Oracle客户端的相关文件。 2. 编写Shell脚本:使用文本编辑创建一个新的Shell脚本文件,例如`connect_oracle.sh`。 3. 在Shell脚本中编写连接Oracle的命令:在Shell脚本文件中,可以使用`sqlplus`命令连接到Oracle数据库。使用下面的命令行模板,将其添加到Shell脚本文件中: ```bash sqlplus username/password@hostname:port/service_name <<EOF [Oracle PL/SQL code] EOF ``` 其中,`username`是Oracle数据库的用户名,`password`是对应的密码,`hostname`是Oracle数据库所在的主机名,`port`是连接Oracle数据库的端口号,`service_name`是要连接的Oracle服务名。在`<<EOF`和`EOF`之间,可以编写具体的Oracle PL/SQL代码。 4. 编写要执行的Oracle PL/SQL代码:在连接Oracle的命令之后,可以编写要在数据库中执行的具体代码。根据实际需要,可以执行各种数据库操作,如查询、更新、创建表等。 5. 保存并运行Shell脚本:保存Shell脚本文件,并确保该文件具有可执行权限。使用终端进入Shell脚本所在的目录,并运行以下命令执行脚本: ```bash ./connect_oracle.sh ``` 执行过程中,Shell脚本将连接到Oracle数据库,并执行预先编写的PL/SQL代码。执行结果将在终端显示。 需要注意的是,以上的步骤中需要根据实际情况进行相应的配置和编写代码。确保Oracle客户端正常安装和配置,以及Shell脚本中的用户名、密码、主机名、端口号和服务名正确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值