附录三 嵌入式C程序的编译与调试

时间:2021-09-02 22:48:09

课程回顾

C语言库的特性和发展 C语言库的常用库函数 标准库函数的特色应用

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

附录三

附录三

嵌入式C程序的编译与调试 嵌入式C程序的编译与调试

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

预习检查

C语言的编译过程分哪几个阶段 嵌入式系统的编译过程分几个阶段 程序中具体有哪几个重要的段

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

课程目标

本章概述

重点

难点

主要描述从源代码编译成可执行文件的过程,以及在操作系统是怎

么运行的

本章目标

掌握C编译的预处理过程,

了解编译,链接的过程 了解程序是如何执行的,以及函数调用时发生了什么

编译的流程

函数调用的深入分析

操作系统是如何执行程序的

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

本章结构

C语言的编译与运行 C语言的编译与运行

嵌入式编译过程

嵌入式编译过程

C语言编译过程 C语言编译过程

C语言程序的运行 C语言程序的运行

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

               3.1 C语言编译

C语言编译器 C语言编译过程 Makefile

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                               3.1.1 C语言编译器 C语言是在70年代初问世的。一九七八年由美国电话

电报公司(AT&T)贝尔实验室正式发表了C语言。

早期的C语言主要是用于UNIX系统

目前最流行的C语言编译器有以下几种: GNU Compiler Collection 或称 GCC

Microsoft C 或称 MS C Borland Turbo C 或称 Turbo C

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                       3.1.2 C语言编译过程

编译:编译程序读取源程序(字符流),对之进行词法和语法的

分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程

序转换为机器语言,并且按照操作系统对可执行文件格式的要求

链接生成可执行程序。

C源程序头文件-->预编译处理(cpp)-->编译程序本身--> 优化程序-->汇编程序-->链接程序-->可执行文件

预处理

编译阶段

优化阶段

汇编过程

连接程序

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                     3.1.2.1 编译预处理 预处理:读取c源程序,对其中的伪指令(以#开头的指令)和特殊

符号进行处理。

伪指令主要包括以下四个方面:

宏定义指令

如 #define Name #undef

条件编译指令 如#ifdef,#ifndef,#else,#elif,#endif,

头文件包含指令

如#include "FileName"或者#include <FileName>等

特殊符号

如 LINE FILE

预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代 ,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出 文件。

这个文件的含义同没有经过预处理的源文件是相同的,但内容有所

不同。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                             3.1.2.2 编译阶段 预编译程序所要作得工作:

词法分析

语法分析,

翻译成等价的中间代码表示或汇编代码。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                           3.1.2.3 优化阶段 优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅

同编译技术本身有关,而且同机器的硬件环境也有很大的关系

中间代码的优化

不依赖于具体的计算机

主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制 条件、已知量的合并等)、复写传播,以及无用赋值的删除,

目标代码的生成优化

依赖于具体的计算机

充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次 数

对指令进行一些调整使目标代码比较短,执行的效率比较高

经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器 指令,方可能被机器执行

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                        3.1.2.4 汇编阶段 汇编过程实际上指把汇编语言代码翻译成目标机器指令

的过程

目标文件中所存放的也就是与源程序等效的目标的机器

语言代码。

目标文件由段组成

代码段 该段中所包含的主要是程序的指令。该段一般是可读和可执 行的,但一般却不可写。

数据段 主要存放程序中要用到的各种全局变量或静态的数据。一般 数据段都是可读,可写,可执行的。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                             3.1.2.4 汇编阶段 UNIX环境下主要有三种类型的目标文件:

可重定位文件 其中包含有适合于其它目标文件链接来创建一个可执 行的或者共享的目标文件的代码和数据。

共享的目标文件 这种文件存放了适合于在两种上下文里链接的代码 和数据。第一种事链接程序可把它与其它可重定位文件及共享的目标文 件一起处理来创建另一个目标文件;第二种是动态链接程序将它与另一 个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。

可执行文件 它包含了一个可以被操作系统创建一个进程来执行之 的文件。

汇编程序生成的实际上是第一种类型的目标文件。对于

后两种还需要其他的一些处理方能得到,这个就是链接

程序的工作了。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                        3.1.2.5 链接阶段

链接程序是将有关的目标文件彼此相连接,使得所有的

这些目标文件成为一个能够被操作系统装入执行的统一

整体。目标文件由段组成

链接处理可分为两种 :

静态链接 动态链接

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

              3.1.3 Makefile

makefile是用于自动编译和链接的 makefile能够纪录文件的信息,决定在链接的时候需要

重新编译哪些文件

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                3.2 嵌入式C程序的编译过程

创建过程 编译 链接 定址

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                            3.2.1 创建过程 源代码转换为可执行的二进制映像的过程

源文件都被编译或汇编到一个目标文件(object file) 可重定位程序(relocatable program) 重定址(relocation)的过程

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

             3.2.2 编译 编译器的工作主要是把用人可读的语言所书写

的程序,翻译为特定的处理器上等效的一系列

操作码。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                3.2.3 链接

创建过程 编译 链接 定址

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                3.2.4 定址

创建过程 编译 链接 定址

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                    3.3 程序运行 A.out及其传说

段 操作系统在a.out里干了什么 C语言运行在a.out里干了什么 函数调用时发生了什么 Auto和static关键字 Unix/Linux的堆栈段 MS-DOS的堆栈段

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                       3.3.1 A.out及其传说

A.out -----“assembler output(汇编程序输出)”的缩写形式

a.out文件格式分析

a.out 文件包含7 个section,格式如下: exec header(执行头部,也可理解为文件头部)

text segment(文本段)

data segment(数据段)

text relocations(文本重定位段) data relocations(数据重定位段) symbol table(符号表)

string table(字符串表)

a.out 是早期UNIX系统使用的可执行文件格式,由 AT&T 设计,现在基本上已被 ELF 文件格式代替

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

               3.3.2

段(segments) :是二进制文件中简单的区域,里面保存了

和某种特定类型(如符号表条目)相关的所有信息 段可以方便地映射到链接器在运行时可以直接载入的对

象中

段在正在执行的程序中是一块内存区域,每个区域都有

特定的目的

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                     3.3.3 操作系统在a.out里干了什么

为什么a.out要以段的形式组织 段可以方便地映射到链接器在运行时可以直接载入的对象中! 段在正在执行的程序中是一块内存区域,每个区域都有特定的目的

段特点

文本段包含序的指令

数据段包含经过初始化的全局和静态变量以及它们的值

堆栈段用于保存局部变量、临时数据、传递到函数中的参数

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                   3.3.4 C语言运行在a.out里干了什么 运行时数据结构种类

堆栈

活动记录(activation record)

数据 堆

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                                3.3.4 C语言运行在a.out里干了什么 堆栈段

堆栈段包含一种单一的数据结构——堆栈 一块动态内存区域,实现了一种“后进先出”的结构 sp,用于提示堆栈当前的顶部位置

堆栈段作用

堆栈为函数内部声明的局部变量提供存储空间

进行函数调用时,堆栈存储与此有关的一些维护性信息

堆栈也可以被用作暂时存储区

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                        3.3.4 C语言运行在a.out里干了什么

如何找到段的地址

例:

声明位于这些段的变量,并打印它们的地址

在不同的计算机架构和不同的操作系统中,堆栈的位置可能各不

相同

#include<stdio.h> main()

{

}

int i;

printf(”The stack top is near %p\n”,&i); return 0;

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                        3.3.5函数调用时发生了什么

跟踪调用链

C语言自动提供的服务 哪些函数调用了哪些函数 实现机制:堆栈中的过程活动记录

过程活动记录

是一种数据结构

支持过程调用

记录调用结束以后返回调用点所需要的全部信息

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                    3.3.6 Autostatic关键字 A.out及其传说

段 操作系统在a.out里干了什么 C语言运行在a.out里干了什么 函数调用时发生了什么 Auto和static关键字 Unix/Linux的堆栈段 MS-DOS的堆栈段

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                          3.3.7 Unix/Linux的堆栈段 堆栈会自动生长

堆栈段(stack segment)包括两部分:

堆(heap):供动态内存(通过malloc申请的)。堆在BSS区域的上方 ,随着程序不断申请内存,堆会向上增长,ps命令显示的进程占用内存 的大小也会随之变化。

栈(stack):就是维护函数调用的系统栈,函数的参数和本地变量( 除去静态变量)储存在这里。栈位于进程内存空间的最高段,并随着函 数的调用向下增长。函数回调时,栈向上收回,其中的参数和变量数据 作废。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

                                3.3.8 MS-DOS的堆栈段 在DOS中,在建立可执行文件时,堆栈的大小必须同时

确定,而且它不能在运行时增长。

确定堆栈大小的方法根据所使用的不同编译器而不同

在Microsoft编译器中,程序员可以把堆栈的大小作为一个链接器参数来 确定。

STACK: nnn 这个参数告诉Microsoft链接器为堆栈分配nnn字节。

Borland编译器则使用一个特殊名字的变量: unsigned int _stklen = 0x4000;/★16K堆栈+/

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

本章总结

C语言的编译与运行 C语言的编译与运行

嵌入式编译过程

嵌入式编译过程

C语言编译过程 C语言编译过程

C语言程序的运行 C语言程序的运行

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

描述C语言的编译过程

讲述嵌入式编译的过程,深

入讲述定址链接和定址

简单讲述C程序的运行特性