• 揭开链接器的面纱(中)


    思考:

    链接器根据什么原则完成具体的链接工作?

    入口函数是可配置的?那么其他的原则是不是也可以配置呢?

    假设是可以配置的,那么必然的存在一个配置文件,在这个文件中可以配置各种各样的原则。这个配置文件就是链接脚本。

    链接脚本里面就写了链接原则(如何链接各个段,如何重定位)。

    上图指定了代码段的起始地址为0x20000000。这就是重定位。

    “.”代表当前位置指针。

    S=. 表示重定位S这个标识符,让S这个标识符位于当前位置指针指代的地址处。(这就是C语言中变量的本质,一段内存的别名,这里S就是一段内存的别名,将这段内存重定位到了0x80000000的地方)

    将.data代码段重定位到0x30000000。

    .bss段没有指明地址,链接器会默认给定一个合法的地址(和平台和链接器有关)。

    实验:

    程序如下:

    链接脚本如下:

     编译运行:

    程序链接成功,但是运行时产生了段错误。因为链接脚本中的text的起始地址不符合linux平台的规范。

    使用objdump -h查看可执行文件信息:

    首先查看没有链接脚本下的情况:

    查看有链接脚本时生成的可执行文件:

    data和text段的起始地址正是我们链接脚本中指定的地址。

    将链接脚本的地址改成符合规范的地址:

     正常运行了。

    修改链接脚本:

    重定位s1这个变量,重新编译:

    继续修改链接脚本:

    s2并没有在源文件中定义,而是在链接脚本中定义的,我们在源文件中直接使用这个变量。

    再次编译运行:

    可以看到正确运行了。链接脚本中定义的变量在源文件中可以使用。

    重定义存储区域:

    MEMORY定义存储器的地址。

    示例:

    数据段放在ram中,代码段在flash中。链接是指定存储区。最终的app.bin烧写进flash,执行时数据段的读写在ram中。这里的ram更多的用于栈、临时变量等。

    入口点:

    实验:

    1 ENTRY(program)
    2 
    3 SECTIONS
    4 {
    5     .text 0x08048400:
    6     {
    7         *(.text)
    8     }
    9 }
    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 
    4 int program()
    5 {
    6     printf("D.T.Software
    ");
    7     
    8     exit(0);
    9 }

    编译运行结果如下:

    objdump -h查看和nm查看:

    可以看到program的地址正好是text段的起始地址。

    链接器默认使用start作为入口函数就是链接脚本在起作用。

    查看默认链接脚本:

    生成的文件内容如下:

    第13行看到了入口函数_start。

    小结:

  • 相关阅读:
    省考失败总结
    Oracle基本介绍及用户的管理2
    Linux 阿里云CentOS7.6 安装 redis6.2.1 及使用客户端工具连接
    阿里云centOS7.6安装配置MySQL8.0
    ORA-01078: failure in processing system parameters LRM-00109: could not open parameter file 解决过程
    Vue SSM搭建一个简单的Demo前后端分离含增删改查(CRUD)、分页、批量功能
    Mybatis (ParameterType) 如何传递多个不同类型的参数
    eclipse的一些常用快捷键
    IntelliJ IDEA常用快捷键总结
    安装vue错误详情解决办法
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9826608.html
Copyright © 2020-2023  润新知