编译器下载
- arm-linux-gcc下载 https://www.linaro.org/downloads/
- 解压添加bin到环境变量
gcc组件
c++ | gcc 的一个版本,默认语言设置为 C++,而且在连接的时候自动包含标准 C++库。这和g++一样 |
g++ | gcc 的一个版本,默认语言设置为 C++,而且在链接的时候自动包含标准 C++库。这和 c++ 是一样的 |
gcc | 该驱动程序用于执行编译程序和连接程序以产生需要的输出 |
gcc使用
gcc参数
选项 | 描述 |
-c | 只编译不链接。 会明确指示 GCC 去编译源代码,在硬盘上留下目标文件,且跳过将目标文件连接到可执行程序这一步。 缺省情况下, GCC通过用`.o'替换源文件名后缀`.c', `.i', `.s',等产生目标文件名.可以使用-o选项选择其他名字. GCC忽略-c选项后面任何无法识别的输入文件(他们不需要编译或汇编). 如:gcc -c hello.c |
-Dmacro | 定义指定的宏,使它能够通过源码中的#ifdef进行检验 |
-o file | 指定输出的文件名 如果没有使用 `-o' 选项,默认的输出结果是:可执行文件为`a.out'。如gcc -c hello.c -o hello.o |
-S | 指示编译程序生成汇编语言代码,然后停止。 缺省情况下, GCC通过用 `.o' 替换源文件名后缀 `.c'、`.i' 等等,产生 目标文件名。可以使用-o选项选择其他名字。 汇编语言的形式依赖于编译程序的目标平台。如果编译多个源文件,会为每个源文件都生成一个汇编语言模块。 GCC忽略任何不需要编译的输入文件。 gcc -S helloworld.c |
-E | 预处理后即停止,不进行编译。预处理后的代码送往标准输出 GCC忽略任何不需要预处理的输入文件. gcc -E helloworld.c gcc -E helloworld.c -o helloworld.i |
-C | 告诉预处理器不要丢弃注释,配合 `-E' 选项使用。 |
-P | 告诉预处理器不要产生 `#line' 命令,配合 `-E' 选项使用 |
-v | (在标准错误)显示执行编译阶段的命令.同时显示编译器驱动程序,预处理器,编译器的版本号. |
-ldl | 表示生成的对象模块需要用到共享库:$ gcc say.c -ldl -o say 主要是用到了 dlopen 等函数需要用到此选项 |
-I | 指定头文件路径 |
-e name | 指定 name 为程序的入口地址 |
-ffreestanding | 编译独立的程序,不会自动链接 C 运行库、启动文件等;他隐含声明了 `-fno-builtin' 选项,而且对main函数没有特别要求。 |
-finline-functions -fno-inline-funcitons | 启用内联函数 关闭内联函数 |
-g | 以操作系统的本地格式(stabs,COFF,XCOFF 或 DWARF)产生调试信息,GDB能够使用这些调试信息。 |
-ggdb | 以本地格式(如果支持)输出调试信息,尽可能包括GDB扩展。 |
-L <directory> | 指定链接时查找路径,多个路径之间用冒号隔开 |
-static | 在支持动态连接(dynamic linking)的系统上阻止连接共享库。即只能使用静态链接。 |
-shared | 生成一个共享目标文件,他可以和其他目标文件链接产生可执行文件。 |
-O | 优化。对于大函数,优化编译占用稍微多的时间和相当大的内存。 不使用 `-O' 选项时,编译器的目标是减少编译的开销,使编译结果能够调试。 语句是独立的:如果在两条语句之间用断点中止程序,可以对任何变量重新赋值,或者在函数体内把程序计数器指到其他语句,以及从源程序中精确地获取你期待的结果。 不使用 `-O' 选项时,只有声明了register的变量才分配使用寄存器。编译结果比不用 `-O' 选项的GCC要略逊一筹. 使用了 `-O' 选项,编译器会试图减少目标码的大小和执行时间。 如果指定了`-O'选项,,`-fthread-jumps' 和 `-fdefer-pop' 选项将被打开。 |
-O2 | 多优化一些。 除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作。例如不进行循环展开(loop unrolling)和函数内嵌(inlining)。 和 -O 选项比较,这个选项既增加了编译时间,也提高了生成代码的运行效果。 |
-O3 | 优化的更多。除了打开 -O2所做的一切,它还打开了-finline-functions选项。 |
-O0 | 不优化。如果指定了多个 -O选项,不管带不带数字,最后一个选项才是生效的选项。 |
-Wall | 对源代码中的多数编译警告进行启用 |
-fpic | 如果支持这种目标机,编译器就生成位置无关目标码。适用于共享库(shared library)。 |
-fPIC | 如果支持这种目标机,编译器就输出位置无关目标码。适用于动态连接(dynamic linking),即使分支需要大范围转移。 |
-fPIE | 使用地址无关代码模式编译可执行文件 随机分配地址 |
-Xlinker option | 把选项option传递给连接器,可以用他传递系统特定的连接选项, GNU CC无法识别这些选项。 如果需要传递携带参数的选项,必须使用两次 `-Xlinker',一次传递选项,另一次传递他的参数。 例如,如果传递 `-assert definitions',必须写成 `-Xlinker -assert -Xlinker definitions',而不能写成 `-Xlinker "-assert definitions"',因为这样会把整个字符串当做一个参数传递,显然这不是连接器期待的。 |
-Wl option | 把选项option传递给连接器。如果option中含有逗号,就在逗号处分割成多个选项。 |
-ffunction-sections | 将每个函数编译到独立的代码段 |
-fdata-sections | 将全局/静态变量编译到独立的数据段 |
动态库
//单文件
gcc -fPIC -shared xxx.c -o libxxx.so
//多文件
gcc -fPIC -shared xxx1.c xxx2.c xxx3.c -o libxxx.so
使用
编译:
gcc -fPIC -shared hello.c -o libhello.so
gcc main.c -L. -lhello -o main
静态库
1 gcc hello.c -o hello.o #这里没有使用-shared
2 ar -crv libhello.a hello.o #这里的ar相当于tar的作用,将多个目标打包。
gcc main.c libhello.a -L. -o main
或
gcc main.c -lhello -L. -static -o main
gcc工具集
addr2line | 给出一个可执行文件的内部地址,addr2line 使用文件中的调试信息将地址翻译成源代码文件名和行号。 |
ar | 这是一个程序,可通过从文档中增加、删除和析取文件来维护库文件。通常使用该工具是为了创建和管理连接程序使用的目标库文档。 |
as | GNU 汇编器。实际上它是一族汇编器,因为它可以被编译或能够在各种不同平台上工作。 |
c++filt | 程序接受被 C++编译程序转换过的名字(不是被重载的) ,而且将该名字翻译成初始形式。 |
elfedit | 更新 ELF 文件的 ELF 头。 |
gprof | 该程序会监督编译程序的执行过程,并报告程序中各个函数的运行时间,可以根据所提供的配置文件来优化程序。 |
ld | GNU 连接程序。该程序将目标文件的集合组合成可执行程序。 |
ld.bfd | 到 ld 的硬链接。 |
libbfd | 二进制文件描述器库。该程序是 binutils 包的一部分 |
libiberty | 包含多个 GNU 程序会使用的途径,包括 getopt、obstack、strerror、strtol 和 strtoul。 |
libopcodes | 一个库,用于处理 opcodes——处理器指令的 "可读文本" 版本;用于编制 objdump 这样的工具。 |
nlmconv | 将可重定位的目标文件转换成 NetWare 可加载模块(NetWare Loadable Module,NLM) 。 |
nm | 列出目标文件中定义的符号。 |
objcopy | 将目标文件从一种二进制格式复制和翻译到另外一种。 |
objdump | 显示一个或多个目标文件中保存的多种不同信息。 |
ranlib | 创建和添加到 ar 文档的索引。该索引被 ld 使用来定位库中的模块。 |
readelf | 从 ELF 格式的目标文件显示信息 |
size | 列出目标文件中每个部分的名字和尺寸。 |
strings | 浏览所有类型的文件,析取出用于显示的字符串。 |
strip | 从目标文件或文档库中去掉符号表,以及其他调试所需的信息。 |
windres | Window 资源文件编译程序。 |
ld -Ttext 0x4000000 -c -o led.o led.c 指定text段地址
查看对应地址函数名 行号
addrline2 4005100 -e a.out -f
查看elf头信息
readelf -h a.out
查看所有信息
readelf -a a.out
列出文件中符号
nm main.o
objdump -d a.out 反汇编
objdump -D a.out 列出详细内容
objdump -x a.out 显示所有头文件信息
objdump -f a.out 查看入口文件
反汇bin格式文件
objdump -D -b binary -m i386 test.bin
objdump -D -b binary -m arm text.bin
objcopy目标格式转化
转化u-boot为二进制
objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
size a.out 列出文件个段大小
strings a.out 列出可打印信息
strip a.out 瘦身
file a.out 列出文件信息
链接脚本
描述
SECTIONS {
...
secname start BLOCK(align) (NOLOAD):AT(ldard)
{
contents
} > region:phdr=fill
}
secname段名
contents 决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代码段、数据段等)
start 运行地址
AT(ldadr) 定义本段加载地址
例子
SECTIONS {
firtst 0x00000000 : { head.o init.o }
second 0x30000000 : AT(4096) { main.o }
}
main.o放在4096(0x1000,是AT指定的,存储地址)开始处,但是它的运行地址在0x30000000,运行之前需要从0x1000(加载处)复制到0x30000000(运行处),此过程也就用到了读取Nand flash。
ld -Txxx.lds
ld -Ttext 0x300000000
OUTPUT_FORMAT(DEFAULT,BIG,LITTLE) : 定义三种输出文件的格式(大小端)
OUTPUT_FORMAT("elf32­littlearm", "elf32­littlearm", "elf32­littlearm")
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定输出可执行文件的平台为ARM
ENTRY(_start)
指定输出可执行文件的起始代码段为_start.
SECTIONS
{
. = 0x00000000 ; 从0x0位置开始
. = ALIGN(4) ; 代码以4字节对齐
.text : ;指定代码段
{
cpu/arm920t/start.o (.text) ; 代码的第一个代码部分
*(.text) ;其它代码部分
}
. = ALIGN(4)
.rodata : { *(.rodata) } ;指定只读数据段
. = ALIGN(4);
.data : { *(.data) } ;指定读/写数据段
. = ALIGN(4);
.got : { *(.got) } ;指定got段, got段式是uboot自定义的一个段, 非标准段
__u_boot_cmd_start = . ;把__u_boot_cmd_start赋值为当前位置, 即起始位置
.u_boot_cmd : { *(.u_boot_cmd) } ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段.
__u_boot_cmd_end = .;把__u_boot_cmd_end赋值为当前位置,即结束位置
. = ALIGN(4);
__bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置
.bss : { *(.bss) }; 指定bss段
_end = .; 把_end赋值为当前位置,即bss段的结束位置
}
//内存区域描述
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 256K
ram (!rx) : org = 0×40000000, l = 4M
}