uboot2011-06 之 make 初体验(四)

来源:互联网 发布:工资软件下载 编辑:程序博客网 时间:2024/05/16 15:23

执行make是总是那么酣畅淋漓,有一种说不出的快感。

好,执行make ,注意在makefile中添加

ARCH=armCROSS_COMPILE=arm-linux-

make 会有很多的错误,一般是提醒你没有定义一些东西,那么这些东西在哪里定义,大部分在之前提到的那个carl210.h文件中定义。

其实这样直接执行make是不合适的,因为肯定会有错,就是看看是否能不能正常的编译。

分析程序我们一般都找main函数,main函数是一个入口,其实在mian函数之前有一段汇编的代码,初始化好堆栈才能使用C的,那现在就找那个函数的入口地址。

三星的210是armv7的,而我们也配置了CPU的类型等等。所以到armv7下找一个文件名是start.s的文件,好开始分析这个文件,在看这个文件之前还有提到在之前的makefile分析中提到的LDSCRIPT的这个连接脚本最后指向了LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds

首先了解uboot的链接脚本board/my2410/u-boot.lds,它定义了目标程序各部分的链接顺序。

/* * January 2004 - Changed to support H4 device * Copyright (c) 2004-2008 Texas Instruments * * (C) Copyright 2002 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">/*指定输出可执行文件为ELF格式,32为,ARM小端*/</span>OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">/*指定输出可执行文件为ARM平台*/</span>OUTPUT_ARCH(arm)
<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">/*起始代码段为 _start*/</span>ENTRY(_start)
SECTIONS{
<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">  /* 指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置*/</span>. = 0x00000000;. = ALIGN(4);  //4字节对齐.text:      //text字段{arch/arm/cpu/armv7/start.o(.text)  //主人公第一阶段入口文件*(.text)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : {*(.data)}. = ALIGN(4); //当前位置4字节对齐. = .;__u_boot_cmd_start = .;    .u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__image_copy_end = .;.rel.dyn : {__rel_dyn_start = .;*(.rel*)__rel_dyn_end = .;}.dynsym : {__dynsym_start = .;*(.dynsym)}_end = .;.bss __rel_dyn_start (OVERLAY) : {__bss_start = .;*(.bss) . = ALIGN(4);__bss_end__ = .;}/DISCARD/ : { *(.dynstr*) }/DISCARD/ : { *(.dynamic*) }/DISCARD/ : { *(.plt*) }/DISCARD/ : { *(.interp*) }/DISCARD/ : { *(.gnu*) }}

其实这个文件的作用是告诉我们入口的文件是arch/arm/cpu/armv7/start.S,还有是各个字段存放的位置。

1.text字段

2.rodata

3.data字段

4.uboot的一些命令

5..rel.dyn 字段

6..dynsym字段

7.bss字段

好开始看arch/arm/cpu/armv7/start.S文件

.globl _start_start: bresetldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irqldrpc, _fiq
1.声明一个全局的标号_start

2.b reset 跳转到reset处

reset:/* * set the cpu to SVC32 mode */mrsr0, cpsrbicr0, r0, #0x1forrr0, r0, #0xd3msrcpsr,r0

设置CPU为svc32模式

#if defined(CONFIG_OMAP34XX)/* Copy vectors to mask ROM indirect addr */adrr0, _start@ r0 <- current position of codeaddr0, r0, #4@ skip reset vectormovr2, #64@ r2 <- size to copyaddr2, r0, r2@ r2 <- source end addressmovr1, #SRAM_OFFSET0@ build vect addrmovr3, #SRAM_OFFSET1addr1, r1, r3movr3, #SRAM_OFFSET2addr1, r1, r3
想想也不会定义CONFIG_OMAP34XX的,我们的是210。

3.ldr pc, _undefined_instruction 跳转到_undefined_instruction

以_undefined_instruction为例,就是,此处分配了一个word=32bit=4字节的地址空间,里面存放的值是undefined_instruction
而此处_undefined_instruction也就是该地址空间的地址了。用C语言来表达就是:
_undefined_instruction = &undefined_instruction
或*_undefined_instruction = undefined_instruction
在后面的代码,我们可以看到,undefined_instruction也是一个标号,即一个地址值,对应着就是在发生“未定义指令”的时候,系统所要去执行的代码。(其他几个对应的“软件中断”,“预取指错误”,“数据错误”,“未定义”,“(普通)中断”,“快速中断”,也是同样的做法,跳转到对应的位置执行对应的代码。)

所以:

ldr pc, 标号1......标号1:.word 标号2......标号2:......(具体要执行的代码)                

的意思就是,将地址为标号1中内容载入到pc,而地址为标号1中的内容,正好装的是标号2。

用C语言表达其实很简单:

PC = *(标号1) = 标号2

对PC赋值,即是实现代码跳转,所以整个这段汇编代码的意思就是:

跳转到标号2的位置,执行对应的代码。

.global _end_vect_end_vect:.balignl 16,0xdeadbeef

声明一个_end_vect的全局标号,然后就是在以后的代码中都要16字节对齐,不足的地方用deadbeef补齐

.globl _TEXT_BASE_TEXT_BASE:.wordCONFIG_SYS_TEXT_BASE
声明一个全局的标号_TEXT_BASE,而_TEXT_BASE被定义为CONFIG_SYS_TEXT_BASE,那么这个CONFIG_SYS_TEXT_BASE一般在carl210.h中定义的。

#ifdef CONFIG_TEGRA2/* * Tegra2 uses 2 separate CPUs - the AVP (ARM7TDMI) and the CPU (dual A9s). * U-Boot runs on the AVP first, setting things up for the CPU (PLLs, * muxes, clocks, clamps, etc.). Then the AVP halts, and expects the CPU * to pick up its reset vector, which points here. */.globl _armboot_start_armboot_start:.word _start#endif
那显然我们不是Tegra2

/* * These are defined in the board-specific linker script. */.globl _bss_start_ofs_bss_start_ofs:.word __bss_start - _start.globl _bss_end_ofs_bss_end_ofs:.word __bss_end__ - _start.globl _end_ofs_end_ofs:.word _end - _start
在armv7下的u-boot.lds中有__bss_start等的定义,其实上面的这些代码得出的结果就是要算出相对于起始地址的偏移量,并声明这些为全局的标号,以便其他的文件能够使用这些个标号或者是变量。

#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word0x0badc0de/* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de#endif/* IRQ stack memory (calculated at run-time) + 8 bytes */.globl IRQ_STACK_START_INIRQ_STACK_START_IN:.word0x0badc0de
这个是当定义使用IRQ时会定义IRQ_STACK_START,FIQ_STACK_START,我们不用。

以上这些都是类似于变量的定义以及初始化,其实真正的代码是在reset中,上面有所提到。

当arm进入svc32 mode,继续看

#if defined(CONFIG_OMAP34XX)/* Copy vectors to mask ROM indirect addr */adrr0, _start@ r0 <- current position of codeaddr0, r0, #4@ skip reset vectormovr2, #64@ r2 <- size to copyaddr2, r0, r2@ r2 <- source end addressmovr1, #SRAM_OFFSET0@ build vect addrmovr3, #SRAM_OFFSET1addr1, r1, r3movr3, #SRAM_OFFSET2addr1, r1, r3
显然不会定义,我们的是210。

next:ldmiar0!, {r3 - r10}@ copy from source address [r0]stmiar1!, {r3 - r10}@ copy to   target address [r1]cmpr0, r2@ until source end address [r2]bnenext@ loop until equal */#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT)/* No need to copy/exec the clock code - DPLL adjust already done * in NAND/oneNAND Boot. */blcpy_clk_code@ put dpll adjust code behind vectors#endif /* NAND Boot */#endif/* the mask ROM code should have PLL and others stable */
都不会执行的。

#ifndef CONFIG_SKIP_LOWLEVEL_INITblcpu_init_crit#endif

CONFIG_SKIP_LOWLEVEL_INIT 是一般不会定义的,所以bl cpu_init_crit ,即跳转到cpu_init_crit

cpu_init_crit:/* * Invalidate L1 I/D */movr0, #0@ set up for MCRmcrp15, 0, r0, c8, c7, 0@ invalidate TLBsmcrp15, 0, r0, c7, c5, 0@ invalidate icache/* * disable MMU stuff and caches */mrcp15, 0, r0, c1, c0, 0bicr0, r0, #0x00002000@ clear bits 13 (--V-)bicr0, r0, #0x00000007@ clear bits 2:0 (-CAM)orrr0, r0, #0x00000002@ set bit 1 (--A-) Alignorrr0, r0, #0x00000800@ set bit 12 (Z---) BTBmcrp15, 0, r0, c1, c0, 0

看英文注释就知道什么意思,具体代码是什么意思,看《arm体系结构与编程》

/* * Jump to board specific initialization... * The Mask ROM will have already initialized * basic memory. Go here to bump up clock rate and handle * wake up conditions. */movip, lr@ persevere link reg across callbllowlevel_init@ go setup pll,mux,memorymovlr, ip@ restore linkmovpc, lr@ back to my caller
看英文注释,是跳转的到和板级相关的带吗中,初始化pll,memory等等,bllowlevel_init 会跳转到这个lowlevel_init的地方。下节讲关于这个函数在哪里定义。



0 0
原创粉丝点击