在main()之前,IAR都做了啥

合集下载

IAR_使用最全方法

IAR_使用最全方法

软件介绍AVR?IAREmbeddedWorkbench?IDE用户手册的这部分包括以下章节:✍✍✍产品介绍✍✍✍已安装文件1.1产品介绍嵌入式IAREmbeddedWorkbench?是一个非常有效的集成开发环境(IDE),它使用户充分有效有效提一个可扩展的模块化的环境尽管嵌入式IAREmbeddedWorkbenchIDE可以提供完成一个成功工程所需的所有工具,但我们也认识到集成其他工具的必要性。

因此,IAREmbeddedWorkbenchIDE容易适应于用户喜欢的编辑器和源代码控制系统。

IARXLINKLinker可以输出多种格式,使用户可在第三方的软件上进行调试。

实时操作系统(RTOS)支持也可加载到产品中。

编译器,汇编器和连接器也可在命令行环境中运行,用户可以在一个已建好的工程环境中把它们作为外部工具使用。

特性嵌入式IAREmbeddedWorkbench是一个灵活的集成开发环境,使用户可以针对多种不同的目标处理器开发应用程序。

并为快速开发和调试提供便捷的Windows截面。

++源窗口管理为使用户充分而方便地控制窗口的位置,每个窗口都可停靠,用户就可以有选择地给窗口做上标记。

可停靠的窗口系统还通过一种节省空间方式使多个窗口可同时打开。

另外,重新分配窗口大小也很方便。

2文本编辑器集成化的文本编辑器可以并行编辑多个文件,并具有时兴编辑器所期望的所有编辑特性,包括无限次的撤销/重做和自动完成。

另外它还包含针对软件开发的特殊功能,比如关键字的着色(C/C++,汇编和用户定义等)、段缩进、以及对源文件的导航功能。

还可识别C语言元素(例如括号的匹配问题)。

下表指出另外的一些特性:✍✍✍上下文智能帮助系统可以显示DLIB库的参考信息;✍✍✍使用文本风格和色条指出C、C++和汇编程序的语法;✍✍✍强大的搜索和置换功能,包括多文件搜索;驱动C-SPY 驱动的概述,请参见第8页,IARC-SPY调试器系统。

Kinetis实战开发——IAR使用详解

Kinetis实战开发——IAR使用详解

Kinetis实战开发——IAR使用详解目前适合开发飞思卡尔Kinetis系列单片机的软件开发环境有IAR、Keil和CodeWarrior,三种软件的功能各有千秋。

本文档将介绍如何使用IAR开发Kinetis系列单片机,希望读者阅读本文档后能对IAR这款软件有所了解。

本文所使用的IAR开发环境的版本为IAR for ARM 6.30。

1.IAR功能介绍●IAR支持ARM汇编、C和C++三种语言的开发;●IAR软件本身集成了编译器,能将用户开发的工程编译成二进制文件,进而烧写到单片机的FLASH中;●IAR软件集成了当前主流仿真器的驱动,比如开发K60单片机时所使用的J-LINK和OSJTAG仿真器的驱动;2.IAR开发环境界面介绍打开IAR软件后,首先会进入IAR开发环境的主界面。

IAR主界面由菜单栏、工具栏、WorkSpace、编程界面和结果显示窗口(Message)组成,如图1.1所示。

下面我们将介绍每个部分的作用。

图1.1 IAR主界面2.1IAR菜单栏在IAR主界面中可以看到菜单栏中有7个选项,如图2.1所示。

图2.1 IAR菜单栏2.1.1F ile选项如图2.2所示,在File选项中包括如下子选项。

“New”可以新建空白文件和工作空间(WorkSpace);“Open”可以打开文件和工作空间(WorkSpace);“Save Workspace”和“Close Workspace”分别对应保存工作空间和关闭工作空间;“Recent Files”用于快速打开最近使用过的源文件;“Recent Files”用于快速打开最近使用过的工作空间。

图2.2 Files选项2.1.2E dit选项如图2.3所示,在Edit选项中,包括了最常用的复制、粘贴、重置和查找等通用的编辑类选项,同时也包括了一些IAR开发环境特殊的编辑功能。

图2.3 Edit选项接下来我们介绍一些比较常用的功能。

a)Find and Replace查找和替换功能查找和替换是我们在编程中使用最频繁的功能。

IAR主窗口与工具栏详细描述

IAR主窗口与工具栏详细描述

IAR主窗口与工具栏详细描述
宁波三维电测设备有限公司张婷婷 2018.10.18 主窗口:
Menu Bar:菜单栏,包含IAR所有操作及内容,在编辑模式和调试模式下存在一些不同。

Tool Bar工具栏:该窗口是一些常见的快捷按钮。

Workspace Window:工作空间窗口,一个工作空间可以包含多个工程,该窗口主要显示工作空间下面工程项目的内容。

Edit Window:编辑空间,代码编辑区。

Message Window:信息窗口,该窗口包括编译信息、调试信息、查找信息等一些信息的窗口。

Status Bar:状态栏:该窗口包含错误警告、光标行列等一些状态信息。

工具栏:
IAR的Tool Bar工具栏共有两个:Main主工具栏和Debug调试工具栏。

在编辑(默认)状态下只显示Main工具栏只显示,在进入调试模式后会显示Debug工具栏。

工具栏可以在通过菜单打开:View -> Tool Bar
在编辑(默认)状态下,只有主工具栏,这个工具栏里面内容也是在编辑状态下常用的快捷按钮。

PS:Download and Debug是下载代码之后再进行调试,Debug without Downloading:只调试不下载。

也就是说你之前下载过了代码,只需要再点击该按钮即可,否则会出现错误。

这两个按钮图标在编辑和调试模式下略有点差异,在调试模式下可以再次下载/调试。

调试工具栏调试工具栏是在程序调试时候才有效的一下快捷按钮,在编辑状态下,这些按钮是无效的。

Reset:复位
Run to Cursor:运行到光标行。

MDK main函数运行前的详细分析

MDK main函数运行前的详细分析

图 2-10 MAP 文件分析 0x0800 015D 地址是函数_scatterload_copy 的入口,该函数到底 copy 了什么 值呢?在此之前我们先要熟悉一下.map 文件 .map 文件是值包括了映像文件信息图和其它信息的一个映射文件, 该文件包 含了: (1) 从映像文件中删除的输入段中未使用段的统计信息,对应参数-remove; (2) 域符号映射和全局、局部符号及生成符号映射统计信息,对应参数 -symbol; (3) 映射文件的信息图,对应参数-map,该信息中包含映像文件中的每个加载 域、运行域和输入段的大小和地址,如 2-11 图、2-12 图所示:
图 2-19
经 过 该 函 数 处 理 得 : r0=0x2000 0098,r1=0x2000 0698,r2=0x2000 0298,r3=0x2000 0298。最后用户栈顶被设置成 0x2000 0698,完成了堆栈的初始 化工作,程序返回到 rt_entry_main
三、 总结
最终函数终于跳转到我们的 main 函数执行我们写的代码。 总结启动文件的整个过程,分为如下: (1) 系统初始化,包括对中断向量表的重新映射; (2) 加载 RW 段; (3) ZI 段清零; (4) 初始化用户堆栈; (5) 初始化微库(具体干什么我也不知道,屏蔽此处函数好像也能正常运行) ; (6) 调用 main 函数。
Main 函数运行前的分析(原创,转载请注明出处)
一、 启动文件的介绍
在 MDK 的启动文件 startup_stm32f10x_md_vl 中,该文件分别定义了栈段、 堆段、存放中断向量表的数据段、还有一个代码段 大小为 0x400 的栈段定义如图 1-1:
图 1-1 大小为 0x200 的堆段如图 1-2:

Keil程序运行main函数之前的汇编

Keil程序运行main函数之前的汇编

Keil开发的ARM程序main函数之前的汇编分析——BIN文件中RW段的数据移动系统平台:STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储;FLASH地址范围0x0800 0000 ~ 0x0808 0000,用于存放代码;片内存储地址范围0x2000 0000 ~ 0x2001 0000,用于存放数据;Cortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main 标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,开启C程序之旅,执行流程如图1所示。

图1 main函数之前的汇编程序执行流程图本文主要讨论RW段的移动,RW段就是程序中赋了初值的变量,它的搬移我看到过两种方式。

在BIN文件中,RO段和RW段之间有8个双字的Region$$Table,4个双字一组,分别用于完成RW段的搬移和ZI段的初始化。

(1)__scatterload_copy来完成此时RW段的内容保存到内存开始的地方,本文中是0x20000000,用这一方式完成后,内存中存放的不是RW数据的内容,而是一个地址。

这个地址是在FLASH中,即指向了其在RO段的地址,实际的内容是在RO段中。

(2)通过__uncompressed1实现RW是程序中初始化的变量,但是这些变量有可能初值是0,因此为了节省空间,实际在BIN文件中RW段是压缩过的。

调用__uncompressed1解压缩RW段的数据内容,并将其保存到内存开始的地方。

图2 BIN文件中压缩RW段内容图2是BIN文件中RW段的数据内容,影印部分显示,大小是164字节。

其中0x0001 C72C前面8个双字的内容是Region$$Table,将其列出如下。

0x0801 C72C BIN文件中RW段的开始地址0x2000 0000 RW段要存放到RAM中的地址0x0000 0334 要存放到RAM中的RW段数据大小0x0800 0184 执行函数__scatterload_copy或者__uncompressed1上面4个双字完成RW段的搬移。

IARFORAVR编译环境中启动代码和堆栈设置的分析

IARFORAVR编译环境中启动代码和堆栈设置的分析

IARFORAVR编译环境中启动代码和堆栈设置的分析1.例子1程序中仅包含一个空的main()函数,代码如下:#include <ioavr.h>int main(void){}此时对应的map文件显示:表中CSTACK的区域由编译环境中DATA STACK的值确定,起始位置是0060H,而RSTACK区域的起始地址就是CSTACK的最大地址+1,即RSTACK紧接着CSTACK,其大小由编译环境则为Return address stack中的值*2。

从0000-0025都是中断向量表的区域,从0026-0049才是程序代码中断向量表的区域如下图所示:从表中可以看出,上电复位后的第一条指令就转移到启动代码?C_STARTUP中。

程序代码如下图所示:在启动代码中,首先设置堆栈指针SP位009FH,这个值就是MAP文件中给出的RSTACK区域的最大地址。

然后将(R29,R28)寄存器对设置成0080H,这个值就是MAP文件中给出的RSTACK区域的最小地址。

由于在AVR中,当压栈时,堆栈指针进行减法,出栈时进行加法,所以栈顶就是009FH,实际上堆栈可使用的区域为0080到009FH。

这部分区域主要用来保存返回地址,因此在编译环境中也被称为返回地址的堆栈,而CSTACK则称为数据堆栈。

这个部分区域应该是用于局部变量的操作,因此要小心设置改值,否则会导致空间溢出。

2.例子2程序包含有一个main()函数,其中定义了一个10个字节的数组,如下图所示:int main(void){unsigned char i;char s[10];for(i=0;i<10;i++){s[i] = 0x55;}}这个程序编译后,生成的MAP图如下:从这里可以发现,没有CSTACK和RSRTACK没有发生变化。

启动代码部分如下所示:可以看出,也没有什么变化。

那么再来看看main()函数的汇编代码,如下图所示:通过读代码,可以看出R16用于存储局部变量i,用于for循环的计数。

IAR用法点滴

IAR用法点滴

IAR用法点滴程序固化后运行方式:程序开始运行后需要将RW 和ZI段搬移到RAM中去,程序下载进Flash中以后,上电后是怎样将RW ZI断搬移到RAM中去的?注意IAR和ADS在进行完.s文件的初始化以后都不是直接跳转到main函数去执行,IAR是跳转到?main中而ADS是跳转到__main函数中,在这些函数中根据icf文件的配置,将RW和ZI段搬移到icf文件规定的RAM区域中。

如果程序的运行时域是在片外RAM中,那程序是在什么时候对片外RAM控制器进行初始化呢?因为.s文件的开始部分是CODE RO的,不需要RAM空间,所以可以在.s文件中对片外RAM进行配置。

还有一个问题,这个问题是在硬件设计时必须注意的,如果需要程序固化在外部Flash中,必须注意外接的Flash必须是片子上电后默认片外总线就支持的片子。

程序在RAM中调试的运行方式为了调试的方便,程序有时候是不需要下载进flash进行调试,而是直接在RAM 中运行,将icf文件中的ROM 和RAM地址都设成硬件RAM的地址,将Flashloader 的使能关掉,那么程序就运行在RAM中了。

但是问题又产生了,因为有时我们想在外部RAM 中调试代码,所以片外RAM控制器需要在代码下载进RAM之前进行初始化,怎么能够实现呢?IAR是通过.mac文件实现的。

在程序下载之前先执行了。

mac文件中的程序,下面是一个例子execUserFlashInit(){__writeMemory32(0x1000ffef, 0xffe00000 , "Memory");__writeMemory32(0x0f000114, 0xE002C014, "Memory");}该例子是lpc初始化外部RAM的例子。

配置好了外部RAM就可以在里面跑代码了。

程序的IAR下载1.文件在片内Flash中下载运行这是最简单也是最常用的方式,一般的ARM芯片都会带有片内Flash,IAR会通过Flashloader将二进制的可执行文件下载到Flash中。

iar编译器使用指南

iar编译器使用指南

iar编译器使用指南(原创实用版)目录1.IAR 编译器的概述2.IAR 编译器的安装3.IAR 编译器的使用4.常见问题与解决方法正文【概述】IAR 编译器是一款功能强大的编译器,适用于多种处理器架构。

它能够将 C、C++语言源代码编译成高效的目标代码,广泛应用于嵌入式系统开发。

本文将为您介绍如何使用 IAR 编译器进行程序开发。

【安装】在使用 IAR 编译器之前,首先需要在电脑上安装它。

您可以从 IAR 官网下载对应版本的编译器,并按照安装向导的提示进行安装。

在安装过程中,请确保选择正确的处理器架构和相应的开发板支持包。

【使用】安装完成后,您可以使用 IAR 编译器编写、编译和调试程序。

以下是使用 IAR 编译器的基本步骤:1.创建一个新的项目:在 IAR Embedded Workbench 中,选择“新建项目”创建一个新的项目。

2.编写源代码:在新建的项目中,编写您的 C 或 C++代码。

3.编译程序:在 IAR Embedded Workbench 中,选择“编译”或按 F7 键,编译器将自动编译您的源代码。

4.调试程序:编译完成后,您可以使用 IAR Embedded Workbench 的调试功能对程序进行调试。

【常见问题与解决方法】在使用 IAR 编译器过程中,可能会遇到一些问题。

以下是一些常见问题的解决方法:1.编译器无法识别源代码文件:请确保您的源代码文件扩展名为.c 或.cpp,并检查文件路径是否正确。

2.编译器报错:遇到编译错误时,请仔细阅读错误信息,并检查您的代码。

常见的错误包括语法错误、拼写错误和库文件缺失等。

3.调试时程序无法运行:请确保您的目标系统已正确连接并启动。

同时,检查您的调试配置是否正确。

通过以上步骤,您应该能够熟练地使用 IAR 编译器进行嵌入式系统开发。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

[原创]在main()之前,IAR都做了啥?最近要在Cortex-M3上写一个简单的操作系统,打算使用IAR,为了写好启动代码,花了一些时间了解了IAR在main()以前做了些什么事。

首先系统复位时,Cortex-M3从代码区偏移0x0000'0000处获取栈顶地址,用来初始化MSP寄存器的值。

接下来从代码区偏移0x0000'0004获取第一个指令的跳转地址。

这些地址,是CM3要求放置中断向量表的地方。

这里是一个程序的启动区的反汇编:__vector_table:08004000 260008004002 200008004004 7E1D08004006 0800这个程序是由IAP程序来启动的,IAP程序获取0x0800'4000处的MSP值(0x20002600),并设置为MSP 的值,即主堆栈最大范围是0x2000'0000~0x2000'25FF。

接下来IAP程序获取0x0800'4004处的Reset_Handler的地址(0x0800'7E1D),并跳转到Reset_Handler()执行。

IAP在这里完全是模仿了Cortex-M3的复位序列,也就是说,在没有IAP的系统上,CM3只能从0x0800'0000获取MSP,从0x0800'0004获取第一条指令所处地址。

而IAP就存在在0x0800'0000这个地址上,IAP的启动,已经消耗掉了这个复位序列,所以IAP要启动UserApp程序的时候,也是完全模仿Cortex-M3的复位序列的。

接下来我们看看复位后第一句指令——Reset_Handler()函数里有什么。

若我们使用的是ST公司标准外设库,那么已经有了现成的Reset_Handler,不过他是弱定义——P U B W E A K,可以被我们重写的同名函数覆盖。

一般来说,我们使用的都是ST提供的Reset_Handler,在V3.4版本的库中,可以在startup_stm32f10x_xx.s中找到这个函数:PUBWEAK Reset_HandlerSECTION .text:CODE:REORDER(2)Reset_HandlerLDR R0, =SystemInitBLX R0LDR R0, =__iar_program_startBX R0看来ST没有做太多的事,他只调用了自家库提供的SystemInit函数进行系统时钟、Flash读取的初始化,并把大权交给了__iar_program_start这个IAR提供的“内部函数”了,我们就跟紧这个__iar_program_start跳转,看看IAR做了什么,上面一段代码的反汇编如下:Reset_Handler:__iar_section$$root:08007E1C 4801 LDR R0, [PC, #0x4]; LDR R0, =SystemInit08007E1E 4780 BLX R0;BLX R008007E20 4801 LDR R0, [PC, #0x4];LDR R0, =__iar_program_start08007E22 4700 BX R0;BX R008007E24 6C6908007E26 080008007E28 7D8D08007E2A 0800细心的观众会发现地址是0x0800'7E1C,比我们查到的0x0800'7E1D差了1,这是ARM家族的遗留问题,因为ARM处理器的指令至少是半字对齐的(16位THUMB指令集 or 32位ARM指令集),所以PC指针的LSB是常为0的,为了充分利用寄存器,ARM公司给PC的LSB了一个重要的使命,那就是在执行分支跳转时,PC的LSB=1,表示使用THUMB模式,LSB=0,表示使用ARM模式,但在最新的Cortex-M3内核上,只使用了THUMB-2指令集挑大梁,所以这一位要常保持1,所以我们查到的地址是0x0800'7E1D(C=1100,D=1101),放心,我们的CM3内核会忽略掉LSB(除非为0,那么会引起一个fault),从而正确跳转到0x0800'7E1C。

从0x0800'7E20处的加载指令,我们可以算出__iar_program_start所处的位置,就是当前PC指针(0x0800'7E24),再加上4,即0x0800'7E28处的所指向的地址——0x0800'7D8D(0x0800'7D8C),我们跟紧着跳转,__iar_program_start果然在这里:__iar_program_start:08007D8C F000F88C BL __low_level_init08007D90 2800 CMP R0, #0x008007D92 D001 BEQ __iar_init$$done08007D94 F7FFFFDE BL __iar_data_init208007D98 2000 MOVS R0, #0x008007D9A F7FDFC49 BL main我们看到IAR提供了__low_level_init这个函数进行了“底层”的初始化,进一步跟踪,我们可以查到__low_level_init这个函数做了些什么,不是不是我们想象中的不可告人。

__low_level_init:08007EA8 2001 MOVS R0, #0x108007EAA 4770 BX LR__low_level_init出乎想象的简单,只是往R0寄存器写入了1,就立即执行"BX LR"回到调用处了,接下来,__iar_program_start检查了R0是否为0,为0,则执行__iar_init$$done,若不是0,就执行__iar_data_init2。

__iar_init$$done这个函数很简单,只有2句话,第一句是把R0清零,第二句就直接"BL main",跳转到main()函数了。

不过既然__low_level_init已经往R0写入了1,那么我们还是得走下远路——看看__iar_data_init2做了些什么,虽然距离main只有一步之遥,不过这中间隐藏了编译器的思想,我们得耐心看下去。

__iar_data_init2:08007D54 B510 PUSH {R4,LR}08007D56 4804 LDR R0, [PC, #0x10]08007D58 4C04 LDR R4, [PC, #0x10]08007D5A E002 B 0x8007D6208007D5C F8501B04 LDR R1, [R0], #0x408007D60 4788 BLX R108007D62 42A0 CMP R0, R408007D64 D1FA BNE 0x8007D5C08007D66 BD10 POP {R4,PC}08007D68 7C7808007D6A 080008007D6C 7C9C08007D6E 0800看来IAR迟迟不执行main()函数,就是为了执行__iar_data_init2,我们来分析分析IAR都干了些什么坏事~首先压R4,LR入栈,然后加载0x0800'7C78至R0,0x0800'7C9C至R4,马上跳转到0x0800'7D62执行R0,R4的比较,结果若是相等,则弹出R4,PC,然后立即进入main()。

不过IAR请君入瓮是自不会那么快放我们出来的——结果不相等,跳转到0x0800'7D5C执行,在这里,把R0指向的地址——0x0800'7C78中的值——0x0800'7D71加载到R1,并且R0中的值自加4,更新为0x0800'7C7C,并跳转到R1指向的地址处执行,这里是另一个IAR函数:__iar_zero_init2:__iar_zero_init2:08007D70 2300 MOVS R3, #0x008007D72 E005 B 0x8007D8008007D74 F8501B04 LDR R1, [R0], #0x408007D78 F8413B04 STR R3, [R1], #0x408007D7C 1F12 SUBS R2, R2, #0x408007D7E D1FB BNE 0x8007D7808007D80 F8502B04 LDR R2, [R0], #0x408007D84 2A00 CMP R2, #0x008007D86 D1F5 BNE 0x8007D7408007D88 4770 BX LR08007D8A 0000 MOVS R0, R0__iar_data_init2还没执行完毕,就跳转到了这个__iar_zero_inti2,且看我们慢慢分析这个帮凶——__iar_zero_inti2做了什么。

__iar_zero_inti2将R3寄存器清零,立即跳转到0x0800'7D80执行'LDR R2, [R0], #0x4',这句指令与刚才在__iar_data_init2见到的'LDR R1, [R0], #0x4'很类似,都为“后索引”。

这回,将R0指向的地址——0x0800'7C7C中的值——0x0000'02F4加载到R2寄存器,然后R0中的值自加4,更新为0x0800'7C80。

接下来的指令检查了R2是否为0,显然这个函数没那么简单想放我我们,R2的值为2F4,我们又被带到了0x0800'7D74处,随后4条指令做了如下的事情:1、将R0指向的地址——0x0800'7C80中的值——0x2000'27D4加载到R1寄存器,然后R0中的值自加4,更新为0x0800'7C84。

2、将R1指向的地址——0x2000'27D4中的值——改写为R3寄存器的值——0,然后R1中的值自加4,更新为0x2000'27D8。

3、R2自减44、检查R2是否为0,不为0,跳转到第二条执行。

不为,则执行下一条。

这简直就是一个循环!——C语言的循环for(r2=0x2F4;r2-=4;r!=0){...},我们看看循环中做了什么。

第一条指令把一个地址加载到了R1——0x2000'27D4是一个RAM地址,以这个为起点,在循环中,对长度为2F4的RAM空间进行了清零的操作。

那为什么IAR要做这个事情呢?消除什么记录么?用Jlink查看这片内存区域,可以发现这片区域是我们定义的全局变量的所在地。

相关文档
最新文档