常用交叉编译工具整理(arm-linux-gcc)

时间:2023-01-05 18:53:27

一、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 start ALIGN(align) (NOLOAD) : AT(ldadr)
{ contexts } > region : phdr = fill
}
secname       : 用来命名这个段; 如 .bss

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