嵌入式Linux应用开发完全手册(一)嵌入式Linux基础知识

时间:2021-01-11 18:48:09

嵌入式Linux应用开发完全手册

3 嵌入式Linux基础知识

3.1 交叉编译工具

  • 编译工具链,编译工作由几个步骤完成,分别用到了不同的工具
    • PC端应用
      • gcc
      • ld
      • objcopy
      • objdump
    • 交叉编译(编译和运行在不同的环境下),arm平台工具链
      • arm-linux-gcc
      • arm-linux-ld

3.1.1 arm-linux-gcc

  • C/C++文件的编译步骤
    • 预处理 preprocessing
    • 编译 compilation
    • 汇编 assembly
    • 连接 linking
预处理

根据预处理命令(#开头的命令)修改源文件,形成.i文件
用到额工具是arm-linux-cpp

编译

将经过预处理的.i文件,翻译成汇编代码,.s文件
用到的工具是ccl

汇编

将汇编代码文件.s翻译成目标文件 .o文件
用到的工具是arm-linux-as

连接

将汇编生成的目标文件和库文件连接起来,最终生成特定平台的可执行文件
用到的工具是arm-linux-ld
连接器处理的文件一般包括
- .o 目标文件
- .a 库文件

arm-linux-gcc的重要选项
  • -E 预处理 :预处理结果通过stdout显示出来
  • -S 预处理、编译 :可以生成.s文件
  • -c 预处理、编译、汇编 :可以生成.o文件
  • -o 指定输出文件名 :如果不指定名成,按照一般规则生成
  • -v 显示制作gcc命令时的配置 :显示更详细的编译信息
  • -Wall 显示所有警告信息 :Warning ALL
  • -g 产生调试信息,以便GDB使用 : 要使用gdb调试,必须有这个选项
  • -O 优化选项 :O0,O1,O2,O3 4级优化,一般应用选O2
  • [object-file-name] :连接的时候,目标文件和库文件名称
  • -l[library] :连接名为l[library]的库文件,库文件名称规则lib[libraay].so
  • -nostartfiles :不连接系统标准启动文件,编译bootloader, 内核的时候会用到
  • -nostdlib :不连接系统标准启动文件和标准库文件,编译bootloader和内核会用到
  • -static :组织连接共享库,打开这个选线柜让编译出来的结果很大,不动态连接一些库,那么就都包含在编译结果里边了
  • -shared :生成库文件
  • -I[dir] :头文件搜索路径中添加 dir
  • -L[dir] :-l指定某个库需要连接的时候,这个参数增加搜索路径,比如-L. 当前目录作为搜索目录添加进来
/ * 举例 */ 
[main.c] - include [sub.h]
[sub.h]
[sub.c] - include [sub.h]

--------

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

--------

gcc -S -o main.s main.c
gcc -E main.c | less

--------
gcc -shared -o sub.a sub.o sub2.o sub3.o
arm-linux-ld选项
  • -T :指定代码段、数据段、bss段的起始位置,或者指定一个连接脚本
    :-T参数只用于连接bootloader,内核等“没有底层软件支持”的软件
    :连接运行于操作系统之上的软件时,不需要-T,使用默认连接即可
-Ttext startaddr
-Tdata startaddr
-Tbss startaddr

/* 代码段运行地址0x00000000,没有定义数据段,bss段,它们依次放在代码段后面 */
arm-linux-ld -Ttext 0x00000000 -g ledon.o -o ledon_elf

/* 使用连接脚本设置地址 */
arm-linux-ld -Ttimer.lds -o timer_elf head.o init.o interrupt.o main.o

[timer.lds]
--------
SECTIONs {
. = 0x30000000;
.text : {*(.text)}
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*(.bss) *(COMMON)}
}
--------
arm-linux-objcopy选项
  • arm-linux-objcopy用来赋值一个目标文件到另一个文件中,可以使用不同于源文件的格式来输出目的文件,也就是可以用来进行格式转换
  • 可以用它来将elf文件转换位二进制可执行文件
/* 编译bootloader和内核的时候,用此命令将elf文件转换为二进制文件 */
arm-linux-objcopy -O binary -S elf_file bin_file
arm-linux-objdump选项
  • 用于显示二进制文件信息,常用来查看反汇编代码
/* 将elf格式文件反汇编 */
arm-linux_objdump -D elffile > dis_file

/* 将二进制文件反汇编 */
arm-linux-objdump -D binary -m arm bin_file > dis_file

3.2 Makefile

Makefile就是一个名字是Makefile的文件。内部缩进必须使用Tab,不能转换为空格。
这里介绍Makefile的最基本的规则。

格式

[Makefile]
--------
target : prerequiries
<Tab>command
--------
  • 目标 通常是要生成的文件名称,可以是可执行文件或者obj文件。也可以是一个需要执行的动作名称,比如“clean”
  • 依赖 用来产生目标的原料(比如源文件),一个目标通常有几个依赖。
  • 命令 生成目标时进行的动作。可以有若干命令,一个命令一行
  • 依赖发生改变,目标就需要通过命令重新生成。如果依赖没有改变,目标不需要重新生成。
/* 一个最简单的例子 */
hello: hello.c
gcc -o hello hello.c
clean:
rm -f hello

变量及赋值

  • 延时变量
    • =
    • ?=
  • 立即变量
    • :=
  • 扩展变量
    • +=
src := $(shel ls *.c)                  /* 立即变量的赋值 */
obj := $(patsubst %.c, %.o, $(src))
obj += temp.o /* 扩展变量 */

test: $(obj) /* 变量使用 */
gcc ...

Makefile函数

Makefile里边可以使用一些函数,格式如下

$(function arguments)
字符串替换和分析函数
  • $(subst from, to, text)
  • $(patsubst pattern, replacement, text)
  • $(strip string)
  • $(findstring find, in)
  • $(filter pattern…, text)
  • $(filterout pattern…, text)
  • $(sort list)
$(subst ee, EE, feet on the street)
fEEt on the strEEt

$(patsubst %.c, %.o, x.c.c bar.c)
x.c.o ar.o

$(strip a b c
a b c

$(findstring a, a b c)
a
$(findstring a, b c)


$(filter %.c %.s, foo.c bar.c baz.s ugh.h)
foo.c bar.c baz.s

$(filterout %.c %.s, foo.c bar.c baz.s ugh.h)
ugh.h

$(sort foo bar lose)
bar foo lose
文件名函数
  • $(dir names)
  • $(notdir names)
  • $(suffix names)
  • $(basename names)
  • $(addsuffix suffix, names)
  • $(addprefix prefix, names)
  • $(wildcard pattern)
$(dir src/foo.c hacks)
src/ ./

$(notdir src/foo.c hacks)
foo.c hacks

$(suffix src/foo.c src-1.0/bar.c hacks)
.c .c

$(basename src/foo.c src-1.0/bar.c hacks)
src/foo src-1.0/bar hacks

$(addsuffix .c, foo bar)
foo.c bar.c

$(addprefix src/, foo bar)
src/foo, src/bar

$(wildcard *.c)/* 等于 $(shell ls *.c)*/
1.c 2.c
其他
  • $(foreach var, list, text)
  • $(if condition, then-part, else-part)
  • $(origin var)
  • $(shell cmd)
dirs := a b c d
files := $(foreach dir, $(dir), $(wildcard $(dir)/*))
/* files 变量赋值为 a/ b/ c/ d/ 下边的所有文件*/
自动变量
  • $@ 规则的目标文件
  • $^ 所有依赖名字,名字之间空格分开
  • $< 第一个依赖的名字
    一个稍微复杂点的例子
src := $(shell *.c)
objs := $(patsbust %.c, %.o, $(src))

test: $(objs)
gcc -o $@ $^

%.o: %.c
gcc -c -o $@ $<

clean:
rm -f test *.o

3.3 常用ARM汇编指令和ATPCS规则

ARM汇编指令

  • 相对跳转b, bl
  • 数据传送指令mov
  • 地址读取伪指令ldr
  • 内存访问指令 ldr str ldm stm
  • 加减 add sub
  • 程序转台寄存器访问指令 msr mrs
  • 其他 .extern .text .global

ATPCS

ARM程序和Thumb程序中子程序调用规则。
- 寄存器
- r0 - r3 传递参数
- r4 - r11 保存局部变量
- r12 子程序间scratch寄存器,别名ip
- r13 数据栈指针,别名sp
- r14 连接寄存器,别名lr
- r15 程序计数器,别名pc
- 堆栈
- FD 满减堆栈
- 8字节对齐
- stmdb ldmia 指令访问,db: Decending before, ia:increase after
- 参数传递规则
- 参数不超过4个,用r0 - r3,超过4个用堆栈
- 返回结果用r0 - r3

4 Windows,Linux环境下的工具、命令介绍

4.1 windows

Source insight

Cuteftp, SecureCRT, tftp

  • 这几个工具用Xshell就全搞定了,不用书上介绍的这几个 *

4.2 Linux

KScope

CKermit

Vi

  • 这几个工具暂时用不到,就用windows环境 Samba连接Linux即可,Vi可以通过Vimtutor熟悉下 *

grep find 命令

grep
  • grep [operation] PATTERN [FILE…]
grep "request_irq" * -R                         // *表示当前目录下所有文件,-R 表示递归查找所有子目录
grep "request_irq" kernel -R // 在当前目录的kernel目录下查找,包含所有子目录
find -name "*.[ch]" | xargs grep "request_irq" // 在当前目录下所有的.c .h 文件中查找关键字
find
  • find [-H] [-L] [-P] [path…] [expression]
find -name "*fb*"
find drivers/net -name "*fb*"
man
  • man [section] name
  • 需要注意的是[section] 部分,因为同一个关键字,可以出现在不同的地方,比如uname 可以是shell命令,也可以是系统格调用,单纯根据关键字是无法定位的。*
  • section的定义
    • 1 命令,比如ls grep find
    • 2 系统调用,比如open read socket
    • 3 库调用,比如fopen, fread
    • 4 特殊文件 比如 /dev 目录下的文件
    • 5 文件格式和惯例,比如/etc/passwd
    • 6 游戏
    • 7 其他
    • 8 系统管理命令,如mount
    • 9 内核例程
man uname
man 2 uname
tar
  • tar有打包、解包、压缩、解压缩 4种功能
  • 压缩格式
    • gzip .gz .z
    • bzip2 .bz2
  • tar命令常用选项
    • c 创建
    • x 提取
    • z 使用gzip方式处理
    • j 使用bzip2方式处理
    • f 文件,接文件名
  • 最常用的选项组合套路
    • czf, cjf 创建压缩包
    • xzf, xjf 解压缩
tar czf dirA.tar.gz dirA
tar cjf dirA.tar.bz2 dirA

tar xzf dirA.tar.gz
tar xjf dirA.tar.bz2
diff patch
  • diff是UNIX标准的文件差异对比工具和格式
  • diff常用选项
    • -u 显示上下文中一些相同的行
    • -r 递归比较各目录下的文件
    • -N 不存在的文件当做空文件
    • -w 忽略空格
    • -B 忽略空行
  • 用diff命令制作补丁文件
diff -urNwB linux-2.6.22.6 linux-2.6.22.6_ok > linux-2.6.22.6_ok.diff
  • patch的用法,patch用来把一个补丁文件(.diff)合并到工程中
cd linux-2.6.22.6
patch -p1 < ../linux-2.6.22.6_ok.diff

其中参数-p1 中是数字1,不是子母l。含义是忽略补丁文件中所有路径相关字段的的第一级目录,具体应该忽略几级,需要打开diff文件查看一下,跟patch执行的当前路径对比一下。