ads1.2使用

ARM汇编语言上机过程

来源: MCU嵌入式领域整理

汇编语言上机过程 
用ARM汇编语言编写的源程序,要使之运行必须经过以下几个步骤: 
1.编辑汇编源程序,保存为文件名后缀是“.s”的文件; 
2.调用汇编程序对源程序进行汇编,生成目标文件; 
3.连接目标文件,生成可以放进ARM软件仿真器进行调试的映象文件或者可下载到ARM的目标板执行的二进制文件; 
4.对生成的最终文件进行调试。 

ARM的开发工具ADS1.2 
ADS1.2是ARM公司推出的一套ARM汇编、C、C++的集成开发环境。 
包含了几个有用的开发工具,包括: 
(1)CodeWarrior IDE for the ARM Developer Suite :为ARM的程序员管理、开发软件工程项目提供了一个简单直观、灵活的用户界面。 
(2)AXD Debuger:AXD是一个功能强大、使用方便的调试器。 

编辑汇编语言源程序 
可以使用简单的Windows自带的记事本程序来编辑ARM的汇编程序: 
单击开始菜单程序附件记事本 
敲入汇编代码保存为.s文件 
也可以使用CodeWarrior IDE来编辑汇编程序: 
单击File菜单的New菜单项 单击Project标签页 单击工具栏的New Text按钮 敲入汇编代码保存为hello.s文件 单击Project菜单,选择“Add *.s to project” 

编译汇编语言源程序 
ARM的编译器有如下几种: 
(1)armcc:ARM C编译器,具有优化功能,兼容ANSI C 
(2)tcc:Thumb的C编译器,同样具有优化功能兼容ANSI C 
(3)armcpp:ARM C++编译器,遵循ANSI C++或者EC++标准 
(4)tcpp:Thubm的C++编译器,遵循ANSI C++或者EC++标准 
(5)armasm:支持ARM和Thumb的汇编器 
这些编译器输出的是ELF(excutive linked file)格式的目标文件,可以包括RAWF2格式的调试信息。同时通过特殊的控制选项可以输出汇编语言文件或者列表文件。 

连接装配汇编程序 
使用armlink程序对ARM的汇编源程序进行连接,它也可以将多个.o目标文件连接生成最终的可执行文件。 术语 : 
映像文件(image):是指一个可执行文件,在执行的时候被加载到处理器中。一个映像文件可以有多个线程。它是ELF(Executable and linking format)格式的。 
段(section):描述映像文件的代码或数据块。 
域(Regions):在一个映像文件中,一个域包含了1~3个输出段。多个域组织在一起,就构成了最终的映像文件。 
加载时地址:映像文件载入存储器时的地址。 
运行时地址:映像文件运行时的地址。 

汇编程序的运行 
两种运行方法: 
(1)生成的*.axf文件是ARM 的ELF 格式的可执行映像文件;这个文件可以载入AXD 进行仿真调试。使用armsd在终端模拟它在ARM目标机上的运行。 
(2)也可以直接在CodeWarrior IDE中运行映像文件:在Project窗口中单击Run按钮,可以执行AXD并在Console窗口中看到运行结果。 
在AXD上调试成功之后,我们可以通过fromelf 工具将ELF 文件转换为二进制格式文件下载到目标板执行 

汇编程序的调试 
使用AXD进行调试 :编译、连接成功之后,可以点击project 窗口的debug按钮启动AXD进行调试: 
主框架窗口上方的调试工具栏有几个常用按钮: 
go:使程序运行直到下一个断点停止 
step in:进入函数内部运行 
step:单步调试,每次移动一行 
step out :跳出循环或函数 
run to cursor:运行到光标所在的位置然后停止。 

ADS下程序设计举例(一) 
使用LDR指令读取0x40003100上的数据,将数据加1,若结果小于10则使用STR指令把结果写回原地址,若结果大于等于10,则把0写回原地址。然后再次读取0x40003100上的数据,将数据加1,判断结果是否小于10……周而复始循环 

ADS下程序设计举例(一) 
COUNT EQU 0x40003100 ; 定义一个变量,地址为 ;0x40003100 
AREA Example2,CODE,READONLY ; 声明代码段Example2 
ENTRY ; 标识程序入口 
CODE32 ; 声明32位ARM指令 
START LDR R1,=COUNT ; R1 <= COUNT 
MOV R0,#0 ; R0 <= 0 
STR R0,[R1] ; [R1] <= R0,即设置COUNT为0 
LOOP LDR R1,=COUNT 
LDR R0,[R1] ; R0 <= [R1] 
ADD R0,R0,#1 ; R0 <= R0 + 1 
CMP R0,#10 ; R0与10比较,影响条件码标志 
MOVHS R0,#0 ; 若R0大于等于10,则此指令执行,R0 <= 0 
STR R0,[R1] ; [R1] <= R0,即保存COUNT 
B LOOP 
END 

ADS下程序设计举例(二) 
编写一个汇编程序文件和一个C程序文件。汇编程序的功能是初始化堆栈指针和初始化C程序的运行环境,然后跳转到C程序运行,这就是一个简单的启动程序。 
C程序使用加法运算来计算1+2+3+4+……+(N-1)+N的值(N>0) 

ADS下程序设计举例(二) 
#define uint8 unsigned char 
#define uint32 unsigned int 
#define N 100 
uint32 sum; 
// 使用加法运算来计算1+2+3+...+(N-1)+N的值。(N>0) 
void Main(void) 
{ uint32 i; 
sum = 0; 
for(i=0; i<=N; i++) 
{ sum += i; 

while(1); 


ADS下程序设计举例(二) 
; 启动文件。初始化C程序的运行环境,然后进入C程序代码。 
IMPORT |Image$$RO$$Limit| ;得到RW数据源的起始地址 
IMPORT |Image$$RW$$Base| ; RW区在RAM里的执行区起始地址 
IMPORT |Image$$ZI$$Base| ; ZI区在RAM里面的起始地址 
IMPORT |Image$$ZI$$Limit| ; ZI区在RAM里面的结束地址 
IMPORT Main ; 声明C程序中的Main()函数 
AREA Start,CODE,READONLY ; 声明代码段Start 
ENTRY ; 标识程序入口 
CODE32 ; 声明32位ARM指令 
Reset LDR SP,=0x40003F00 
; 初始化C程序的运行环境 
LDR R0,=|Image$$RO$$Limit| 
LDR R1,=|Image$$RW$$Base| 
LDR R3,=|Image$$ZI$$Base| 

ADS下程序设计举例(二) 
CMP R0,R1 
BEQ LOOP1 
LOOP0 CMP R1,R3 
LDRCC R2,[R0],#4 
STRCC R2,[R1],#4 
BCC LOOP0 
LOOP1 LDR R1,=|Image$$ZI$$Limit| 
MOV R2,#0 
LOOP2 CMP R3,R1 
STRCC R2,[R3],#4 
BCC LOOP2 
B Main ; 跳转到C程序代码Main()函数 
ENd 

ADS下程序设计举例(二) 
程序实现了RW数据的拷贝和ZI区域的清零功能。其中引用到的4个符号是由链接器第一输出的。 
|Image$$RO$$Limit|:表示RO区末地址后面的地址,即RW数据源的起始地址。 
|Image$$RW$$Base|:RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址。 
|Image$$ZI$$Base|:ZI区在RAM里面的起始地址。 
|Image$$ZI$$Limit|:ZI区在RAM里面的结束地址后面的一个地址。 
程序先把ROM里|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达。 
|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit| 

ADS下程序设计举例(二) 
映像一开始总是存储在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分是必须转移到可写的RAM里去。所谓应用程序执行环境的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零。 

ARM的启动代码 
一般的嵌入式系统在主程序执行之前都需要执行一些初始化的过程以创造嵌入式程序运行的环境。 
尤其是一些高级的嵌入式系统,由于核心芯片使用内存映射、内存保护等机制以及编程使用高级语言C,C++甚至JAVA语言,都需要先创建一个适合程序运行的硬件环境,然后初始化或者配置或者剪裁run-time library, 
这些工作都必须在主程序运行前完成,所以一个startup程序或者程序组对于一个嵌入式系统来说是非常重要的。 

ARM程序的工作过程 
首先由各种source file经过编译产生object文件 
然后object文件经过链接生成Image文件,然后通过ICE的方法,根据描述文件的指定下载到目标板上的固态存储器指定地址当中比如flash, EEPROM, ROM等等。 

ARM程序的工作过程 
程序执行之前,根据某些描述文件,将需要读写数据的部分读出放入动态存储器比如RAM当中,然后程序从ROM开始执行 
同时ARM结构的异常向量表规定放在地址为0x00000000开始的地址空间上,而一般的CPU为了提高异常相应速度,会将这个向量段remap到其他的RAM当中,所以在描述文件当中必须精确指定异常向量跳转程序的地址到remap的地方。 

ARM程序的工作过程 
其他工作 
系统工作时钟 
总线频率 
runtime-library 
stack 

ARM Image的结构 
一个ARM Image structure由linker在以下几个方面定义: 
组成它的regions 和 output sections 
当Image 下载的时候这些regions 和 sections 在内存中的位置 
   当Image 执行时这些regions和sections在内存中的位置 

ARM Image的组成 

ARM Image的组成 
Input section 有几种属性,分别为readonly,read-write,zero-initialized。分别称为RO,RW和ZI 
属性来源于AREA后的attr属性。 比如CODE是RO, 
DATA是RW, 
NOINT默认为ZI,即用0值初始化,但是可以选择不进行0值初始化。 
ZI属性仅仅来源于SPACE, DCB, DCD, DCDU, DCQ, DCQU, DCW, 或者DCWU。由以上定义,ZI属性的包含于RW属性,它是有初始值的RW数据。又例如在C语言中,代码为RO,静态变量和全局变量是RW,ZI的。 

Image 的Load view 和 execution view 

制定Memory map 

制定Memory map 
这些都是linker预先定义的外部变量,在使用的时候可以用IMPORT引入。下面给出一个例子。 假设linker 选项为:-ro-base 0x40000000 -rw-base 0x40003000。程序和只读变量(const 变量)大小为0x84,这样RO section的大小为0x84 bytes。Data的大小为0x04 bytes,并且data被初始化,则RW section的大小为0x04,ZI section的大小为0x04。这样程序 在load view,地址是这样的: 0x40000000开始到地址0x40000080,是RO section部分(程序从0x40000000开始),Image$$RO$$Limit = 0x40000084. 0x40000084地址开始到地址0x40000084,是RW section部分。 

制定Memory map 
在execution view,由linker的选项,各个section的地址是这样的: RO section的地址不变。 RW section的起始地址x40003000,则Image$$RW$$Base = 0x40003000。 因为全部的0x04 bytes data被初始化,所以Image$$RW$$Limit = Image$$ZI$$Limt = 0x40003004。 现在要做的就是将RW section移到以0x40003000开始的地方,并且创造一个ZI section。 一个更通用的做法是: 首先比较Image$$RO$$Limit和mage$$RW$$Base,如果相等,说明execution view下RW section的地址和load view 下RW section的地址相同,这样,不需要移动RW section;如果不等,说明需要移动RW section 到它在execution view中的地方。然后将Image$$ZI$$Base地址到Image$$ZI$$Limt地址的内容清零。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值