-
单片机启动流程分析
2020-11-07 14:40:28一 单片机启动流程概述 单片机上电后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤: 1.内核初始化; 2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数; 3.在复位中断函数中调用 ...一 单片机启动流程概述
单片机上电后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤:
1.内核初始化;
2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数;
3.在复位中断函数中调用 SystemInit 函数,初始化时钟,配置中断向量表等
4.调用 __main 函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数
5.跳转到main函数中执行二 内核初始化
在单片机上电后首先会进行一系列内核的初始化,关于这部分工作我们只需要了解即可,在内核初始化的过程中主要做了以下几件事情:
1.内核复位和NVIC寄存器部分清零;
2.内核设置堆栈:内核从向量表0地址读出堆栈地址,并设置主堆栈指针(SP_main);
3.设置PC和LR寄存器
a. LR设置未初始复位值0xFFFF FFFF
b. 单片机的内部硬件机制自动将PC指针定位到中断向量表的复位中断向量出,把复位中断函数Reset_Handler的地址赋值给PC指针,然后跳转执行Reset_Handler。三 复位中断函数 Reset_Handler
在内核复位的最后一步,将PC指针指向了复位中断向量,而复位中断服务函数中的内容才是我们真正需要关心的内容。查看IAR环境中的* .s 单片机汇编启动文件有以下一段内容:
Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit ;加载SystemInit的地址到寄存器R0中 BLX R0 ;跳转R0中的地址执行(执行SystemInit函数) LDR R0, =__main ;加载SystemInit的地址到寄存器R0中 BX R0 ;跳转R0中的地址执行(执行__main函数) ENDP
上面的代码就是Reset_Handler的中断服务函数,可以看到在服务中断函数中先使用 IMPORT声明了两个函数 __main,SystemInit,然后顺序跳转执行SystemInit和**__main**函数。下面我们再来了解一下这两个函数具体干了些什么事情:
SystemInit 函数:在system_stm32f4xx.c文件中我们可以看到该函数的定义,该函数主要干了以下两件事情:
1.初始化时钟:SYSCLK,HCLK,PCLK2 and PCLK1 prescalers
2.配置中断向量表:中断向量表的定位是在 Flash 还是 SRAM,是否需要偏移)
注意:可以通过system_stm32f4xx文件中的宏定义修改系统时钟频率(通过设置锁相环的相关系数),中断向量表的地址(位于SRAM还是Flsah,是否偏移,偏移地址多少等参数)__main()函数(在IAR中是 __iar_program_start ):
该函数被封装进了编译器的库中,所以不同的IDE该函数的名称有所区别,但所实现的功能大致类似:
1.完成全局变量/静态变量/常量的初始化和重定位工作:
a. 跳转进入__scatterload_rt2函数:通过设置四个寄存器来配置待copy内容(静态变量、全局变量、常量)的的加载域和运行域,设置待copy内容的大小,为后续__scatterload_cpy()函数服务。
b. 跳转进入__scatterload_cpy函数,完成静态变量、全局变量、常量的从flash到SRAM的重定位。
c. 跳转进入__scatterload_zeroinit函数,完成未初始化的全局变量的初始化。2.初始化堆栈(这里指程序栈)和库函数:
跳转进入__user_steup_stackheap函数:调用**__user_libspac__user_libspace**为C库保持了静态数据。这是一个96字节,0初始化的数据块,该块由C库创建。在C库初始化期间可以用来当做临时栈。再调用 __user_initial_stackheap 用户的初始化堆栈函数,实现用户的堆栈的配置,调用 _fp_init 和 __rt_fp_status_addr (C库函数) 两个函数调用实现浮点运算的支持。3.程序的跳转,进入main()函数:
跳转进入用户的main函数注意:
- 未初始化和初始值为零的全局变量,静态变量一般在RAM中, 初始值不为零的全局变量/静态变量 一般在FLASH中。
- 因为Flash不能随机写(只能写0,不能写1),所以一般会在程序运行之前将初始值不为零的全局变量重定位到RAM中。
- 全局变量和常量的地址在编译时都已经被分配好了(所以能够在 .map 文件中看到), 而局部变量则是程序运行时在栈中创建的,栈空间大小可以在IDE中设置。
- 单片机启动时,不需要用将代码从ROM搬移到RAM ,而 ARM 则需要。单片机程序执行的过程分三个步骤:取执行->分析指令->执行指令。取指令的任务是:根据 PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从 RAM 存取相关数据。要知道RAM取数的速度是远高于ROM的,但是单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。而ARM不同,CPU运行的频率高,远大于从 ROM读写的速度,所以一般有大型的操作系统时,都需要将代码部分拷贝到RAM中再执行。
-
STM8单片机启动流程彻底探究--基于IAR开发环境
2016-08-09 15:16:00 -
单片机启动流程和存储架构详解
2019-11-07 00:26:521. ECU启动流程 2. 存储空间解析 3. TC397单片机的Memory Map和一些备注 1. ECU启动流程 图总比文字直观: 如上图所示,上电以后其实就三步: "运行ROM的启动函数 -- 跳转到FLASH里...最近在给公司的ADAS DCU做内存分配(Memory Allocation),在这儿记录一下相关知识点,也算是给中文社区做贡献了。
目录:
1. ECU启动流程
2. 存储空间解析
3. TC397单片机的Memory Map和一些备注
1. ECU启动流程
图总比文字直观:
如上图所示,上电以后其实就三步: "运行ROM的启动函数 -- 跳转到FLASH里的Startup函数 -- 跳转到我们熟悉的main函数" 。 所以FLASH里的Startup函数其实才是最先执行,且用户可以修改的函数。只是它一般都被封装好了,所以才没有接触到。
如果你想写BootLoader,就在Startup函数的基础上改就ok了。
2. 存储空间解析
以下将对上面那张图的PFLASH,DFLASH等名词进行解释:
重要且有用的:
2.1 掉电后数据不会消失的FLASH,EEPROM
PFLASH: Program Flash用来存程序,价格便宜,配的容量也大,我用的这款足有16M
DFLASH: Data Flash用来存用户数据,虽然叫Flash其实它是EEPROM,成本比FLASH高,我这款才1M多
FLASH 和EEPROM的最大区别是FLASH按扇区(section)擦写,用来存储程序这种大但不太频繁更改的data,成本低。EEPROM则按字节(Byte)擦写,存储用户数据这种小的,零碎的,总是在变的data时,擦写速度快。
2.2 掉电后数据会消失的RAM
RAM:速度快,甚至会比Flash快50%以上。由于RAM空间有限,单片机运行的时候,程序存储在flash,但数据会存储在RAM,即CPU从flash中取指令,从RAM中抓数据。
重要但没啥用的:【直接转到第三章如果你赶时间】
扩展阅读:
a: 当然你也可以可以通过#pragma CODE_SECTION等将程序先从Flash拷到RAM里面,再在RAM里面运行,来提升运行速度。详见Running an Application from Internal Flash Memory 第四章“Copying Sections from Flash to RAM” [1]
b: 冯诺依曼,哈佛结构: [2]
2.3 链接文件(Linker File)总的来说linker file用来定义数据和代码具体存放在哪一块。比如它会规定存储在Flash的启动函数_START()的存储地址和BootROM里面reset vector内预设的地址匹配,这样复位以后就总会从启动函数_START()开始执行
- 即reg.h 里面将寄存器的地址重命名,所以向寄存器写其实就等于向该地址赋值
- 而link file里面则是将函数和变量存在哪个地址做了规定
具体定义见下图:
这张图进一步解释了linker file在存储中的作用[3] :
3. TC397单片机的Memory Map和一些备注
先来一张从用户手册里拿来的单片机Memory Map:
可以看到:
1. 对这款6核ECU,core0到5都有自己的专属FLASH,大小为3M(core5是1M),读取它有专属的接口FPIn,速度快
2. 每个core内部都有16k的program cache和16k的data cache。 PSPR和DSPR稍大,看起来是2级缓存
3. 这6个core没有太大的区别,唯一就是core0和core1的DSPR(data scrachpad RAM)大一些。240KB,其他的core是96KB
4. 可以用的RAM还有LMU,DAM和4M的EMEM。但根据datasheet,DAM不支持ASIL B及以上的软件【becasue of hardware safety mechanism】
5. 对于第一条里提到的FLASH,对于同一块物理存储空间。它们可以在地址0x8000,0000通过总线进行cache access,也可以在地址0xA000,0000通过总线进行non-cache access, 这是比较有意思的
6. 因为是TC397 -ADAS,所以有额外的EMES,SPU,RIF,CIF以及扩展的HSM
Reference:
1. http://www.ti.com/lit/an/spra958l/spra958l.pdf
2. https://blog.csdn.net/jj163zhuangzi/article/details/47088843
3. http://downloads.ti.com/docs/esd/SLAU131U/introduction-to-sections-stdz0691509.html
-
单片机启动流程文件startup_device.s
2019-04-01 15:55:11MODULE ?cstartup ;; Forward declaration of sections. SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start EXTERN S...MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
EXTERN __iar_program_start
EXTERN SystemInit
EXTERN g_bootloaderTree
PUBLIC __vector_table
PUBLIC __vector_table_0x1c
PUBLIC __Vectors
PUBLIC __Vectors_End
PUBLIC __Vectors_Size【1】MODULE 控制指令是用来标记 modules 源码的开始和结束,后边的 ?cstartup 是模块的名字,此文档的最后的 END 表明模块的结束
【2】SECTION 指令是声明段,一个段不能同时包含 public symbol 和 pubweak symbol ,模块只有在相同的名字的模块没有被链接进来的时候才会被链接进来。
语法格式:SECTION section:type [flag] [(align)]
align,是用于指定地址对齐到 2^align,他的取值是 0 到 30
flag,取值NOROOT、ROOT、REORDER、NOREORDER,默认是ROOT,NOROOT表示如果这个段中的符号没有被引用,将会被连接器舍弃,即可被优化。ROOT表示不可被优化。REORDER表示开始一个新的名字是 section 的段(section),NOREORDER表示开始一个新的名字为 section 的片段(fragment),多个片段组成一个段(section)
type,memory 的类型,取值是 CODE、CONST、DATA
section,段的名字
【3】EXTERN 用导入其他模块的 symbol(符号)
【4】PUBLIC 导出 symbol(符号)【1】MODULE 控制指令是用来标记 modules 源码的开始和结束,后边的 ?cstartup 是模块的名字,此文档的最后的 END 表明模块的结束
【2】SECTION 指令是声明段,一个段不能同时包含 public symbol 和 pubweak symbol ,模块只有在相同的名字的模块没有被链接进来的时候才会被链接进来。
语法格式:SECTION section:type [flag] [(align)]
align,是用于指定地址对齐到 2^align,他的取值是 0 到 30
flag,取值NOROOT、ROOT、REORDER、NOREORDER,默认是ROOT,NOROOT表示如果这个段中的符号没有被引用,将会被连接器舍弃,即可被优化。ROOT表示不可被优化。REORDER表示开始一个新的名字是 section 的段(section),NOREORDER表示开始一个新的名字为 section 的片段(fragment),多个片段组成一个段(section)
type,memory 的类型,取值是 CODE、CONST、DATA
section,段的名字
【3】EXTERN 用导入其他模块的 symbol(符号)
【4】PUBLIC 导出 symbol(符号)
DATA ; DATA 表示下边中的标签是 32 位的标签
__vector_table
DCD sfe(CSTACK) ; sfe 指令作用是返回栈的结尾
DCD Reset_Handler
DCD NMI_Handler ;NMI Handler
DCD HardFault_Handler ;Hard Fault Handler
DCD MemManage_Handler ;MPU Fault Handler
DCD BusFault_Handler ;Bus Fault Handler
DCD UsageFault_Handler ;Usage Fault Handler
__vector_table_0x1c
DCD g_bootloaderTree ;Reserved
DCD 0 ;Reserved
DCD 0 ;Reserved
DCD 0 ;Reserved
DCD SVC_Handler ;SVCall Handler
DCD DebugMon_Handler ;Debug Monitor Handler
DCD 0 ;Reserved
DCD PendSV_Handler ;PendSV Handler
DCD SysTick_Handler ;SysTick Handler
;External Interrupts
DCD DMA0_DMA16_IRQHandler ;DMA Channel 0, 16 Transfer Complete
DCD DMA1_DMA17_IRQHandler ;DMA Channel 1, 17 Transfer Complete
DCD DMA2_DMA18_IRQHandler ;DMA Channel 2, 18 Transfer Complete
DCD DMA3_DMA19_IRQHandler ;DMA Channel 3, 19 Transfer Complete
DCD DMA4_DMA20_IRQHandler ;DMA Channel 4, 20 Transfer Complete
DCD DMA5_DMA21_IRQHandler ;DMA Channel 5, 21 Transfer Complete
DCD DMA6_DMA22_IRQHandler ;DMA Channel 6, 22 Transfer Complete
DCD DMA7_DMA23_IRQHandler ;DMA Channel 7, 23 Transfer Complete
DCD DMA8_DMA24_IRQHandler ;DMA Channel 8, 24 Transfer Complete
DCD DMA9_DMA25_IRQHandler ;DMA Channel 9, 25 Transfer Complete
DCD DMA10_DMA26_IRQHandler ;DMA Channel 10, 26 Transfer Complete
DCD DMA11_DMA27_IRQHandler ;DMA Channel 11, 27 Transfer Complete
DCD DMA12_DMA28_IRQHandler ;DMA Channel 12, 28 Transfer Complete
DCD DMA13_DMA29_IRQHandler ;DMA Channel 13, 29 Transfer Complete
DCD DMA14_DMA30_IRQHandler ;DMA Channel 14, 30 Transfer Complete
DCD DMA15_DMA31_IRQHandler ;DMA Channel 15, 31 Transfer Complete
DCD DMA_Error_IRQHandler ;DMA Error Interrupt
DCD MCM_IRQHandler ;Normal Interrupt
DCD FTFE_IRQHandler ;FTFE Command complete interrupt
DCD Read_Collision_IRQHandler ;Read Collision Interrupt
DCD LVD_LVW_IRQHandler ;Low Voltage Detect, Low Voltage Warning
DCD LLW_IRQHandler ;Low Leakage Wakeup
DCD WDOG_EWM_IRQHandler ;WDOG Interrupt
DCD RNG_IRQHandler ;RNG Interrupt
DCD I2C0_IRQHandler ;I2C0 interrupt
DCD I2C1_IRQHandler ;I2C1 interrupt
DCD SPI0_IRQHandler ;SPI0 Interrupt
DCD SPI1_IRQHandler ;SPI1 Interrupt
DCD I2S0_Tx_IRQHandler ;I2S0 transmit interrupt
DCD I2S0_Rx_IRQHandler ;I2S0 receive interrupt
DCD Reserved46_IRQHandler ;Reserved interrupt 46
DCD UART0_RX_TX_IRQHandler ;UART0 Receive/Transmit interrupt
DCD UART0_ERR_IRQHandler ;UART0 Error interrupt
DCD UART1_RX_TX_IRQHandler ;UART1 Receive/Transmit interrupt
DCD UART1_ERR_IRQHandler ;UART1 Error interrupt
DCD UART2_RX_TX_IRQHandler ;UART2 Receive/Transmit interrupt
DCD UART2_ERR_IRQHandler ;UART2 Error interrupt
DCD UART3_RX_TX_IRQHandler ;UART3 Receive/Transmit interrupt
DCD UART3_ERR_IRQHandler ;UART3 Error interrupt
...........
DCD PORTA_IRQHandler ;Port A interrupt
DCD PORTB_IRQHandler ;Port B interrupt
DCD PORTC_IRQHandler ;Port C interrupt
DCD PORTD_IRQHandler ;Port D interrupt
DCD PORTE_IRQHandler ;Port E interrupt
DCD SWI_IRQHandler ;Software interrupt
DCD SPI2_IRQHandler ;SPI2 Interrupt
DCD UART4_RX_TX_IRQHandler ;UART4 Receive/Transmit interrupt
DCD UART4_ERR_IRQHandler ;UART4 Error interrupt
DCD Reserved84_IRQHandler ;Reserved interrupt 84
DCD Reserved85_IRQHandler ;Reserved interrupt 85
DCD CMP2_IRQHandler ;CMP2 interrupt
DCD FTM3_IRQHandler ;FTM3 fault, overflow and channels interrupt
DCD DAC1_IRQHandler ;DAC1 interrupt
DCD ADC1_IRQHandler ;ADC1 interrupt
DCD I2C2_IRQHandler ;I2C2 interrupt
DCD CAN0_ORed_Message_buffer_IRQHandler ;CAN0 OR'd message buffers interrupt
DCD CAN0_Bus_Off_IRQHandler ;CAN0 bus off interrupt
DCD CAN0_Error_IRQHandler ;CAN0 error interrupt
DCD CAN0_Tx_Warning_IRQHandler ;CAN0 Tx warning interrupt
DCD CAN0_Rx_Warning_IRQHandler ;CAN0 Rx warning interrupt
DCD CAN0_Wake_Up_IRQHandler ;CAN0 wake up interrupt
DCD SDHC_IRQHandler ;SDHC interrupt
DCD ENET_1588_Timer_IRQHandler ;Ethernet MAC IEEE 1588 Timer Interrupt
DCD ENET_Transmit_IRQHandler ;Ethernet MAC Transmit Interrupt
DCD ENET_Receive_IRQHandler ;Ethernet MAC Receive Interrupt
DCD ENET_Error_IRQHandler ;Ethernet MAC Error and miscelaneous Interrupt
DCD LPUART0_IRQHandler ;LPUART0 status/error interrupt
DCD TSI0_IRQHandler ;TSI0 interrupt
DCD TPM1_IRQHandler ;TPM1 fault, overflow and channels interrupt
DCD TPM2_IRQHandler ;TPM2 fault, overflow and channels interrupt
DCD USBHSDCD_IRQHandler ;USBHSDCD, USBHS Phy Interrupt
DCD I2C3_IRQHandler ;I2C3 interrupt
DCD CMP3_IRQHandler ;CMP3 interrupt
DCD USBHS_IRQHandler ;USB high speed OTG interrupt
DCD CAN1_ORed_Message_buffer_IRQHandler ;CAN1 OR'd message buffers interrupt
DCD CAN1_Bus_Off_IRQHandler ;CAN1 bus off interrupt
DCD CAN1_Error_IRQHandler ;CAN1 error interrupt
DCD CAN1_Tx_Warning_IRQHandler ;CAN1 Tx warning interrupt
DCD CAN1_Rx_Warning_IRQHandler ;CAN1 Rx warning interrupt
DCD CAN1_Wake_Up_IRQHandler ;CAN1 wake up interrupt
DCD DefaultISR ;116
........
DCD DefaultISR ;232
DCD DefaultISR ;233
DCD DefaultISR ;234
DCD DefaultISR ;235
DCD DefaultISR ;236
DCD DefaultISR ;237
DCD DefaultISR ;238
DCD DefaultISR ;239
__Vectors_End【1】DATA 表示下边中的标签是 32 位的标签,THUMB 表示下边的标签是 16 位的标签,所谓的标签是 地址的别名,不占用代码空间,给编译器看的.
【2】 DCD 是数据定义或者 重定位指令,为的是定义一个值,或者保留 memory,DCD 别名是 DC32,用于声明一个 32 位的常量,这部分是中断向量表的内容,需要注意的是,他们的顺序不能改变,此部分会放到 flash 的最开始部分,当系统启动的时候会加载前另个地址,第一个地址是 c 程序的栈的栈顶地址,第二个地址是向量表的开始地址,中断发生时会根据向量表的首地址和偏移量来找到程序的入口
【3】sfe 指令作用是返回栈的结尾,因为栈的增长方向是反方向的
-
[东拼西凑]STM32单片机启动流程及RAM和Flash的配置关系和堆栈溢出现象
2019-01-08 21:53:59开头的话: 之前一直用现成的LED工程demo,改改就上,也...一、STM32上电启动 BOOT1 BOOT0 启动方式 X 0 从STM32内置flash启动,JTAG或者SWD固化程序位置 1 1 从STM32内置SRAM启动,由于SRAM没有程序存储能... -
STM32系列单片机的启动流程
2015-11-04 21:09:22M3系列内核与早期的ARM9/ARM11的启动动作不同,启动地址本身不再偏移,而是映射不同空间到0地址实现不同方式启动。 -
stm8启动流程
2013-06-08 09:46:16该文档为stm8单片机启动流程分析,对有需要做单片机iap升级,flash操作很有帮助。 -
uboot启动流程_AURIX TC3xx单片机介绍-启动过程介绍2
2020-12-03 23:31:48AURIX TC377,TC387,TC397用户启动程序流程用户启动程序是在Boot Firmware之后运行的程序(即用户程序里的第一级Boot Loader,类似Linux的Uboot),初始化过程是CPU0完成的。用户可以根据不同的复位事件来选择不同... -
单片机中程序和数据存放位置、与电脑内存和硬盘的类比,单片机和计算机程序启动流程对比
2021-03-04 16:50:29单片机程序在内存和FLASH中的空间分配3.计算机启动过程 1.ROM、RAM和闪存 ROM、RAM和闪存的区别 2.单片机程序在内存和FLASH中的空间分配 https://blog.csdn.net/fengruoying93/article/details/97613986 3.计算机... -
ARM启动流程及启动代码分析
2021-01-20 11:06:33一、ARM的启动流程 基于ARM的芯片多数为复杂的片上系统。这种复杂系统里的多数硬件模块都是可配置的。需要由软件来设置其需要的工作状态。因此在用户的应用程序之前,需要由专门的一段代码来完成对系统的初始化。... -
STM32启动流程
2020-11-18 16:47:00STM32启动流程前言一、STM32的三种启动方式?二、启动流程图总结 前言 先阐述一个问题,嵌入式应用程序以C语言为主,因此main函数成为程序运行的起点,但是我们忽略了一个问题:MCU(微控制器/单片机)上电之后,是... -
C51 启动流程总结
2019-03-08 21:25:11简单介绍下 C51 内存框架及启动流程吧 相关参考资料: C51.pdf 《单片机原理与应用及 C51 编程技术》 《基于单片机 8051 的嵌入式开发指南》 硬件框架 存储框架 由上面知道了 C51 硬件复位后,会执行到... -
4412启动流程
2018-10-04 19:56:30单片机属于微控制器,也就是MCU ARM9,ARM11,A8,A9属于微处理器,也就是MPU 低端的ARM,比如cortex-M系列也属于MCU MCU 和 MPU 的区别 MPU多了两个部件,CACHE 和 MMU (高速缓存和内存管理单元) 事实上,... -
STC12系列单片机冷启动、热启动
2013-04-16 15:33:56冷启动——是指在断电状态下重新上电。冷启动,是在下载程序开始时,为了是单片...可通过查询PCON寄存器中的POF位来判断,单片机上电冷启动后,POF位变为1,可由软件清0 实际判断流程图: 怎样才能产生冷启 -
4412启动流程和字符设备驱动概念
2019-11-19 11:08:454412启动流程单片机和嵌入式的区别上电执行iROMUboot启动:uboot 加载linux内核zImage,挂载文件系统linux内核之间和文件系统之间的关系uboot iROM–>BL1—>BL2---->uboot---->zImage---->挂接文件... -
keil创建工程及单片机程序执行流程
2019-09-14 09:43:20一、单片机程序执行流程: 1、startup_stm32f10x_md.s启动系统 2、system_stm32f10x.c进行系统初始化 3、最后通过引导程序将程序引导至主函数开始执行 二、keil创建工程: 1、首先,创建项目文件,在此路径下... -
rt-thread启动流程分析
2019-08-27 21:21:48经常习惯使用裸机系统,所以在做集成的时候往往会有很多不方便的地方。 在现在火热的物联网生态...51单片机老师说:系统上电后,有外部RC保证NRST引脚处于一定时长的低电平时间,使单片机完成复位操作…… 那么在st... -
STM32再学习——启动流程分析
2017-09-13 15:13:08STM32再学习——启动流程分析 我们写嵌入式程序,基本上采用C语言来编写,以main( )作为程序的入口。但实际上,mian()并不是最先要执行的,在这之前需要做一些基本的工作,如堆、栈的定义;main函数的复位...