一、arm-linux-gcc
1. 编译部分:
-o : 后面接的是输出文件名(arm-linux-gcc -o hello hello.c)
-v : 可以观看编译细节 (arm-linux-gcc -v -o hello hello.c)
-c : 预编译,编译和汇编源文件,不做连接 [裸板程序一般先不做连接,最后一起做链接](arm-linux-gcc -o hello.o -c hello.c)
-S : 编译后停止,不进行汇编(arm-linux-gcc -S -o hello.s hello.c)
-E : 预编译后即顶着,不进行编译(arm-linux-gcc -E hello.c)
-g : 产生调试信息
-Wall : 打开所有需要注意的警告信息
2. 优化部分
(注可以指定多个"-O"选项,不管带不带数字,生效的是最后一个)
-O or -O1 : 不使用-O/-O1时,可以减少编译的开销,使编译结果能够调试,语句是独立的,只有声明了register的变量才分配使用寄存器;
使用-O/-O1时,编译器试图减少目标码的大小和执行时间。
-O2 : 多优化一些,除了涉及空间和速度交换的优化选项,执行几乎所有优化工作,例如不进行循环展开和函数内嵌;
-O3 : 优化的更多,除了-O2, 还打开"-finline-functions"
-O0 : 不作优化
3. 链接部分
-llibrary_name : 链接名为library的库文件,真正的名字为liblibrary.a,如要链接libtest.a or libtest.so ,则写成-ltest,如果有动态库,则会优先链接动态库。
-Llibpath : 指定链接库搜索路径,如库都放在/prj/libs/下面,则-L/prj/libs
-nostartfiles : 不连接系统标准启动文件,标准库文件仍然正常使用(编译bootloader,kernel时用到)
-nostdlib : 不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器(编译bootloader,kernel时用到)
[与-nostartfiles的区别是,-nostartfiles只是不包含启动文件]
-static : 在支持dynamic linking的系统上阻止连接共享库[默认情况下会优先选择连接动态库,使用了static会直接连接静态库] (gcc-static -o main main.c func.c)
-shared :生成共享OBJ文件 (gcc -shared -o libfunc.so -c func.c; gcc -o main main.c -lfunc -L.)
-fPIC :编译成位置无关,当编译多个文件为动态库是,必须使用这个选项
(gcc-shared -fPIC -o libfunc.so func1.c func2.c func3.c)
-Xlinkeroption : 把选项option传递给连接器,如果要带参数,必须使用两次"-Xlinker" (-Xlinker -assert -Xliner definitions)
-Wl,option : 把选项option传递给连接器,如果option有逗号,则传递多个选项。常见有(-Wl,--start-group ... -Wl, --end-group)
4. 目录部分
-Iinclude_dir : 在头文件中搜索路径列表中添加include_dir
-Llibpath : 指定链接库搜索路径,如库都放在/prj/libs/下面,则-L/prj/libs
二、arm-linux-ld
-T : 用于指定代码段,数据段,bss段的起始地址 or 指定一个连接脚本
1. 用于指定代码段,数据段,bss段的起始地址
-Ttext startaddr //text 指的是代码段, startaddr指的是起始地址
-Tdata startaddr //data指的是数据段
-Tbss startaddr //bss通常指全局未初始化变量
如下:指定代码段的运行地址为0x00000000,没有定义数据段,bss段的起始地址,被依次放在代码段后面
arm-linux-ld-Ttext 0x00000000 -g led_on.o -o led_on.elf注:位置无关码和位置相关码
bootloader,kernel刚开始执行时所处的位置通常不等于运行地址, 在程序开头使用b,bl,mov等"位置无关"指令
将代码从Flash中copy到sdram中,然后再用位置相关码ldr pc, =addr跳转到相应位置执行。
2. 指定一个连接脚本
arm-linux-ld -Tlink.lds -o led_on.elf len_on.S
link.lds:
/*
*OUTPUT_FORMAT 指定输出格式,elf32-littlearm的意思是指定输出可执行文件是elf格式,32位ARM指令,小端
*OUTPUI_ARCH 指定输出可执行文件的平台为ARM
*ENTRY 指定程序入口地址
*_start 等于SECTIONS里面.=0x30000000, 即目标代码的起始地址
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS{
.= 0x30000000;
.text: { *(.text) }
.rodata ALIGN(4) : { *(.rodata) }
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
section格式为:
SECTIONS{secname : 用来命名这个段; 如 .bss
...
secname start ALIGN(align) (NOLOAD) : AT(ldadr)
{ contexts } > region : phdr = fill
}
contexts : 用来确定什么部分放在这个段;
start : 重定位地址,运行地址,如果代码中有位置无关指令,程序在运行时,这个段必须放在这个地址上
ALGIN(align) : 虽然start指定运行地址,但是仍然可以指定对齐要求,对齐后的才是真正运行地址
NOLOAD : 用来告诉加载器,在运行时不用加载这个段,只有在操作系统的情况下才有意义
AT(ldadr) : 编译出来映像文件中的地址-加载地址load address, 如果不使用这个选项,
加载地址等于运行地址。A段放在A处,B段放在B处,运行前再把A,B读出来组装成一个完整的执行程序
在代码中指定某个section:
格式:__attribute__((unused,section (".section-name")))
如:
C语言中:__attribute__((unused,section (".u_boot_cmd")))
link-ds中:
.= .;
__u_boot_cmd_start= .;
.u_boot_cmd: { *(.u_boot_cmd) }
__u_boot_cmd_end= .;
三、arm-linux-objcopy
1. input-file, out-file
: 表示输入目标文件(源目标文件)和输出目标文件(目的目标文件)
2. -I bfdname or --input-target=bfdname
: input-file文件BFD库中描述的标准格式名,如果不指定,则arm-linux-objcopy自己去分析源文件的格式
3. -Obfdname or --output-target=bdfname
: 输出格式
4. -F bfdname or --target=bfdname
: 源目标文件是什么格式,目标文件就是什么格式,只复制不做格式转换
5.-R sectionname or--remove-section=sectionname
: 从输出文件中删掉所有名为sectionname的段
6.-S or --strip-all
: 不从源文件中复制重定位信息和符号信息到目标文件中去(bootloader,kernel等裸板程序用到)
7.-g or --strip-debug
: 不从源文件中复制调试符号到目标文件中去
在编译bootloader, kernel时,常用arm-linux-objcopy将ELF格式生成结果转化为二进制文件:
// binary表示输出格式为二进制文件
// file.elf表示ELF格式文件名
// file.bin表示二进制文件名
#arm-linux-objcopy -O binary -S file.elf file.bin
bfdname 有以下几个格式:ELF文件格式(elf32-littlearm, elf32-bigarm)、S-record文件格式(srec)、HEX文件格式(ihex)、bin文件格式(binary)
BIN文件格式(binary): 原始的二进制格式,内部没地址标记,直接照二进制格式下载,并且照绝对地址烧写到Flash中,
就可以启动了,而如果下载运行,则下载到编译时的地址即可。
ELF文件格式 : 是Linux系统下的一种常用、可移植目标文件(objectfile)格式
S-Record文件格式
HEX文件格式
四、 arm-linux-objdump (反汇编代码)
1. -b bfdname or --target=bfdname : 指定目标码格式,
2. --infoor -i : 查看目标码格式列表
3. --disassemble or -d : 反汇编可执行段(executablesections)
4. -D or --disassemble-all : 反汇编所有段
5. --file-headers or -f : 显示文件的整体头部摘要信息
6. --section-headers, --headers or -h : 显示目标文件各个段头部摘要信息
7. --section=nameor -j name : 仅显示指定section的信息
//将ELF格式的文件转换成为反汇编文件,arm-linux-objdump默认格式elf
#arm-linux-objdump -D file.elf > file.dis
//将二进制文件转换成反汇编文件
#arm-linux-objdump -D -b binary -m arm file.bin > file.bin
五、arm-linux-readelf (查看当前文件or库是由什么编译器所编译 )
#arm-linux-readelf–h libxxx.so
六、arm-linux-ar (生成.a or 把.a拆分成.o)
1. -x : 把.a拆分成.o
#arm-linux-ar -x libfunc.a
2.生成静态库.a文件
-c : 创建一个文档
-s : 在文档中添加索引
-r : 插入文件成员
/* libfunc.a一定在.o文件前面 */
#arm-linux-ar -rcs libfun.a fun1.o fun2.o fun3.o
七、arm-linux-strip (去掉其中的调试信息,执行文件大小or动态库将小的多)
arm-linux-strip libfunc.so