您的位置:首页 > 运维架构 > Linux

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

2017-08-12 21:34 204 查看

嵌入式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执行的当前路径对比一下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  嵌入式 linux