本文共 3939 字,大约阅读时间需要 13 分钟。
在韦东山的mmu试验中的makefile是这样写的:看的不知其所以然,花了一天时间查明白是干什么的了:
objs := head.o init.o leds.o
mmu.bin : $(objs)
arm-linux-ld -T mmu.lds -o mmu_elf $^
arm-linux-objcopy -O binary -S mmu_elf $@
arm-linux-objdump -D -m arm mmu_elf > mmu.dis
%.o:%.c
arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -O2 -c -o $@ $<
clean:
rm -f mmu.bin mmu_elf mmu.dis *.o
SECTIONS {
firtst 0x00000000 : { head.o init.o }
second 0xB0004000 : AT(2048) { leds.o }
}
1 objs := head.o init.o leds.o
objs是makefile中的一个变量,类似C中的宏定义#define ,是为了省去在后面写 head.o init.o leds.o,可以直接用$(objs)代替。
2 mmu.bin : $(objs),mmu.bin是目标文件,
$(objs)是依赖关系。 3
arm-linux-ld 是连接器,它把一些目标和归档文件结合在一起,重定位数据,并连接符号引用。通常,建立一个新编译程序的最后一步就是调用ld。arm-linux-objcopy 把一种目标文件中的内容复制到另一种类型的目标文件中.rm-linux-objdump 显示一个或者更多目标文件的信息。使用选项来控制其显示的信息,它所显示的信息通常只有编写编译工具的人才感兴趣. 其实 gcc是编译器,负责对c代码的编译, ld是连接器 负责将多个*.o的目标文件链接成elf可执行文件。elf可执行文件是unix常用的可执行文件类型,就像windows的exe文件。elf文件中有很多信息包括段信息还有头信息,这些信息对硬件是没有意义的,所以有的时候我们通过objcopy将elf转化成bin 文件加载到内存中运行,bin文件就是一个纯二进制文件,并且你可以通过objdump将elf文件来反汇编。
arm-linux-gcc -Wall -O2 -c -o $@ $<
-o 只激活
预处理,编译,和汇编,也就是他只把程序做成obj文件也就是.o的目标文件
-O2 编译器对程序提供的编译优化选项,在编译的时候使用该选项,
可以使生成的执行文件的执行效率提高,O后面还可以附带其他的数值,表示提供不同的优化策略。 -c 表示只要求编译器进行编译,而不要进行链接,生成以源文件的文件名命名但把其后缀由 .c 或 .cc 变成 .o 的目标文件
-S 只激活预处理和编译,就是指把文件编译成为汇编代码也就是.s文件
$@和$< 在makefile中其实是自动化变量,“$<”表示所有的依赖目标集(也就是“.c ”),“$@”表示所有目标集(“.o”) arm-linux-ld –Ttext 0x0000000 –g led.o –o led_elf
arm-linux-ld –Ttimer.lds –o timer_elf $^
Secname start ALING(aling) (NOLOAD):AT(ldaddr)
{contents} > region:phdr=fill
被用来复制一个目标文件的内容到另一个文件中,可用于
不同源文件的之间的格式转换 arm-linux-objcopy –O binary –S elf_file bin_file
1.input-file , outfile
输入和输出文件,如果没有outfile,则输出文件名为输入文件名
2.-I bfdname或—input-target=bfdname
用来指明源文件的格式,bfdname是BFD库中描述的标准格式名,如果没指明,则arm-linux-objcopy自己分析
3.-O bfdname 或--output-target=bfdname 输出的格式
4.-F bfdname 同时指明源文件,目的文件的格式,将源文件和输出文件的格式都设置为bfdname
5.-R sectionname 从输出文件中删除掉所有名为sectionname的段
6.-S 不从源文件中复制重定位信息和符号信息到目标文件中
arm-linux-objdump -D -m arm led_elf > led.dis
-m machine 指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述架构信息的时候(比如S-records),这个选项很有用。可以用-i选项列出这里能够指定的架构 File :Makefile 01 CC = arm-linux-gcc (编译工具) 02 LD = arm-linux-ld(连接工具) 03 AR = arm-linux-ar(将多个.o文件合并成一个.O或者静态库文件(.a文件)) 04 OBJCOPY = arm-linux-objcopy(复制一个目标的内容到另一个文件中,将elf转化成bin文件加载到内存中运行用此工具) 05 OBJDUMP = arm-linux-objdump(用于显示二进制文件信息,将elf文件反汇编) 06 INCLUDEDIR := $(shell pwd)/include (shell函数,本句是在当前目录下的include文件夹下) 07 CFLAGS := -Wall -O2 (CFLAGS为C语言编译器参数,-wall打开警告和优化级别为O2) 08 CPPFLAGS := -nostdinc -I$(INCLUDEDIR) (CPPFALGS 为c语言预处理参数,这里-nostdinc的意思是:Do not search the standard system directories for header files。-I 指定只对#include “file”有效的头文件搜集目录) LDFLASG := -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc (LDFLAGS为链接器参数-print-libgcc-file-name: 示编译器伴随库的名称) 09 export CC LD OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS AR ( 用export声明这些变量使得他们可以被子目录的Makefile使用 ) 10 objs := head.o init.o nand.o interrupt.o adc_ts.o serial.o main.o lib/libc.a (objs 为变量,代替后面.o程序。lib/libc.a为连接库文件) 11 adc_ts.bin: $(objs) 12 ${LD} -Tadc_ts.lds -o adc_ts_elf $^ ${LDFLASG} (-T后面链接脚本adc_ts.lds ,$^为自动化变量,表示所有依赖目标的集合) 13 ${OBJCOPY} -O binary -S adc_ts_elf $@ ($@表示规则中的目标文件集,本句将elf文件可执行文件转换成二进制) 14 ${OBJDUMP} -D -m arm adc_ts_elf > adc_ts.dis( '-m' 后面跟的是 构架 arm就表示是arm构架的 '>' 表示将这个程序的反汇编程序写入到led.dis这个文件中,在终端中不显示出来.当你打开led.dis这个文件时就会看到上面命令的输出的反汇编程序了 ) 15 .PHONY : lib/libc.a (,PHONY用来声明一个伪目标) 16 lib/libc.a: 17 cd lib; make; cd .. 18 %.o:%.c 19 ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< (将所有的[.C]文件都编译成[.O]文件) 20 %.o:%.S 21 ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< (将所有的[.s]文件都编译成[.O]文件) 22 clean:(删除文件) 23 make clean -C lib 24 rm -f adc_ts.bin adc_ts_elf adc_ts.dis *.o 转载地址:http://kyrsi.baihongyu.com/