armgcc交叉编译的文件无法运行_认识GCC交叉编译器

一、GCC 简介

GCC(GNU Compiler Collection)是一套功能强大、性能优越的编程语言编译器,它是GNU计划的代表作品之一。GCC 是 Linux 平台下最常用的编译器,GCC 原名为 GNU C Compiler,即 GNU C 语言编译器,随着 GCC 支持的语言越来越多,它的名称也逐渐变成了GNU Compiler Collection。

二、什么是交叉编译

简单地说,我们在 PC 机上编译程序时,这些程序应该是在 PC 机上运行的。那如果我们想让一个程序在 ARM 板子上运行,怎么办?

ARM 板性能越来越强,可以认为 ARM 板就相当于一台 PC,当然可以在 ARM 板上安装开发工具,比如安装 ARM 版本的 GCC,这样就可以在 ARM 板上编译程序,在 ARM 板上直接运行这个程序。

但是,有些 ARM 板性能弱,或者即使它的性能很强也强不过 PC 机,所以更多时候我们是在 PC 机上开发、编译程序,再把这个程序下载到 ARM 板上去运行。

这就引入一个问题:
我们使用工具比如说 gcc 编译出的程序是给 PC 机用的,这程序里的指令是 X86 指令。 那么能否使用同一套工具给 ARM 板编译程序?

显然是不行,因为 X86 的指令肯定不能在 ARM 板子上运行。所以我们需要使用另一套工具: 交叉编译工具链。

为何叫“交叉”?
首先,我们是在 PC 机上使用这套工具链来编译程序;然后再把程序下载到 ARM 板运行;如果程序不对,需要回到 PC 机修改程序、编译程序,再把程序下载到 ARM 板上运行、验证。如此重复。在这个过程中,我们一会在 PC 上写程序、编译程序,一会在 ARM 板上运行、验证,中间来来回回不断

重复,所以称之为“交叉”。对于所用的工具链,它是在 PC 机上给 ARM 板编译程序,称之为“交叉工具链”。

903711ca0fa63b7da81a7b88ce2c28bd.png

交叉工具链其实有很多种,常见的如下:

  1. Ubuntu平台:交叉工具链有arm-linux-gcc编译器、arm-linux-gnueabihf编译器。 

  2. Windows平台: 利用ADS(ARM 开发环境),使用 armcc 编译器。

  3. Windows平台: 利用cygwin环境,运行arm-elf-gcc编译器。

三、gcc 编译过程详解

一个 C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和连接(linking) 等 4 步才能生成可执行文件,编译流程图如下:

380189b2fc0963461d05a99aa920e9e0.png

  • 预处理:

    C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令 “#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、 将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一步处理。

  • 编译: 

    对预处理后的源码进行词法和语法分析,生成目标系统的汇编代码文件,后缀名为“.s”。

  • 汇编:

    对汇编代码进行优化,生成目标代码文件,后缀名为“.o”。

  • 链接:

    解析目标代码中的外部引用,将多个目标代码文件连接为一个可执行文件。

编译器利用这 4 个步骤中的一个或多个来处理输入文件,源文件的后缀名表示源文件所用的语言,后缀名控制着编译器的缺省动作

a7c9ff30852af53925482b24f521e48f.png

其他后缀名的文件被传递给连接器(linker),通常包括:

  • .o: 目标文件(Object file,OBJ 文件)

  • .a: 归档库文件(Archive file)

在编译过程中,除非使用了“-c”,“-S”或“-E”选项(或者编译错误阻止了完整的过程),否则最后的步骤总是连接。在连接阶段中,所有对应于源程序的.o 文件,“-l”选项指定的库文件,无法识别的文件名(包括指定的“.o”目标文件和“.a”库文件)按命令行中的顺序传递给连接器。

四、gcc 命令

gcc 的命令格式如下:

gcc [选项] 文件列表

gcc 命令用于实现 c 程序编译的全过程。文件列表参数指定了 gcc 的输入文件;选项用于定制 gcc 的行为。gcc 根据选项的规则将输入文件编译生成适当的输出文件。

gcc 的选项非常多,常用的选项,它们大致可以分为以下几类 。并且使用一个例子来描述这些选项。

#include #define COUNT 10int main(){    printf("COUNTS:%d\n", COUNT);    return 0;}
  • 过程控制选项

过程控制选项用于控制 gcc 的编译过程。无过程控制选项时,gcc 将默认执行全部编译过程,产生可执行代码。常用的过程控制选项有:

(1) 预处理选项(-E) 

C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、 将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一步处理。使用例子如下:

[root@localhost test]# arm-linux-gcc -E main.c -o main.i

运行结果,生成 main.i,main.i 的内容如下(由于头文件展开内容过多,我将截取部分关键代码):

extern char *ctermid (char *__s) __attribute__ ((__nothrow__));# 882 "/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/usr/include/stdio.h" 3 4extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));# 912 "/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/usr/include/stdio.h" 3 4# 2 "main.c" 2int main(){    printf("COUNTS:%d\n", 10);    return 0;}

你会发现头文件被展开和 printf 函数中调用 COUNT 这个宏被展开。

(2) 编译选项(-S)

编译就是把 C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码。使用例子如下:

[root@localhost test]# arm-linux-gcc -S main.i -o main.s

运行结果,生成 main.s,main.s 的内容如下:

cd854ee731d200f4ffc3c900283908df.png

(3) 汇编选项(-c)

汇编就是将上述的“.s”文件汇编代码翻译成符合一定格式的机器代码,在 Linux 系统上一般表现为 ELF 目标文件(OBJ 文件)

[root@localhost test]# arm-linux-gcc -c main.s -o main.o

运行结果,生成 main.o(将源文件转为一定格式的机器代码)。

  • 输出选项

输出选项用于指定 gcc 的输出特性等,常用的选项有:

(1) 输出目标选项(-o filename)

-o 选项指定生成文件的文件名为 filename。使用例子如下:

c8ee6e99c7458e18cbd5e55f3be7de40.png

其中,如果无此选项时使用默认的文件名,各编译阶段有各自的默认文件名,可执行文件的默认名为 a.out。使用例子如下:

2a3de53e7e13fbdb2550ad7c57f11645.png

(2) 输出所有警告选项(-Wall)

显示所有的警告信息,而不是只显示默认类型的警告。建议使用。我们把上面的 main.c 稍微修改一下。

557ca213638777ee30f17da9b9d574c4.png

  • 头文件选项

头文件选项: -I dirname。
将 dirname 目录加入到头文件搜索目录列表中。当 gcc 在默认的路径中没有找到头文件时,就到本选项指定的目录中去找。

在上面的例子中创建一个 inc 目录,并在里面创建一个头文件 test.h。
然后 main.c 里面增加#include“test.h”。

e10c82bcd22326981900a5c4c63be9fb.png

如果不添加头文件选项,会产生错误提示,无法找到 test.h 头文件。
  • 链接库选项

1. 添加库文件搜索目录(-L dirname)
将 dirname 目录加入到库文件的搜索目录列表中。

2. 加载库名选项(-l name)
加载名为 libname.a 或 libname.so 的函数库。

例如:-lm 表示链接名为 libm.so 的函数库。

3. 静态库选项(-static) 使用静态库。

注意: 在命令行中,静态库必须放在目标文件之后。

[root@localhost test]# gcc test.cpp -o test libexample.a -static
  • 代码优化选项

gcc 提供几种不同级别的代码优化方案,用“-Olevel”选项表示。level 取值可以是 0、1、2、3 和 s。默认 0 级,即不进行优化。典型的优化选项:
(1) -O 或-O1: 基本优化,使代码执行的更快

(2) -O2: 产生尽可能小和快的代码。如无特殊要求,不建议使用 O2 以上的优化。

(3) -Os:生成最小的可执行文件,适合用于嵌入式软件。

  • 调试选项及调试示例

gcc 支持数种调试选项: 

-g: 产生能被 GDB 调试器使用的调试信息。

举个例子,首先需要在编译时加上“-g”选项,操作步骤如下:

[root@localhost test]# arm-linux-gcc main.c -I inc -g -o main

GDB 调试示例:

(1) run 命令

调试运行,使用 run 命令开始执行被调试的程序;

run 命令的格式: run [运行参数]

(2) list 命令
列出源代码,使用 list 命令来查看源程序以及行号信息;

list 命令的格式: list [行号]

(3) 设置断点
1) break 命令,设置断点命令,break 命令的格式: break |

2) info break 命令,查看断点命令;

3) delete breakpoint 命令,删除断点命令;delete breakpoint 命令的格式: delete breakpoint

(4) 跟踪运行结果
1) print 命令,显示变量的值,print 命令的格式:print[/格式]
2) display 命令,设置自动显示命令,display 命令的格式: display
3) step 和 next 命令,单步执行命令,step 和 next 命令的格式:step  或 next

4) continue 命令,继续执行命令。

bd36bb79d6b813b7e39e3d90a25dc12b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值