第二课时: Linux开发工具链简介
1. gcc使用-v选项,可以看到许多被隐藏的信息
gcc -o test test.c -v
2. c程序编译过程 预处理->编译成汇编代码->汇编成目标代码->链接
3. 只进行预处理 -E参数
gcc -E -o test.cpp test.c
4. 比较两个文件的前后差异 wc 命令
wc test.c test.cpp
5. -x 根据指定的步骤进行工作,预处理文件到汇编代码cpp-output,生成汇编代码后停止工作-S
gcc -x cpp-output -S -o test.s test.cpp
直接编译得到汇编代码
gcc -S test.c
6. 汇编代码->目标代码 gcc -x assembler -c gcctest.s
直接编译成目标代码 gcc -c gcctest.c
使用汇编器生成目标代码as -o gcctest.o gcctest.s
7.目标代码->执行代码gcc -o gcctest gcctest.o
直接生成执行代码gcc -o gcctest gcctest.c
8.-Wall:打开所有的警告信息
9.优化编译选项:-O0缺省情况,不优化-O1 -O2 -O3等等
gcc -01 -o m1 test.c
10. 使用time命令统计程序的运行 time ./m1
GNU binutils 工具简介
1. ar(建立归档文件(库文件))
(1)假设有两个源程序add.c minus.c,包含两个函数文件
将这两个源程序编译成目标文件
gcc -c add.c minus.c
(2)生成库文件,然后复制到/usr/lib目录下
ar rv libtest.a add.o minus.o
sudo cp libtest.a /usr/lib/
(3) 在其他源代码文件中使用了之前库文件中的函数,在链接时用"-l<name>"指明库文件
gcc -o test test.c -llibtest
/***********这里课件上是-ltest 不知道是否正确**************/
2. nm列出目标文件中的符号
A:符号的值是绝对值,并且不会被将来的链接所改变
B:符号位于未初始化数据部分(BSS段)
C:符号是公共的。公共符号是未初始化的数据。在链接时,
多个公共符号可能以相同的名字出现。如果符号在其他地方
被定义,则该文件中的这个符号会被当作引用来处理
D:符号位于已初始化的数据部分
T:符号位于代码部分
U:符号未被定义?:符号类型未知,或者目标文件格式特
殊
nm test.o
3.objcopy可以将一种格式的目标文件内容进行转换,并输出为另一种格式的目标文件。
将test转换为srec格式的文件ts
objcopy -O srec test ts
使用file命令查看文件信息
file ts
4. objdump显示一个或多个目标文件的信息,由其选项来控制显示哪些信息。这个工具可以方便的查看执行文件或者库文件的信息
(1) “-f”选项显示文件头的内容
objdump -f test
(2) “-d”选项进行反汇编
objdump -d add.o
5. readelf 显示一个或多个ELF格式的目标文件信息。
readelf -h test
Gdb = GNU debuger
1. gdb调试bug:gdb bug
2. gcc -g参数:gcc -g -o bug bug.c
GNU make
Make可以识别出makefile中哪些文件已经被修改,并且在再次编译的时候只编译这些文件,从而提高编译的效率
(1) 一般规则:
目标文件 : 依赖文件列表
(注意是tab)命令组
target ... : prerequisites ...
<tab>command
<tab>...
<tab>...
test:test.c;
gcc -O -o test test.c
(2) 缺省情况下从makefile中的第一个目标开始执行,类似深度遍历
(3) 使用变量
$(objects)
objects=main.o kbd.o command.o
edit:$(objects)
<tab>cc -o edit $(objects)
(4)预定义变量:Make使用了许多预定义的变量,如AR、AS、CC、CXX、CFLAGS、CPPFLAGS等等
(5)关于.PHONY例如:
.PHONY:clean
clean:
<tab>rm *.o exec_file
.PHONY通常会放在最后PHONY,作用是告诉make这个target不是真正的文件,只是一个虚拟的target。如果目录下恰好有一个名字为clean的文件。加上那一行和不加那一行就完全不同。如果没有那一行,make clean应该是提示"clean is up-to-date".如果有那一行,则是编译执行rm命令,也就是告诉程序,这个命令是要执行下面的命令,而不是对文件clean进行编译
(6)内部变量
$@扩展成当前规则的目的文件名
$<扩展成依赖列表中的第一个依赖文件
$ˆ扩展成整个依赖列表(除掉了里面所有重复的文件名)
不需要括号括住
CC = gcc
CFLAGS = -Wall -O -g
foo.o : foo.c foo.h bar.h
$(CC) $(CFLAGS) -c $< -o $@
相当于 gcc -Wall -O -g -c foo.c -o foo.o
(7) Makefile中的函数
典型的函数:
7.1 $(subst from,to,text)
$(subst ee,EE,feet on the street)
得到结果等于fEEt on the strEEt’
7.2 $(patsubst pattern,replacement,text)
$(patsubst %.c,%.o,x.c.c bar.c)
相当于‘x.c.o bar.o‘
7.3 $(wildcard pattern) 扩展通配符
$(wildcard *.c)
7.4 $(notdir patter) 去除文本中的路径
dir=$(notdir ./abc/a.c)
得到结果是 a.c
(8) 四种条件语句
ifeq...else...endif 如果等于
ifneq…else…endif 如果不等于
ifndef…else…endif
ifndef...else…endif
/*********这两个一样?**************/
GNU ld 链接器
ld软件的作用是把各种目标文件(.o文件)和库文件链接在
一起,并定位数据和函数地址,最终生成可执行程序
gcc可以间接的调用ld,使用gcc的-Wl参数可以传递参数给ld
目标文件
由多个节(section)组成,常见的节有:
text节保存了可执行代码,
data节保存了有初值的全局标量。已经初始化的数据
bss节保存了无初值的全局变量。没有初始化的数据,只有名称和大小
text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。有值
链接描述文件(Linker script )
分类:
设置入口点命令
处理文件的命令
处理文件格式的命令
常用的命令:
1. 设置入口点
格式:ENTRY(symbol)
设置symbol的值为执行程序的入口点。
ld有多种方法设置执行程序的入口点,确定程序入口点的顺序如下:
(1)ld命令的-e选项指定的值
(2)Entry(symbol)指定的值
(3).text节的起始地址
(4)入口点为0
2.包含其他filename的链接描述文件
INCULDE filename
3.指定多个输入文件名
INPUT(file,file,…)
4.指定输出文件的格式
OUTPUT FORMAT(bfdname)
5.指定目标机器体系结构..
OUTPUT ARCH ( bfdname )
例如:
OUTPUT ARCH(arm)
6.MEMORY:这个命令在用于嵌入式系统的链接描述文件中经常出现, 它描述了各个内存块的起始地址和大小。格式如下:
MEMORY
{
name [(attr)]:ORIGIN = origin,LENGTH = len
…
}
例如:
MEMORY
{
rom : ORIGIN=0x1000, LENGTH=0x1000
}
7. SECTIONS
告诉ld如何把输入文件的各个节映射到输出文件的各个节中。在一个链接描述文件中只能有一个SECTIONS命令
在SECTIONS命令中可以使用的命令有三种:
(1)定义入口点
(2)赋值
(3)定义输出节
定义输出节:
SECTIONS
{
secname :
{
contents
}
}
例子:
SECTIONS
{
ROM:{*(.text)}>rom
}
8.定位计数器
一个特殊的ld变量,使用“.”表示
总是在SECTIONS中使用
例如:
SECTIONS
{
output:
{
file1(.text);
. = . + 1000;
file2(.text);
. = . + 1000;
file3(.text);
} = 0x1234;
}
/*********有问题的地方******************/
链接描述符文件
SECTIONS
定位输出点