看了网上大神写的bootload,弄个小笔记
1、内联汇编编程
带有C/C++表达式的内联汇编格式为:
asm volatile(“InSTructiON List” : Output : Input : Clobber/Modify);
Instruction list是汇编指令序列:
当Instruction list中有多条指令时,可以将多条指令放在一对引号中,用;或\n将它们分开,如过一条指令放一对引号中,可以每条指令一行。
2. __volatile__是GCC 关键字volatile 的宏定义
#define volatile volatile
__volatile__或volatile 是可选的,假如用了它,则是向GCC 声明不答应对该内联汇编优化,否则当 使用了优化选项(-O)进行编译时,GCC 将会根据自己的判定决定是否将这个内联汇编表达式中的指令优化掉。
3. Output 用来指定内联汇编语句的输出
4.Input
Input 域的内容用来指定当前内联汇编语句的输进Input中,格式为形如“constraint”(variable)的列表(逗号分隔)
5.Clobber/Modify
有时候,你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希看GCC在编译时能够将这一点考虑进往。那么你就可以在Clobber/Modify域声明这些寄存器或内存。这种情况一般发生在一个寄存器出现在"Instruction List",但却不是由Input/Output操纵表达式所指定的,也不是在一些Input/Output操纵表达式使用"r"约束时由GCC 为其选择的,同时此寄存器被"Instruction List"中的指令修改,而这个寄存器只是供当前内联汇编临时使用的情况。如果内存有改动就加”memory”
例如:
void CP15_SetTranslationTableBase(int Base)
{
asm volatile (
"mcr p15,0,%0,c2,c0,0\n"
: : "r"(Base):"memory"
);
}
2、S3C2416.lds — 连接脚本,主要在连接过程中指定代码的重定位
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000; --- 编译起始地址
. = ALIGN(4);
.text : --- 代码区
{
_scode = .; --代码区的首地址
./System/s3c2416.o (.text* .rodata*)
./System/LowLevelInit.o (.text* .rodata*)
./System/NandBoot.o (.text* .rodata*)
./System/Coprocessor.o (.text* .rodata*)
./System/Download.o (.text* .rodata*)
*(.text*)
}
. = ALIGN(4);
.rodata : { *(.rodata*) }
. = ALIGN(4); --- 4个字节对齐
.data : --- 数据区
{
_sdata = .;
*(.data*)
_edata = .;
}
_ecode = .;
. = ALIGN(4);
.bss :
{
_sbss = .;
*(.bss*)
*(COMMON*)
_ebss = .;
}
. = ALIGN(4);
.heap (NOLOAD):
{
PROVIDE(end = .);
*(.heap*)
}
. = ALIGN(4);
.stack (NOLOAD):
{
*(.stack*)
}
. = ALIGN(4);
.mem_uninit (NOLOAD):
{
*(.mem_uninit)
}
/* cache off, write buffer off */
. = ALIGN(0x100000);
.mem_ncnb (NOLOAD):
{
_smem_ncnb = .;
*(.mem_ncnb)
_emed_ncnb = .;
}
/* cache off, write buffer on */
. = ALIGN(0x100000);
.mem_ncb (NOLOAD):
{
_smem_ncb = .;
*(.mem_ncb)
_emem_ncb = .;
}
/* cache on, write through */
. = ALIGN(0x100000);
.mem_cnb (NOLOAD):
{
_smem_cnb = .;
*(.mem_cnb)
_emem_cnb = .;
}
}
3、LowLevelInit.S – 实现重要的函数
.text
.arm
.align 2
/************************ 时钟初始化 *****************************/
// Clock Base Address
#define CLOCK_BASE 0x4C000000
#define LOCKCON0_OFS 0x00
#define LOCKCON1_OFS 0x04
#define MPLLCON_OFS 0x10
#define EPLLCON_OFS 0x18
#define CLKSRC_OFS 0x20
#define CLKDIV0_OFS 0x24
#define CLKDIV1_OFS 0x28
#define CLKDIV2_OFS 0x2C
.globl Clock_Init
Clock_Init: //对时钟进行设置
LDR R0, =CLOCK_BASE
LDR R1, =3600
// MPLL锁定时间大于300us,以外部晶振12M计
STR R1, [R0, #LOCKCON0_OFS]
LDR R1, =3600
// EPLL锁定时间大于300us
STR R1, [R0, #LOCKCON1_OFS]
LDR R1, =(0x1<<0)+(1<<2)+(1<<3)+(0x1<<4)+(0x0<<9)
STR R1, [R0, #CLKDIV0_OFS]
LDR R1, =(0x0<<4)+(0x3<<6)+(0x0<<8)+(0x0<<12)+ \
(0x0<<16)+(0x0<<24)
STR R1, [R0, #CLKDIV1_OFS]
LDR R1, =(0x0<<0)+(0x3<<6)
STR R1, [R0, #CLKDIV2_OFS]
// 设置EPLL输出96M,
LDR R1, =(2<<0)+(1<<8)+(32<<16)+(0x0<<24)+(0x0<<25)
STR R1, [R0, #EPLLCON_OFS]
// 外部晶振12M,设置MPLL输出为533M
LDR R1, =(1<<0)+(3<<5)+(267<<14)+(0x0<<24)+(0x0<<25)
STR R1, [R0, #MPLLCON_OFS]
LDR R1, =(1<<4)+(1<<6)
STR R1, [R0, #CLKSRC_OFS]
BX LR
/********************* 内存初始化 ********************************/
// DRAM controller base address
#define DRAM_BASE 0x48000000
#define BANKCFG_OFS 0x00
#define BANKCON1_OFS 0x04
#define BANKCON2_OFS 0x08
#define BANKCON3_OFS 0x0C
#define REFRESH_OFS 0x10
#define TIMEOUT_OFS 0x14
.globl ERAM_Init
ERAM_Init: //初始化内存
LDR R0, =DRAM_BASE
LDR R1, =(2<<17)+(2<<14)+(2<<11)+(2<<8)+(1<<6)+(1<<4)+(1<<1)+(1<<0)
STR R1, [R0, #BANKCFG_OFS]
// DQS delay 3,Write buffer,Auto pre-charge,bank address 在高位
LDR R1, =(3<<28)+(1<<26)+(1<<8)+(0<<7)+ \
(1<<6)+(0<<5)+(1<<4)
STR R1, [R0, #BANKCON1_OFS]
LDR R1, =(5<<20)+(13<<16)+(3<<4)+(1<<2)+(1<<0)
STR R1, [R0, #BANKCON2_OFS]
// issue a PALL(pre-charge all) command
LDR R1, [R0, #BANKCON1_OFS]
BIC R1, R1, #0x03
ORR R1, R1, #0x01
STR R1, [R0, #BANKCON1_OFS]
// issue an EMRS(extern mode register) command to EMR(2)
LDR R1, [R0, #BANKCON3_OFS]
LDR R2, =0xFFFF0000
BIC R1, R1, R2
ORR R1, R1, #(2<<30)
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
ORR R1, R1, #0x03
STR R1, [R0, #BANKCON1_OFS]
// issue an EMRS(extern mode register) command to EMR(3)
LDR R1, [R0, #BANKCON3_OFS]
LDR R2, =0xFFFF0000
BIC R1, R1, R2
ORR R1, R1, #(3<<30)
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
ORR R1, R1, #0x03
STR R1, [R0, #BANKCON1_OFS]
// issue an EMRS to enable DLL and RDQS, nDQS, ODT disable
LDR R1, =0xFFFF0000
LDR R2, [R0, #BANKCON3_OFS]
BIC R2, R2, R1
LDR R1, =(0x1<<30)+(0<<27)+(1<<26)+ \
(0<<23)+(0<<16)
ORR R1, R1, R2
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
ORR R1, R1, #0x03
STR R1, [R0, #BANKCON1_OFS]
// issue a mode register set command for DLL reset
LDR R1, =0x0000FFFF
LDR R2, [R0, #BANKCON3_OFS]
BIC R2, R2, R1
LDR R1, =(1<<8)+(0<<7)+(3<<4)
ORR R1, R1, R2
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
BIC R1, R1, #0x03
ORR R1, R1, #0x02
STR R1, [R0, #BANKCON1_OFS]
// Issue a PALL(pre-charge all) command
LDR R1, [R0, #BANKCON1_OFS]
BIC R1, R1, #0x03
ORR R1, R1, #0x01
STR R1, [R0, #BANKCON1_OFS]
// Issue 2 or more auto-refresh commands
LDR R1, =0x20
STR R1, [R0, #REFRESH_OFS]
// Issue a MRS command with LOW to A8 to initialize device operation
LDR R1, =0x0000FFFF
LDR R2, [R0, #BANKCON3_OFS]
BIC R2, R2, R1
LDR R1, =(0<<8)+(0<<7)+(3<<4)
ORR R1, R1, R2
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
BIC R1, R1, #0x03
ORR R1, R1, #0x02
STR R1, [R0, #BANKCON1_OFS]
// Wait 200 clock, execute OCD Calibration
LDR R1, =200
0: SUBS R1, R1, #1
BNE 0b
// Issue a EMRS1 command to over OCD Mode Calibration
LDR R1, =0xFFFF0000
LDR R2, [R0, #BANKCON3_OFS]
BIC R2, R2, R1
LDR R1, =(0x1<<30)+(0<<27)+(1<<26)+ \
(0<<23)+(0<<19)+(0<<22)+(0<<18)+ \
(0x0<<17)+(0<<16)
ORR R1, R1, R2
STR R1, [R0, #BANKCON3_OFS]
LDR R1, [R0, #BANKCON1_OFS]
ORR R1, R1, #0x03
STR R1, [R0, #BANKCON1_OFS]
// Refresh period is 7.8us, HCLK=133M, REFCYC=1037
LDR R1, =1037
STR R1, [R0, #REFRESH_OFS]
// issue a Normal mode
LDR R1, [R0, #BANKCON1_OFS]
BIC R1, R1, #0x03
STR R1, [R0, #BANKCON1_OFS]
BX LR
/******************* 复制代码函数*******************************/
// SD/MMC Device Boot Block Assignment
#define eFuseBlockSize 1
#define SdReservedBlockSize 1
#define BL1BlockSize 16
#define SdBL1BlockStart SdReservedBlockSize + \
eFuseBlockSize + BL1BlockSize
#define globalBlockSizeHide 0x40003FFC
#define CopyMovitoMem 0x40004008
// Nand controller base address
#define NFCONF 0x4E000000
// Port c base address
#define GPCCON 0x56000020
// 引出代码搬移函数,以供启动代码调用
.globl CopyCodeToRAM
// 引入Nand启动的初始化函数及Nand读函数
.extern NandBoot_Init
.extern NandBoot_ReadSkipBad
.extern NandBoot_ReadWithoutCheck
.extern CP15_EnableICache
.extern _scode
.extern _ecode
CopyCodeToRAM:
STMFD SP!, {LR} // 将LR入栈,保存返回地址
BL CP15_EnableICache // 开启ICache,加快执行代码
LDR R0, =GPCCON
MOV R1, #0
STR R1, [R0] // 设置GPC为输入引脚
// 判断NFCONF的最高位为1,说明启动设备为Nand
LDR R0, =NFCONF
LDR R1, [R0]
AND R1, R1, #0x80000000
CMP R1, #0x80000000
BNE IROM_Boot //IROM启动
Nand_Boot:
BL NandBoot_Init // Nand初始化
MOV R0, #0
LDR R1, =_scode
LDR R2, =_ecode
SUB R2, R1
BL NandBoot_ReadSkipBad // 调用Nand读函数,检查坏块
// 如果用仿真器下载代码进NAND,Nand boot启动应禁止对NAND检验,应采用下面的函数加载
// BL NandBoot_ReadWithoutCheck // 不检验读取数据,不检查坏块
MOVS R0, R0 // 返回值确定函数成功还是失败
Nand_Boot_Loop:
BNE Nand_Boot_Loop // 返回非0说明拷贝失败
B AfterCopy
IROM_Boot:
LDR R0, =GPCCON
LDR R1, [R0, #4] // GPC data
AND R1, R1, #(7<<5) // GPC5 ~ GPC7
MOV R0, #(0<<5) // IROM MMC boot
CMP R0, R1
BEQ IROM_MMC_Boot //如果是SD卡启动
MOV R0, #(5<<5)
CMP R0, R1
BEQ Nand_Boot // NANDFLASH启动
IROM_Unknow_Boot:
B IROM_Unknow_Boot
IROM_MMC_Boot:
LDR R3, =0
// 到链接执行域内存代码处
LDR R2, =_scode
// 计算代码的大小,以block计,不足512字节的算1个block
// 代码的大小包括Code RO-data RW-data(代码需保存需初始化的RW的初始值)
// 代码保存在ROM中,应从加载域得到ROM的大小,而不是执行域,编译器可能压缩
// 代码段保存在加载域的ROM中
LDR R0, =_ecode
SUB R0, R2
LDR R1, =0x1ff
TST R0, R1 // TST按位与运算,是否不足一个block(512Bytes)
BEQ 0f // 代码恰好block对齐,不用加多一个block
ADD R0, R0, #512
0:
LSR R1, R0, #9 // 逻辑右移,得到代码的block大小(注:9位就是相当于512B)
// 计算代码在SD/MMC卡中的block起启地址
LDR R4, =SdBL1BlockStart
LDR R0, =globalBlockSizeHide //SD卡的总块数
LDR R0, [R0] // SD/MMC的总block块
SUB R0, R4 // 减去保留块及BL1大小
CMP R1, #16 // 代码不足8k,直接BL1处拷贝
BLS ParameterOK // 代码少于16个block跳转
SUB R0, R1 // 再减去代码的大小,代码的block位置
// 用IROM Movi拷贝函数,仅适用于IROM启动,卡访问时钟25M
ParameterOK:
LDR R4, =CopyMovitoMem
LDR R4, [R4]
MOV LR, PC // 准备函数的返回地址
BX R4
MOVS R0, R0 // 返回值确定函数成功还是失败
MMC_SD_Boot_Loop:
BEQ MMC_SD_Boot_Loop // 返回0说明拷贝失败
AfterCopy:
LDMFD SP!, {PC} // 函数返回
4、s3c2416.S —运行时第一个载入的文件
// Clock setting(External Crystal 12M):
// MPLLCLK = 533M, EPLLCLK = 96M
// ARMCLK = 533M, HCLK = 133M
// DDRCLK = 266M, SSMCCLK = 66M, PCLK = 66M
// HSMMC0, HSMMC1 = 24M
// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
#define Mode_USR 0x10
#define Mode_FIQ 0x11
#define Mode_IRQ 0x12
#define Mode_SVC 0x13
#define Mode_ABT 0x17
#define Mode_UND 0x1B
#define Mode_SYS 0x1F
// when I bit is set, IRQ is disabled
#define I_Bit 0x80
// when F bit is set, FIQ is disabled
#define F_Bit 0x40
// Stack Configuration
#define UND_Stack_Size 0x00000020
#define SVC_Stack_Size 0x00000020
#define ABT_Stack_Size 0x00000020
#define FIQ_Stack_Size 0x00000020
#define IRQ_Stack_Size 0x00040000
#define USR_Stack_Size 0x00200000
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + \
ABT_Stack_Size + FIQ_Stack_Size + \
IRQ_Stack_Size)
.section .stack, "aw", %nobits
.align 3
.globl __StackTop
.globl __StackLimit
__StackLimit:
.space (USR_Stack_Size+ISR_Stack_Size)
__StackTop:
// Heap Configuration
#define Heap_Size 0x00400000
.section .heap, "aw", %nobits
.align 3
.globl __HeapBase
.globl __HeapLimit
__HeapBase:
.space Heap_Size
__HeapLimit:
// Watchdog Timer Base Address
#define WT_BASE 0x53000000
// Interrupt Register Base Address
#define INT_BASE 0x4A000000
#define INTMSK1_OFS 0x08
#define INTSUBMSK_OFS 0x1C
#define INTMSK2_OFS 0x48
//---------------------- CODE -------------------------------------------
.text
.arm
.align 2
.globl _start
_start:
B Reset_Handler
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
LDR PC, Notuse_Addr
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
.word 0x55aa55aa // 0x20位置用来判断代码的运行区域
.extern Undef_Handler
.extern SWI_Handler
.extern PAbt_Handler
.extern DAbt_Handler
.extern IRQ_Handler
.extern FIQ_Handler
Reset_Addr:
.word Reset_Handler
Undef_Addr:
.word Undef_Handler
SWI_Addr:
.word SWI_Handler
PAbt_Addr:
.word PAbt_Handler
DAbt_Addr:
.word DAbt_Handler
Notuse_Addr:
.word 0 // Reserved Address
IRQ_Addr:
.word IRQ_SaveContext
FIQ_Addr:
.word FIQ_Handler
IRQ_SaveContext:
// 保存中断上下文,支持中断嵌套
SUB LR, LR, #4 // 计算返回地址
STMFD SP!, {R0-R12, LR} // 所有寄存器压栈保存
MRS R0, SPSR // 保存中断前的CPSR(即现在的SPSR)
STMFD SP!, {R0}
MSR CPSR_cxsf, #(Mode_SYS | I_Bit) // 切换到系统模式
STMFD SP!, {LR} // 压栈系统模式LR
LDR R0, =IRQ_Handler // 系统模式下进行IRQ代码处理
MOV LR, PC // 准备函数的返回地址
BX R0 // 调用中断处理函数
LDMFD SP!, {LR} // 出栈系统模式LR
MSR CPSR_cxsf, #(Mode_IRQ | I_Bit) // 切换到IRQ模式
LDMFD SP!, {R0} // 返回中断前的CPSR
MSR SPSR_cxsf, R0
LDMFD SP!, {R0-R12, PC}^ // ^表同时从spsr恢复给cpsr
.globl Reset_Handler
Reset_Handler:
/***********************************************************************/
// 看门狗关闭
LDR R0, =WT_BASE
LDR R1, =0
STR R1, [R0]
/***********************************************************************/
// 关闭所有外设中断
LDR R0, =INT_BASE
LDR R1, =0xFFFFFFFF
STR R1, [R0, #INTMSK1_OFS]
STR R1, [R0, #INTMSK2_OFS]
STR R1, [R0, #INTSUBMSK_OFS]
/***********************************************************************/
// 判断代码是否已加载进RAM
LDR R0, =_scode
ADD R0, R0, #0x20
LDR R0, [R0]
LDR R1, =0x55aa55aa
CMP R0, R1
BEQ SkipLoadCode
/***********************************************************************/
// 系统时钟设置
.extern Clock_Init
BL Clock_Init
/************************************************************************/
// 外部内存控制设置
.extern ERAM_Init
BL ERAM_Init ;// 外部RAM初始化
LDR SP, =__StackTop
/************************************************************************/
// 拷贝用户代码到RAM
.extern CopyCodeToRAM
BL CopyCodeToRAM
/***********************************************************************/
// 检查是否进入串口下载模式,开机时按住空格键进入串口下载模式
.extern DownloadCheck
BL DownloadCheck
/************************************************************************/
SkipLoadCode:
// MMU初始化
LDR SP, =__StackTop
.extern MMU_Init
BL MMU_Init
/*************************************************************************/
// 堆栈初始化
LDR R0, =__StackTop
// Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #(Mode_UND | I_Bit | F_Bit)
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
// Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #(Mode_ABT | I_Bit | F_Bit)
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
// Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #(Mode_FIQ | I_Bit | F_Bit)
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
// Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #(Mode_IRQ | I_Bit | F_Bit)
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
// Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #(Mode_SVC | I_Bit | F_Bit)
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
// Enter System Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SYS
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
/*************************************************************************/
Clear_bss:
LDR R0, =_sbss
LDR R1, =_ebss
MOV R2, #0
Clear_bss_loop:
CMP R0, R1
BGE Clear_bss_done
STR R2, [R0], #4
B Clear_bss_loop
Clear_bss_done:
/*************************************************************************/
// 绝对地址跳转到c入口
.extern main
LDR R0, =main
BX R0
5接下来看makefile中的配置文件Config.mk
TEXT_BASE=0x30000000 #--连接重定位地址
export TEXT_BASE
CROSS_COMPILE = arm-linux- #编译器的宏定义
export CROSS_COMPILE
DEBUG = n
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP
AFLAGS :=
ARFLAGS := cr
PROJECT := Bootloader #生成的文件名
SUBDIRS := $(TOPDIR)/System $(TOPDIR)/Driver \ #编译的目标文件
$(TOPDIR)/Common $(TOPDIR)/Apps \
CFLAGS := -Wall -Wstrict-prototypes \
-march=armv5t -mfloat-abi=soft -mabi=aapcs-linux -marm \
-ffunction-sections -fdata-sections \
-I $(TOPDIR)/System -I $(TOPDIR)/Driver \
-I $(TOPDIR)/Common -I $(TOPDIR)/Apps \
ifeq ($(DEBUG), y)
CFLAGS += -g
else
CFLAGS += -Os
endif
OBJCFLAGS :=
PLATFORM_LIBS := -L $(TOPDIR)/newlib -lm -lc
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
LDSCRIPT = $(TOPDIR)/System/s3c2416.lds
LDFLAGS := --gc-sections --no-enum-size-warning -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
export PROJECT SUBDIRS LDFLAGS AFLAGS CFLAGS ARFLAGS OBJCFLAGS PLATFORM_LIBS
#下面就是编译的方法
%.o: %.S
@echo "assembling $<..."
@$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.s
@echo "assembling $<..."
@$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
@echo "compiling $<..."
@$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.C
@echo "compiling $<..."
@$(CC) $(CFLAGS) -c -o $@ $<
6顶层的makefile文件
TOPDIR := $(shell pwd) #得到当前的文件目录
export TOPDIR
include config.mk #包含上面的配置文件
FOLDERS := $(notdir $(SUBDIRS)) #将文件名去掉路径:
#例如: ./APPS 经过上面的处理之后就剩下apps
LIBS_TEMP := $(addsuffix .a, $(addprefix /lib, $(FOLDERS))) #前面街上/lib ,后缀加上.a 例如、libApps.a
LIBS := $(join $(SUBDIRS), $(LIBS_TEMP)) #就是字符串拼接例如:./libApps.a
ALL = $(PROJECT).bin $(PROJECT).dis $(PROJECT).srec #这个就是咋们的目标文件
.PHONY: all clean depend $(SUBDIRS)
all: $(ALL)
$(PROJECT).hex: $(PROJECT).elf
@echo "creating hex file $@ from $<..."
@$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(PROJECT).srec: $(PROJECT).elf
@echo "creating srec file $@ from $<..."
@$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(PROJECT).bin: $(PROJECT).elf
@echo "creating bin file $@ from $<..."
@$(OBJCOPY) ${OBJCFLAGS} -S -O binary $< $@
$(PROJECT).dis: $(PROJECT).elf
@echo "creating dis file $@ from $<..."
@$(OBJDUMP) -d $< > $@
$(PROJECT).elf: depend $(SUBDIRS) $(LDSCRIPT)
@echo "Linking..." #生成的全部.a文件全部进行连接
@$(LD) $(LDFLAGS) --start-group $(LIBS) $(PLATFORM_LIBS) --end-group -Map $(PROJECT).map -o $(PROJECT).elf
depend:
@echo "Build target $(PROJECT)"
@for dir in $(SUBDIRS); do $(MAKE) --no-print-directory -C $$dir _depend; done
//对各个文件夹中的文件以此进行编译,并返回到上面all
$(SUBDIRS):
@$(MAKE) -C $@ all
clean: //对文件进行删除的伪指令
rm -f $(PROJECT).elf $(PROJECT).map $(PROJECT).srec $(PROJECT).bin $(PROJECT).dis
@for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
工程的文件结构如下
在这里对Systm里面makefile进行解析,其他文件的套路都是一样的
include $(TOPDIR)/config.mk
SOBJS := s3c2416.o LowLevelInit.o
COBJS := Coprocessor.o NandBoot.o Exception.o Download.o Retarget.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(SOBJS) $(COBJS)
CURDIR := $(shell pwd)
FOLDER := $(notdir $(CURDIR))
LIB := lib$(FOLDER).a
.PHONY: all clean
all: .depend $(LIB)
$(LIB): $(OBJS) #目标就是连接成libxxx.a文件
@$(AR) $(ARFLAGS) $@ $(OBJS)
clean:
rm -f .depend *.o $(LIB)
#########################################################################
# defines $(obj).depend target
include $(TOPDIR)/rules.mk
sinclude .depend
#########################################################################