u-boot移植(四)---修改前工作:代碼流程分析3---代碼重定位


一、重定位  

  1.以前版本的重定位

    

  2.新版本

    

    我們的程序不只涉及一個變量和函數,我們若想訪問程序里面的地址,則必須使用SDRAM處的新地址,即我們的程序里面的變量和函數必須修改地址。我們要修改地址,則必須知道程序的地址,就需要在鏈接的時候加上PIE選項:

    

    加上PIE選項后,鏈接時候的地址就會生成,然后存儲在段里面,如下段(u-boot.lds):

    

    然后我們根據這些地址的信息來修改代碼,程序就可以復制到SDRAM的任何地方去。

 二、代碼流程 

  start.S中執行到了 bl _main,跳轉到_main,_main函數入口在crt0.S (arch\arm\lib) 中。

  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 (include\generated)
12      * #define GENERATED_GBL_DATA_SIZE 192
13      * JZ2440.h(include\config)
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, '\0', 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 (arch\arm\lib) 。

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

  內存分布圖如下:

  

 

  gd->start_addr_sp所在位置也看的出來了。gd->start_addr_sp 代碼(內存分布代碼):

  

 1 Jz2440.h (include\configs)  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 (include\configs)  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 (include\configs)  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\n", 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 (include\configs)  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, '\0', 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 (arch\arm\lib) 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 (arch\arm\lib) 

 

 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

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM