• 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址


    驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址

    最近重新看了乾龙_Heron的《ARM 上电启动及 Uboot 代码分析》(下简称《代码分析》)

    文档里写道:

     

    Uboot.lds文件中起始地址是0x00,但是config.mk中的TEXT_BASE是0x57e00000,但是生成的uboot反汇编文件中,为什
    么start.s的第一条指令地址也是0x57e00000?不应该是0x00么?因为start.s的加载地址和运行地址都是0x00啊!? 答:Uboot.lds的0x00: 跟在SECTION后面的第一条 location counter,总是默认初始化为0。config.mk中的TEXT_BASE就是ROM在CPU上的地址,也就是说,
    不同的CPU已经规定了不同的ROM地址

     

    先来看看笔者这篇文章标题的关键字:链接地址 加载地址 

    《代码分析》中也给了答案

     连接地址<==>运行地址
    
     存储地址<==>加载地址
    
    (1)对于有操作系统时,运行地址与加载地址不同,在加载过程中装载器就把段加载到它应该去的连接地址处(也就是生成该段时的运行地址)
    
    (2)对于uboot,运行地址与加载地址不同时,需要它自己(例如前4k代码)将自己加载到运行地址处执行。
    

      

    那么什么是链接脚本地址,来看一段链接脚本的内容:

    SECTIONS
    
    {
    
           . = 0x08048000;
    
           tinytext : { *(.test) *(.rodata)}
    
           . = 0x08088000;
    
           tinydata : {*(.data)}
    
    }
    

    用过脚本代码的人知道,.test段和.rodata将紧跟在0x08048000地址后面,这种在链接脚本上假定的地址,称为链接脚本地址(未知是否有更专业的名称,暂用此名)。为什么我要说是假定呢?因为在ld命令中可以覆盖lds脚本设定段的地址,就是《代码分析》中出现的.lds的地址被.mk文件(.mk文件,其实就是makefile文件)中的TEXT_BASE修改了。

    上面已经提到,链接地址就是代码运行地址,运行地址我们可以通过对执行文件的反汇编得到;那我们来做一个实验,看lds文件中的地址是不是代码链接地址,

    下面用gcc -c 和 ld 来编译链接代码(参考程序员的自我修养 p125)

    c代码
    
    int aa=8;
    
    void main(void)
    
    {
    
           int i=0;
    
           aa = i;
    
    }
    
     
    
    .lds 代码
    
    ENTRY(main)
    SECTIONS
    
    {
           . = 0x08048000;
    
           tinytext : { *(.test) *(.rodata)}
    
           . = 0x08088000;
    
           tinydata : {*(.data)}
    }
    
    然后
    
    $ gcc -c -fno-builtin ttext.c
    $ ld -static -T test_Ttext.lds -o ttext ttext.o
    $ objdump -S ttext
    
    ttext:     file format elf64-x86-64
    Disassembly of section .text:
    0000000008048000 <main>:
     8048000:    55                          push   %rbp
     8048001:    48 89 e5               mov    %rsp,%rbp
     8048004:    c7 45 fc 00 00 00 00 movl   $0x0,-0x4(%rbp)
     804800b:    8b 45 fc                mov    -0x4(%rbp),%eax
     804800e:    89 05 ec ff 03 00           mov    %eax,0x3ffec(%rip)        # 8088000 <aa>
     8048014:    5d                          pop    %rbp
     8048015:    c3                   retq  
    
    我们看看符号表:
    $ objdump -t ttext
    ttext:     file format elf64-x86-64
    SYMBOL TABLE:
    0000000008048000 l    d  .text 0000000000000000 .text
    0000000008048018 l    d  .eh_frame      0000000000000000 .eh_frame
    0000000008088000 l    d  tinydata   0000000000000000 tinydata
    0000000000000000 l    d  .comment       0000000000000000 .comment
    0000000000000000 l    df *ABS*     0000000000000000 ttext.c
    0000000000000000 l    df *ABS*     0000000000000000
    0000000008088000 g     O tinydata  0000000000000004 aa
    0000000008048000 g     F .text 0000000000000016 main
    

      

    从上面这个实验,我们可以看出来,链接脚本地址和链接地址居然是一样的!

    那么,到底.mk文件里面做了什么,使TEXT_BASE成为了代码的地址?关键一点就是.mk在ld 中加了一个选项 -Ttext,这个选项使得.text地址的链接地址为此选项的参数TEXT_BASE。

    我们来看一下是不是:

     

    之前我们的ld没有加选项-Ttext,现在加上试试
    
    $ ld -static -T test_Ttext.lds -o ttext ttext.o -Ttext 0xff
    
    $ objdump -S ttext
    ttext:     file format elf64-x86-64
    Disassembly of section .text:
    00000000000000ff <main>:
      ff:       55                          push   %rbp
     100:     48 89 e5               mov    %rsp,%rbp
     103:     c7 45 fc 00 00 00 00 movl   $0x0,-0x4(%rbp)
     10a:     8b 45 fc                mov    -0x4(%rbp),%eax
     10d:     89 05 ed 7e 08 08          mov    %eax,0x8087eed(%rip)        # 8088000 <aa>
     113:     5d                          pop    %rbp
     114:     c3                   retq  
    
    我们可以发现,.text的地址变成了0xff 跟我们输入的参数一样
    再看看符号表
    
    $ objdump -t ttext
    
     
    
    ttext:     file format elf64-x86-64
    
     
    
    SYMBOL TABLE:
    
    0000000008088000 l    d  tinydata   0000000000000000 tinydata
    
    00000000000000ff l    d  .text   0000000000000000 .text
    
    0000000008088008 l    d  .eh_frame      0000000000000000 .eh_frame
    
    0000000000000000 l    d  .comment       0000000000000000 .comment
    
    0000000000000000 l    df *ABS*     0000000000000000 ttext.c
    
    0000000000000000 l    df *ABS*     0000000000000000
    
    0000000008088000 g     O tinydata  0000000000000004 aa
    
    00000000000000ff g     F .text   0000000000000016 main
    

      

    .text 段地址的确是变了,但是没有影响 data段

     在这样的试验结果下,可以确定的说,-Ttext选项会改变.text段的地址,这就是TEXT_BASE成为Uboot的代码段链接地址的原因

     


     

    文章讨论Uboot代码段链接地址的问题到这里就结束了,下面将测试-Ttext 选项对.data是否会产生影响;

     

    上面的实验将.data放在另一段,如果将.data放在tinytext中,是否会随着-Ttext改变.text的时候同时被改变呢?

     

    $ cat test_Ttext.lds
    
    ENTRY(main)
    
    SECTIONS
    {
    
           . = 0x08048000;
    
           tinytext : { *(.test)*(.data) *(.rodata)}
    }
    
    $ ld -static -T test_Ttext.lds -o ttext ttext.o -Ttext 0xff
    $ objdump -S ttext
    ttext:     file format elf64-x86-64
    Disassembly of section .text:
    00000000000000ff <main>:
      ff:       55                          push   %rbp
     100:     48 89 e5               mov    %rsp,%rbp
     103:     c7 45 fc 00 00 00 00 movl   $0x0,-0x4(%rbp)
     10a:     8b 45 fc                mov    -0x4(%rbp),%eax
     10d:     89 05 ed 7e 04 08          mov    %eax,0x8047eed(%rip)        # 8048000 <aa>
     113:     5d                          pop    %rbp
     114:     c3                    retq  
    
    咦,怎么aa变成了tinytext的地址呢?
    我们看看符号表
    $ objdump -t ttext
    ttext:     file format elf64-x86-64
    SYMBOL TABLE:
    0000000008048000 l    d  tinytext   0000000000000000 tinytext
    00000000000000ff l    d  .text   0000000000000000 .text
    0000000008048008 l    d  .eh_frame      0000000000000000 .eh_frame
    0000000000000000 l    d  .comment       0000000000000000 .comment
    0000000000000000 l    df *ABS*     0000000000000000 ttext.c
    0000000000000000 l    df *ABS*     0000000000000000
    0000000008048000 g     O tinytext  0000000000000004 aa
    00000000000000ff g     F .text   0000000000000016 main
    

    发现.text改变了,但是aa(.data)没有随.text而变,而是紧跟着tinytext的首地址

     

    一个疑问,在开发过程中,可能板子的RAM地址比较低/高,那么我们要怎么改data和rodata字段使其符合内存的范围限制呢?

     

  • 相关阅读:
    插入排序java代码
    选择排序java代码
    break语句的作用
    while和do-while的区别
    if-else-if-else与switch的区别
    Java中基本类型的转换规则
    如何让计算机最高效的算出2乘以8?
    |和||的作用和区别
    &和&&的作用和区别
    i++和++i的作用和区别
  • 原文地址:https://www.cnblogs.com/simonlin/p/6259533.html
Copyright © 2020-2023  润新知