S5PV210开发 -- 交叉编译器

来源:互联网 发布:阿里云香港b区速度 编辑:程序博客网 时间:2024/05/16 06:45

交叉编译器我们讲了不少,Hi3516A开发--安装交叉编译器  DM368开发 -- 环境搭建  但都未系统的总结一下。

接下来,先讲一下S5PV210的交叉编译器的安装,然后再总结。

一、安装交叉编译器

(1)下载

下载:arm-none-linux-gnueabi-gcc下载

(2)安装

交叉编译所需软件包为 arm-2009q3.tar.bz2

《1》解压

在 /usr/local/ 目录下建立目录 arm,将软件解压至该目录。

    #tar -xvf arm-2009q3.tar.bz2 -C /usr/local/arm/

PS:按理说是可以解压在任意目录下的,但提供的kernel源码编译器默认设置的位置是  /usr/local/arm/ 

《2》增加环境变量

环境变量之前讲过,参看:UNIX再学习 -- 环境变量

修改 /etc/profile 文件 

    #gedit /etc/profile  

在最末尾添加:

    export PATH=/usr/local/arm/arm-2009q3/bin/:$PATH

执行如下指令让环境变量生效:
    #source /etc/profile

检验:

which arm-none-linux-gnueabi-gcc  查看所在位置
echo $PATH  查看环境变量

二、交叉编译器详解

参看:交叉编译详解

参看:交叉编译详解 一 概念篇

(1)什么是交叉编译

在讲交叉编译之前,可以先回顾一下之前讲的 gcc 编译,参看:C语言再学习 -- GCC编译过程

这个 gcc 编译,可以理解为“本地编译”,直接将源文件编译出来的程序,编译出来的程序可以在当前平台下进行运行。

而所谓的交叉编译器正好与本地编译相对应,在当前编译平台下,编译出来的程序能运行在体系结构不同的另一种目标平台上,但是编译平台本身却不能运行该程序。

举个栗子:

参看:MQTT再学习 -- 交叉编译与移植

然后我门再看一下,gcc 和 arm-none-linux-gnueabi-gcc 编译生成的文件到底有啥不同。

gcc编译:

[cpp] view plain copy
  1. # file libmosquitto.so.1   
  2. libmosquitto.so.1: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked,   
  3. BuildID[sha1]=0xb05795243eded68d65abe39b12212099c849965b, not stripped  
arm-none-linux-gnueabi-gcc 交叉编译:
[cpp] view plain copy
  1. # file libmosquitto.so.1   
  2. libmosquitto.so.1: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked,   
  3. not stripped  
看出来了么? 是类型啦,主要是在 Intel 执行还是在 ARM 执行的。

参看:PM2.5检测 -- PMS7003 采集和 MQTT 传输
生成可执行文件 client
[cpp] view plain copy
  1. //查看文件属性  
  2. # file client   
  3. client: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs),   
  4. for GNU/Linux 2.6.14, not stripped  
  5.   
  6. //Ubuntu下 不能执行  
  7. # ./client   
  8. bash: ./client: cannot execute binary file  
arm-none-linux-gnueabi-gcc 在Ubuntu下编译生成的文件,不能在Ubuntu下运行,只能在ARM开发板下执行。

(2)为什么会有交叉编译器

之所以要有交叉编译,主要原因是:
速度: 目标平台的运行速度往往比主机慢得多,许多专用的嵌入式硬件被设计为低成本和低功耗,没有太高的性能
能力: 整个编译过程是非常消耗资源的,嵌入式系统往往没有足够的内存或磁盘空间
可用性: 即使目标平台资源很充足,可以本地编译,但是第一个在目标平台上运行的本地编译器总需要通过交叉编译获得
灵活性: 一个完整的Linux编译环境需要很多支持包,交叉编译使我们不需要花时间将各种支持包移植到目标板上
为什么交叉编译比较困难,参看:Introduction to cross-compiling for Linux

(3)交叉编译链

参看:C语言再学习 -- GCC编译过程
编译过程可分为四个阶段:预处理->>编译->>汇编->>链接    看参看文章即可,这里就不多讲了。

(4)交叉编译器的名字的命名规则

参看:arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi区别

《1》命名规则

交叉编译器的(前缀)的名字的命名规则是: arch-vendor-kernel-system
arch,即系统架构
表示交叉编译器,是用于哪个目标系统架构中,用于那个平台中的。即,用此交叉编译器编译出来的程序,是运行在哪种CPU上面的。arch的值,常见的有很多种,比如arm,x86,mips等等。
vendor,即生成厂家,提供商
表示谁提供的,即谁制作出来这个交叉编译器的。但是这一组命名好像比较灵活,在其它厂家提供的交叉编译链中,有以厂家名称命名的,也有以开发板命名的,或者直接是none或cross的。
kernel,直译为,内核
其实指的是,你用此交叉编译器,编译出来的程序,所运行的目标系统。即,此交叉编译器,编译出来的程序,在什么系统中,什么环境中,运行。见过的有 Linux,uclinux,bare(无OS)。
system,直译为,系统
其实主要表示的,交叉编译器所选择的库函数和目标系统。最常见的一些值有,gnu,gnueabi,uclibcgnueabi等等。

扩展:
ABI:二进制应用程序接口(Application Binary Interface (ABI) for the ARM Architecture)。在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口。
EABI:嵌入式ABI。嵌入式应用二进制接口指定了文件格式、数据类型、寄存器使用、堆积组织优化和在一个嵌入式软件中的参数的标准约定。开发者使用自己的汇编语言也可以使用 EABI 作为与兼容的编译器生成的汇编语言的接口。
两者主要区别是,ABI是计算机上的,EABI是嵌入式平台上(如ARM,MIPS等)

《2》分类和说明

参看:ARM交叉编译工具链
从授权上,分为免费授权版和付费授权版。
免费版目前有三大主流工具商提供,第一是GNU(提供源码,自行编译制作),第二是 Codesourcery,第三是Linora。
收费版有ARM原厂提供的armcc、IAR提供的编译器等等,因为这些价格都比较昂贵,不适合学习用户使用,所以不做讲述。
arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-linux-gnueabihf-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
aarch64-linux-gnu-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-none-elf-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
arm-none-eabi-gcc:是 GNU 推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。

(5)包含的工具

查看 arm-2009q3/bin 可以看到其包含很多工具,那么这些工具都是干哈的,我们来看一下。

《1》GNU Binutils 简介

参看:GNU Binutils
参看:GNU Binary Utilities
GNU Binutils是二进制工具的集合。 主要的是:
ld - GNU链接器。
as - GNU汇编程序。
addr2line - 将地址转换为文件名和行号。
ar - 用于创建,修改和从档案中提取的实用程序。
c++ filt - 过滤到demangle编码的 C++ 符号。
dlltool - 创建用于构建和使用DLL的文件。
gold - 一个新的,更快的ELF链接器,仍在测试中。
gprof - 显示分析信息。
nlmconv - 将目标代码转换为 NLM。
nm - 列出来自目标文件的符号。
objcopy - 复制和翻译目标文件。
objdump - 显示来自对象文件的信息。
ranlib - 生成一个档案内容的索引。
readelf - 显示来自任何 ELF 格式对象文件的信息。
size - 列出对象或归档文件的节大小。
strings - 列出文件中可打印的字符串。
strip - 丢弃符号。
windmc - Windows兼容的消息编译器。
windres - Windows资源文件的编译器。

《2》使用示例

汇编器
arm-linux-as led.o -o led.s -g
链接器
arm-linux-ld -o led led.o
文件格式转换
arm-linux-objcopy binary -O led led.bin
反汇编
arm-linux-objdump -S led.o>led.asm
elf格式文件查看
arm-linux-readelf -a led.elf
符号表生成指令
arm-linux-nm led.elf 
去掉elf文件中不需要的信息和代码
arm-linux-strip led.elf      arm-linux-strip led.o

三、会遇到的问题

如果是对gcc编译不熟悉的人可能会遇到一个问题:
上传到板子的“可执行文件”,运行后出现 line 1: syntax error: unexpected word (expecting ")") 

问题分析:

1. 编译器的问题

用arm-linux-gcc编译,可能原来是用gcc编译的。假如是脚本,#!/bin/sh 改 #!/bin/bash试试

2. 文件完整性

重新烧写或上传一遍

3. 编译命令问题

比如我的一个测试程序 test.c

编译:arm-none-linux-gnueabi-gcc -c i2c_test.c -o i2c_test     //i2c_test 为目标文件

使用file查看:
# file i2c_testi2c_test: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
使用 readelf 查看:
# readelf -h i2c_testELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              REL (Relocatable file)  Machine:                           ARM  Version:                           0x1  Entry point address:               0x0  Start of program headers:          0 (bytes into file)  Start of section headers:          1008 (bytes into file)  Flags:                             0x5000000, Version5 EABI  Size of this header:               52 (bytes)  Size of program headers:           0 (bytes)  Number of program headers:         0  Size of section headers:           40 (bytes)  Number of section headers:         15  Section header string table index: 12
这相当于将 i2c_test.o 重命名为 i2c_test 其本质还是目标文件。
如果此时你将 i2c_test 拷贝到开发板,执行的话,当然就会出现问题
line 1: syntax error: unexpected word (expecting ")") 

编译:arm-none-linux-gnueabi-gcc i2c_test.c -o i2c_test     //i2c_test 为可执行文件

使用 file 查看:
# file i2c_testi2c_test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped
使用 readelf 查看:
# readelf -h i2c_testELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              EXEC (Executable file)  Machine:                           ARM  Version:                           0x1  Entry point address:               0x84a0  Start of program headers:          52 (bytes into file)  Start of section headers:          3132 (bytes into file)  Flags:                             0x5000002, has entry point, Version5 EABI  Size of this header:               52 (bytes)  Size of program headers:           32 (bytes)  Number of program headers:         8  Size of section headers:           40 (bytes)  Number of section headers:         31  Section header string table index: 28
readelf 指令以前有讲过,参看:C语言再学习-- readelf、objdump、nm使用详解
-h选项读取ELF文件的文件头信息,注意其中的两项值:Type 和 Entry point address。
Type信息就是file中的文件类型,而 Entry point address表示文件的执行入口点,只有可执行文件该项才有值,而目标文件是可重定向文件,还不可以直接执行,因此该项值为0.

file指令,参看:file 指令
主要查看是目标文件(Relocatable)还是可执行文件(Executable)
还有查看是GCC编译(Intel)还是交叉编译(ARM)