zoukankan      html  css  js  c++  java
  • u-boot移植(四)---修改前工作:代码流程分析3---代码重定位

    一、重定位  

      1.以前版本的重定位

        

      2.新版本

        

        我们的程序不只涉及一个变量和函数,我们若想访问程序里面的地址,则必须使用SDRAM处的新地址,即我们的程序里面的变量和函数必须修改地址。我们要修改地址,则必须知道程序的地址,就需要在链接的时候加上PIE选项:

        

        加上PIE选项后,链接时候的地址就会生成,然后存储在段里面,如下段(u-boot.lds):

        

        然后我们根据这些地址的信息来修改代码,程序就可以复制到SDRAM的任何地方去。

     二、代码流程 

      start.S中执行到了 bl _main,跳转到_main,_main函数入口在crt0.S (archarmlib) 中。

      1.crt0.S  

     1 ENTRY(_main)
     2 
     3 /*
     4  * Set up initial C runtime environment and call board_init_f(0).
     5  * 初始化C运行环境并且调用 board_init_f(0) 函数
     6  */
     7 
     8  /*
     9   * 初始化栈地址
    10   */
    11     /* Generic-asm-offsets.h (includegenerated)
    12      * #define GENERATED_GBL_DATA_SIZE 192
    13      * JZ2440.h(includeconfig)
    14      * #define PHYS_SDRAM_1        0x30000000
    15      * #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
    16      * #define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE)
    17      * 
    18      * CONFIG_SYS_INIT_SP_ADDR = 0x30000000 + 0x1000 - 192(0xc0) = 0x30000f40
    19      */
    20     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)        /* 设置CFIG_SYS_INIT_SP_ADDR定义的地址,include/configs/jz2440.h中定义 */
    21 
    22     /* sp 的8字节对齐 */
    23     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
    24 
    25     mov    r0, sp                    /* r0 = sp */
    26     bl    board_init_f_mem        /*跳转到 board_init_f_mem 执行*/
    27     mov    sp, r0                    
    28 
    29     mov    r0, #0
    30     bl    board_init_f            /* 调用单板的初始化函数,跳转到 borad_init_f 处执行 */

      执行到 board_init_f 处,则跳转到Board_f.c (common) 中去执行。

      2.baord_init_f

     1 /*
     2  * 单板的初始化函数
     3  */
     4 void board_init_f(ulong boot_flags)
     5 {
     6     gd->flags = boot_flags;
     7     gd->have_console = 0;
     8 
     9     if (initcall_run_list(init_sequence_f))
    10         hang();
    11 
    12 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 
    13         !defined(CONFIG_EFI_APP)
    14     /* NOTREACHED - jump_to_copy() does not return */
    15     hang();
    16 #endif
    17 }

      在其中最重要的函数则是 initcall_run_list(init_sequence_f) ,init_sequence_f 执行单板的各种初始化任务,如下:

      1 static init_fnc_t init_sequence_f[] = {
      2     //gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
      3     //CONFIG_SYS_MONITOR_BASE = _start = 0
      4     //设置gd->mon_len为编译出来的u-boot.bin+bss段的大小
      5     setup_mon_len,    
      6     initf_malloc,
      7     initf_console_record,
      8     //这个函数应该是留给移植人员使用的,里面什么都没做,而且被__weak修饰,
      9     //所以我们可以在别的地方重新定义这个函数来取代它
     10     arch_cpu_init,        /* basic arch cpu dependent setup:CPU初始化*/
     11     initf_dm,
     12     arch_cpu_init_dm,    //同上
     13     mark_bootstage,        /* need timer, go after init dm */
     14 #if defined(CONFIG_BOARD_EARLY_INIT_F)
     15     /* 初始化CPU时钟和各种IO(待修改) */
     16     board_early_init_f,
     17 #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || 
     18         defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || 
     19         defined(CONFIG_SPARC)
     20     /* 初始化定时器 */
     21     timer_init,        /* 初始化定时器 */ 
     22 #endif
     23     env_init,        /* 初始化环境变量 */ 
     24     init_baud_rate,        /* 初始化波特率为: 115200 */
     25     serial_init,        /* 设置串口通讯 */
     26     console_init_f,        /* stage 1 init of console */
     27     // 打印版本信息,你可以修改include/version.h中的CONFIG_IDENT_STRING选项,
     28     // 加入自己的身份信息 
     29     display_options,    /* say that we are here */
     30     //打印bss段信息及text_base, 需要 #define DEBUG
     31     display_text_info,    /* show debugging info if required */
     32     print_cpuinfo,        /* 打印CPUID和时钟频率 */
     33     INIT_FUNC_WATCHDOG_INIT
     34         INIT_FUNC_WATCHDOG_RESET
     35     announce_dram_init,    //输出"DRAM: " 然后在下面进行SDRAM参数设置
     36     /* TODO: unify all these dram functions? */
     37 #if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || 
     38         defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
     39     dram_init,        /* 在smdk2440.c中定义,配置SDRAM大小,可根据实际进行修改 */
     40 #endif
     41     INIT_FUNC_WATCHDOG_RESET
     42     INIT_FUNC_WATCHDOG_RESET
     43     /*
     44      * Now that we have DRAM mapped and working, we can
     45      * relocate the code and continue running from DRAM.
     46      *
     47      * Reserve memory at end of RAM for (top down in that order):
     48      *  - area that won't get touched by U-Boot and Linux (optional)
     49      *  - kernel log buffer
     50      *  - protected RAM
     51      *  - LCD framebuffer
     52      *  - monitor code
     53      *  - board info struct
     54      */
     55     setup_dest_addr,    //将gd->relocaddr、gd->ram_top指向SDRAM最顶端           
     56     reserve_round_4k,    //gd->relocaddr 4K对齐
     57 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && 
     58         defined(CONFIG_ARM)
     59     //gd->arch.tlb_size = PGTABLE_SIZE; 预留16kb的MMU页表
     60     //gd->relocaddr -= gd->arch.tlb_size;
     61     //gd->relocaddr &= ~(0x10000 - 1); 64kb对齐
     62     //gd->arch.tlb_addr = gd->relocaddr;
     63     reserve_mmu,
     64 #endif
     65 #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && 
     66         !defined(CONFIG_ARM) && !defined(CONFIG_X86) && 
     67         !defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
     68     reserve_video,
     69 #endif
     70 #if !defined(CONFIG_BLACKFIN)
     71     //gd->relocaddr -= gd->mon_len;    一开始设置的u-boot.bin + bss段长度
     72     //gd->relocaddr &= ~(4096 - 1);    4k对齐,这是最终重定位地址
     73     //gd->start_addr_sp = gd->relocaddr;  设置重定位后的栈指针
     74     reserve_uboot,
     75 #endif
     76 #ifndef CONFIG_SPL_BUILD
     77     //gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; 
     78     //预留4MB MALLOC内存池
     79     reserve_malloc,
     80     //gd->start_addr_sp -= sizeof(bd_t);  预留空间给重定位后的gd_t->bd
     81     //gd->bd = (bd_t *)gd->start_addr_sp; 指定重定位bd地址
     82     //memset(gd->bd, '', sizeof(bd_t)); 清零
     83     reserve_board,
     84 #endif
     85     //gd->bd->bi_arch_number = CONFIG_MACH_TYPE; 
     86     //对于S3C2440来说就是MACH_TYPE_S3C2440 (arch/arm/include/asm/mach-types.h)
     87     setup_machine,
     88     reserve_global_data,
     89     reserve_fdt,
     90     reserve_arch,
     91     //gd->start_addr_sp -= 16;   栈指针16字节对齐
     92     //gd->start_addr_sp &= ~0xf;
     93     reserve_stacks, 
     94     //gd->bd->bi_dram[i].start = addr;   设置sdram地址和大小
     95     //gd->bd->bi_dram[i].size = size;
     96     setup_dram_config,
     97     show_dram_config,//打印SDRAM大小,与上面的announce_dram_init相对应
     98     display_new_sp,
     99     INIT_FUNC_WATCHDOG_RESET
    100     reloc_fdt,
    101     //gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; 计算重定位偏移地址
    102     //memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
    103     //将原来的gd复制到重定位后的gd地址上去
    104     setup_reloc,
    105 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
    106     /* 重定位代码 */
    107     jump_to_copy,
    108 #endif
    109     NULL,
    110

       3.relocate_code

      jump_to_copy中调用重定位代码relocate_code:C语言调用汇编代码,relocate_code 定义在 relocate.S (archarmlib) 。

      relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);    

      内存分布图如下:

      

      gd->start_addr_sp所在位置也看的出来了。gd->start_addr_sp 代码(内存分布代码):

      

      1 Jz2440.h (includeconfigs)    
      2 #define PHYS_FLASH_1        0x00000000 /* Flash Bank #0 */
      3 #define CONFIG_SYS_FLASH_BASE    PHYS_FLASH_1
      4 #define CONFIG_SYS_MONITOR_BASE    CONFIG_SYS_FLASH_BASE
      5 static int setup_mon_len(void)
      6 {
      7     /* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
      8     gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
      9     return 0;
     10 }
     11 
     12 Jz2440.h (includeconfigs)    
     13 #define PHYS_SDRAM_1_SIZE    0x04000000 /* 64 MB */
     14 
     15 int dram_init(void)
     16 {
     17     /* dram_init must store complete ramsize in gd->ram_size */
     18     gd->ram_size = PHYS_SDRAM_1_SIZE;
     19     return 0;
     20 }
     21 
     22 Jz2440.h (includeconfigs)
     23 #define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */
     24 #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
     25 
     26 static int setup_dest_addr(void)
     27 {
     28     gd->ram_size = board_reserve_ram_top(gd->ram_size);    //64M ram_size
     29 
     30 #ifdef CONFIG_SYS_SDRAM_BASE
     31     gd->ram_top = CONFIG_SYS_SDRAM_BASE;    //gd->ram_top = 0x30000000
     32 #endif
     33     gd->ram_top += get_effective_memsize();    //gd->ramtop = 0x30000000 + 64M
     34     gd->ram_top = board_get_usable_ram_top(gd->mon_len);//gd->ram_top值不变
     35     gd->relocaddr = gd->ram_top;//gd->relocaddr = 0x30000000 + 64M
     36     return 0;
     37 }
     38 
     39 static int reserve_round_4k(void)    //gd->relocaddr 4K对齐
     40 {
     41     gd->relocaddr &= ~(4096 - 1);    
     42     return 0;
     43 }
     44 
     45 static int reserve_mmu(void)
     46 {
     47     /* reserve TLB table */
     48     gd->arch.tlb_size = PGTABLE_SIZE;    //预留16kb的MMU页表
     49     gd->relocaddr -= gd->arch.tlb_size; //gd->relocaddr = gd->relocaddr - 16K = 0x33ffc000
     50 
     51     /* round down to next 64 kB limit */
     52     gd->relocaddr &= ~(0x10000 - 1);    //64kb对齐    gd->relocaddr = 0x33ff0000
     53 
     54     gd->arch.tlb_addr = gd->relocaddr;    //gd->arch.tlb_addr = 0x33ff0000
     55     debug("TLB table from %08lx to %08lx
    ", gd->arch.tlb_addr,
     56           gd->arch.tlb_addr + gd->arch.tlb_size);
     57     return 0;
     58 }
     59 
     60 
     61 static int reserve_uboot(void)
     62 {
     63     /*
     64      * reserve memory for U-Boot code, data & bss
     65      * round down to next 4 kB limit
     66      */
     67     gd->relocaddr -= gd->mon_len;    // 一开始设置的u-boot.bin + bss段长度 
     68                                     //gd->relocaddr=gd->relocaddr-4kb=0x33fef000
     69     gd->relocaddr &= ~(4096 - 1);    // 4k对齐,这是最终重定位地址 0x33fef000
     70 
     71     gd->start_addr_sp = gd->relocaddr;    //设置重定位后的栈指针gd->start_addr_sp=0x33fef000
     72 
     73     return 0;
     74 }
     75 
     76 Jz2440.h (includeconfigs)    
     77 #define CONFIG_SYS_MALLOC_LEN    (4 * 1024 * 1024)    //4M 0x400000    4194304
     78 
     79 Common.h (include)
     80 #define    TOTAL_MALLOC_LEN    CONFIG_SYS_MALLOC_LEN
     81 
     82 static int reserve_malloc(void)
     83 {    //gd->start_addr_sp = gd->start_addr_sp - 4 * 1024 * 1024 =0x33bef000
     84     gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; //预留4MB MALLOC内存池 
     85     return 0;
     86 }
     87 
     88 static int reserve_board(void)
     89 {
     90     if (!gd->bd) {
     91         gd->start_addr_sp -= sizeof(bd_t);    //预留空间给重定位后的gd_t->bd
     92         gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));    //指定重定位bd地址
     93         memset(gd->bd, '', sizeof(bd_t));                    //清零
     94     }
     95     return 0;
     96 }
     97 
     98 static int reserve_global_data(void)
     99 {
    100     gd->start_addr_sp -= sizeof(gd_t);
    101     gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
    102     return 0;
    103 }
    104 
    105 static int reserve_stacks(void)
    106 {
    107     /* make stack pointer 16-byte aligned */
    108     gd->start_addr_sp -= 16;    //栈指针16字节对齐
    109     gd->start_addr_sp &= ~0xf;
    110 
    111     return arch_reserve_stacks();
    112 }
    113 
    114 Stack.c (archarmlib)    
    115 int arch_reserve_stacks(void)
    116 {
    117     /* setup stack pointer for exceptions */
    118     gd->irq_sp = gd->start_addr_sp;
    119 
    120 # if !defined(CONFIG_ARM64)
    121     /* leave 3 words for abort-stack, plus 1 for alignment */
    122     gd->start_addr_sp -= 16;
    123 # endif
    124     return 0;
    125 }

      relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);中的三个参数也已经清楚。gd->relocaddr=0x33fef000 

      crt0.S (archarmlib) 

     1 #if ! defined(CONFIG_SPL_BUILD)
     2     /*
     3      * 这一段代码是将board_init_f中设置好的start_addr_sp地址值赋给栈指针,使其指向重定位后的栈顶
     4      * 8字节对齐后,将r9设为新的GD地址( gd地址=bd地址-sizeof(gd_t))
     5      */
     6     ldr    sp, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp */
     7     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
     8     ldr    r9, [r9, #GD_BD]        /* r9 = gd->bd */
     9     sub    r9, r9, #GD_SIZE        /* new GD is below bd */
    10 
    11     adr    lr, here                 /*设置返回地址为下面的here,重定位到sdram后返回here运行*/
    12     ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off 取重定位地址偏移值 */
    13     add    lr, lr, r0                /*返回地址加偏移地址等于重定位后在sdram中的here地址*/
    14     ldr    r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr 传入参数为重定位地址 */
    15     b    relocate_code                /*跳到arch/arm/lib/relocate.S中执行*/
    16 here:        /*返回后跳到sdram中运行    */    
    17     bl    relocate_vectors
    18 /* Set up final (full) environment */
    19     bl    c_runtime_cpu_setup    /* we still call old routine here */
    20 
    21     ldr    r0, =__bss_start    /* this is auto-relocated! */
    22     ldr    r1, =__bss_end        /* this is auto-relocated! */
    23     mov    r2, #0x00000000        /* prepare zero to clear BSS */
    24 
    25 clbss_l:cmp    r0, r1            /* while not at end of BSS */
    26 
    27     strlo    r2, [r0]        /* clear 32-bit BSS word */
    28     addlo    r0, r0, #4        /* move to next */
    29     blo    clbss_l
    30 #endif

       relocate.S

     1 ENTRY(relocate_code)
     2     ldr    r1, =__image_copy_start    /* r1 <- SRC &__image_copy_start 
     3                                  * 这是u-boot.bin起始链接地址,
     4                                  * 定义在u-boot.lds中 (编译后在顶层目录生成)
     5                                  * 原文件是arch/arm/cpu/u-boot.lds
     6                                  */
     7     subs    r4, r0, r1        /* r4 <- relocation offset 
     8                              * r0是crt0.S中传入的重定位地址
     9                              * 这里是算出偏移值 
    10                              */
    11     beq    relocate_done        /* skip relocation 
    12                              * 如果r4为0,则认为重定位已完成
    13                              */
    14     ldr    r2, =__image_copy_end    /* r2 <- SRC &__image_copy_end 
    15                                  * 同第一条指令,在u-boot.lds中定义
    16                                  */
    17                                  
    18 /* r1是源地址__image_copy_start,r0是目的地址relocaddr,
    19  * size = __image_copy_start - __image_copy_end 
    20  */
    21 copy_loop:
    22     ldmia    r1!, {r10-r11}        /* 从 r1 中拷贝数据到 r10、r11 寄存器中 */
    23     stmia    r0!, {r10-r11}        /* 把r10、r11 寄存器的数据存到r0寄存器中 */
    24     cmp    r1, r2            /* 比较 r1 和 r2 ,若 r0 < r2 则继续拷贝*/
    25     blo    copy_loop
    26 
    27     /*
    28      * fix .rel.dyn relocations          定义了"-PIE"选项就会执行下面这段代码
    29      * 目的是为了让位置相关的资源(代码、参数、变量)的地址在重定位后仍然能被寻址到,所以让他们加上偏移地址,
    30      * 即等于他们重定位后的真正地址
    31      * 这些 "存放(资源的地址)的地址" 存放在.rel.dyn这个段中,每个参数后面都会跟着一个起标志作用的参数,
    32         * 如果这个标志参数为23,即0x17,则表示这个 (资源的地址) 是位置相关的,需要加上重定位偏移值
    33      * 这一段代码首先让.rel.dyn这个段中的存放的地址值加上偏移值,使其在sdram中取出(资源的地址)
    34      * 然后再让这些(资源的地址)加上偏移值,存回rel.dyn中存放这些地址的地址中,
    35      */
    36 
    37     ldr    r2, =__rel_dyn_start    /* r2 <- SRC &__rel_dyn_start */
    38     ldr    r3, =__rel_dyn_end    /* r3 <- SRC &__rel_dyn_end */
    39 fixloop:
    40     /* r0为"存放(资源的地址)的地址",这个地址里存放的是需要用到的(资源的地址),r1为标志值 */
    41     ldmia    r2!, {r0-r1}        /* (r0,r1) <- (SRC location,fixup) */
    42     and    r1, r1, #0xff    /* r1 = r1 & 0xff r1取低八位*/
    43     cmp    r1, #23            /* relative fixup?  r1 是否等于23(0x17)*/
    44     bne    fixnext            /* 若相等跳转到 fixnext执行 */
    45 
    46     /* relative fix: increase location by offset */
    47     /* r4存放的是重定位偏移值,r0这个地址存放的是位置相关的(资源的地址),
    48      * r4+r0即为重定位后的"存放(资源的地址)的地址",
    49      */
    50     add    r0, r0, r4        /* r0 = r0 + r4 */
    51     ldr    r1, [r0]        /* r1 = r0的地址?在sdram中取出还未修改的(资源的地址)*/
    52     add    r1, r1, r4        /* r1 = r1 + r4 加上偏移值*/
    53     str    r1, [r0]        /* 存回去 */
    54 fixnext:                /* 跳到下一个继续检测是否需要重定位 */
    55     cmp    r2, r3
    56     blo    fixloop            /* 跳转到 fixloop 继续执行 */
    57 
    58 relocate_done:
    59 #ifdef __ARM_ARCH_4__
    60     /* ARM920T用的汇编指令集是ARMv4,所以使用这条返回指令,返回重定位后的here标志 */
    61     mov    pc, lr
    62 #else
    63     bx    lr
    64 #endif
    65 
    66 ENDPROC(relocate_code)

     

    参考:http://blog.csdn.net/funkunho/article/details/52474373

      

  • 相关阅读:
    POJ3189 Steady Cow Assignment(二分图多重匹配)
    POJ2112 Optimal Milking(二分图多重匹配)
    POJ2289 Jamie's Contact Groups(二分图多重匹配)
    安装jhipster
    AngularJS版本下载
    业务平台技术架构一些注意事项
    反向数据库表
    近期需要关注的内容
    一些不太常见但很有用的java类
    文件复制
  • 原文地址:https://www.cnblogs.com/kele-dad/p/6938865.html
Copyright © 2011-2022 走看看