第3章-ARM汇编语言程序设计-GNU-汇编_第1页
第3章-ARM汇编语言程序设计-GNU-汇编_第2页
第3章-ARM汇编语言程序设计-GNU-汇编_第3页
第3章-ARM汇编语言程序设计-GNU-汇编_第4页
第3章-ARM汇编语言程序设计-GNU-汇编_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

ADS/SDTIDE开发环境:它由ARM公司开发,使用了CodeWarrior公司的编译器;集成了GNU开发工具的IDE开发环境:它由GNU的汇编器as、交叉编译器gcc、和链接器ld等组成。汇编语言都具有一些相同的基本特征。①一条指令一行。②使用标号(label)给内存单元提供名称,从第1列开始书写。③指令必须从第2列或能区分标号的地方开始书写。④注释跟在指定的注释字符后面(ARM使用的是“;”/”@”),一直书写到行尾。ARM汇编语言基本的的语句格式如下:

{symbol}{instruction|directive|pseudo-instruction}{;comment}符号

指令、伪指令或伪操作

[;/@注释]①符号由大小写字母、数字及下画线组成,符号不能用数字开头。②符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。③符号在其作用范围内必须唯一。④自定义的符号名不能与系统的保留字相同。⑤符号名不应与指令或伪指令同名。伪操作(Directive)是ARM汇编语言程序里的一些特殊的指令助记符,其作用主要是为完成汇编程序做各种准备工作,对源程序运行汇编程序处理,而不是在计算机运行期间由处理器执行。不同的编译程序所使用的伪操作有所不同。常量编译控制伪操作程序代码控制伪操作宏及条件编译伪指令其他伪指令GNUARM汇编伪操作Linux汇编行结构

任何汇编行都是如下结构:[:]

[}

@

comment

[:]

[}

@注释

Linux

ARM

汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。

【例1】定义一个"add”的函数,返回两个参数的和。

.section

.text,

“x”

.global

add

@

give

the

symbol

add

external

linkage

add:

ADD

r0,

r0,

r1

@

add

input

arguments

MOV

pc,

lr

@

return

from

subroutine

@

end

of

program

Linux

汇编程序中的标号

Linux汇编程序中的标号标号只能由a~z,A~Z,0~9,“.”,”_”等字符组成。当标号为0~9的数字时为局部标号,局部标号可以重复出现,使用方法如下:标号f:在引用的地方向前的标号标号b:在引用的地方向后的标号【例2】使用局部符号的例子,一段循环程序1:subsr0,r0,#1@每次循环使r0=r0-1bne1f@跳转到1标号去执行局部标号代表它所在的地址,因此也可以当作变量或者函数来使用。Linux汇编程序中的分段(1).section伪操作

用户可以通过.section伪操作来自定义一个段,格式如下:

.section

section_name

[,

"flags"[,

%type[,flag_specific_arguments]]]

每一个段以段名为开始,

以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。

下面是ELF格式允许的段标志

a

允许段,

w

可写段x:执行段例子:.section.mysection

@自定义数据段,段名为“.mysection”预定义段.text、.data、.bss语法格式.text{subsection}.data{subsection}

@初始化数据.bss{subsection}作用.text、.data和.bss将汇编系统预定义的段名编译到相应的代码段、数据段和bss段。注意:源程序中.bss段应该在.text之前。说明bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域

举例

.section.data

<initializedatahere>

.section.bss

<uninitializeddatahere>

.section.text.global_start

_start:<instructioncodegoeshere>.end语法格式

.end作用表明源文件的结束,如果该标号之后还有代码,不会被编译到执行文件中.include语法格式 .include"filename"作用

可以将指定的文件在使用位置处展开,一般是头文件.incbin语法格式 .incbin"file"[,skip[,count]]作用

可以将原封不动的一个二进制文件编译到当前文件中。其中,skip表明是从文件开始跳过skip个字节开始读取文件,count是读取的字数.if、.else/.endif

语法格式

.if条件表达式

代码段1.else

代码段2.endif.macro、.exitm和.endm语法格式

.macro宏名参数名列表@伪操作.macro定义一个宏宏体.endm

@.endm表示宏结束说明如果宏使用参数,那么在宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值,可以使用.exitm伪指令来退出宏举例

.macroSHIFTLEFTa,b.if\b<0MOV\a,\a,ASR#-\b.exitm.endifMOV\a,\a,LSL#\b.endm.string/.asciz/.ascii语法格式 .string/.asciz/.ascii表达式{,表达式}...作用.string/.asciz/.ascii定义多个字符串。注意:ascii伪操作定义的字符串需要自动添加结尾字符'\0'举例

.string"abcd","hello".equ、.set语法格式.equ(.set)常量名,表达式作用

.equ和.set用于为程序中标号定义名称举例

.equabc3

@让abc=3.global/.globl语法格式.global/.globlsymbol作用

.global和.globl用来定义一个全局的符号.extern语法格式

.externlabel作用

.extern用于声明一个外部标号.ltorg、.pool语法格式.ltorg/.pool作用

.ltorg和.pool用于声明一个数据缓冲池的开始,它可以分配很大的空间伪指令是ARM处理器支持的汇编语言程序里的特殊助记符,它不在处理器运行期间由机器执行,只是在汇编时将被合适的机器指令代替成ARM或Thumb指令,从而实现真正的指令操作。ARM汇编语言伪指令如表3-2所示。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。ADR伪指令中的地址是基于PC或寄存器的,当ADR伪指令中的地址是基于PC时,该地址与ADR伪指令必须在同一个代码段中。地址表达式expr的取值范围如下:当地址值是字节对齐时,其取指范围为−255B~255B;当地址值是字对齐时,其取指范围为−1020B~1020B。ARM伪指令——小范围的地址读取

ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR0,Delay...DelayMOVR0,r14...应用示例(源程序):使用伪指令将程序标号Delay的地址存入R0...0x20ADDr1,pc,#0x3c......0x64MOVr0,r14...ARM伪指令——小范围的地址读取

ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR1,Delay...DelayMOVR0,r14...应用示例(源程序):编译后的反汇编代码:使用伪指令将程序标号Delay的地址存入R0地址程序代码ARM伪指令——小范围的地址读取

ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。...ADRR0,Delay...DelayMOVR0,r14...应用示例(源程序):...0x20ADDr0,pc,#0x3c......0x64MOVr0,r14...编译后的反汇编代码:使用伪指令将程序标号Delay的地址存入R0ADR伪指令被汇编成一条指令ARM伪指令——小范围的地址读取

ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。

应用示例2(查表):

ADRR0,DISP_TAB ;加载转换表地址

LDRBR1,[R0,R2] ;使用R2作为参数,进行查表

…DISP_TAB:.word0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。示例:

LDRr1,=0xff ;将0xff读取到r1中 ;编译后得到MOVr1,0xff示例:

LDRr1,=ADDR ;将外部地址ADDR读取到R1中

汇编后将得到:;LDRr1,[PC,OFFSET_TO_LPOOL];…;LPOOL.wordADDR.text.global_start_start: mov r0,#9 mov r1,#15loop: cmp r0,r1 //比较r0r1 sublt r1,r1,r0 //若r0<r1则r1=r1–r0 subgt r0,r0,r1 //若r1<r0则r0=r0–r1 bne loop //若r0r1不相等则继续循环stop: b stop.end用预先设定的行标与B、BL结合可以设计各种循环结构。例如:LOOPADDR0,R0,R1 ;R0=R0+R1CMPR0,#3 ;比较R0和#3BLSLOOP ;ifR0<3then跳转到LOOP循环.end在ARM汇编语言程序中,子程序的调用一般是通过BL指令来实现的。在程序中,使用指令:BL子程序名

即可完成子程序的调用。该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在LR中的返回地址重新复制给程序计数器PC即可。在调用子程序的同时,也可以完成参数的传递和从子程序返回运算的结果,通常可以使用寄存器R0~R3完成。以下是使用BL指令调用子程序的汇编语言源程序的基本结构:

……BLPRINT_TEXT ;跳转到子程序PRINT_TEXT,并保存PC至LR……PRINT_TEXT ;子程序入口……MOVPC,LR ;子程序运行完毕将PC置为LR,准备返回.end【例3-3】给出一个输出HelloWorld的程序。

.sectionHelloWorld, ;声明代码段.equSWI_WriteC&0 ;输出R0中的字符,&0为预定义的

输出代码段入口.equSWI_Exit&11 ;程序结束&11为预定义程序结束代码入口.text.global_start_start:

;代码的入口ADRR1,TEXT ;R1→"HelloWorld"LOOP:LDRBR0,[R1],#1 ;读取下一个字节CMPR0,#0 ;检查文本终点SWINESWI_WriteC ;若非终点,则打印BNELOOP ;并返回LOOPSWISWI_Exit ;执行结束TEXT:.string

"HelloWorld",&0a,&0d,0.end ;程序源代码结束堆栈指令初始化INITSTACK: MOVR0,LR;保存返回地址;设置管理模式堆栈

MSRCPSR_C,#0xD3 LDRSP,StackSvc;设置中断模式堆栈

MSRCPSR_C,#0xD2 LDRSP,StackIrqC语言的优点是运行速度快、编译效率高、移植性好和可读性强。C语言支持模块化程序设计,支持自顶向下的结构化程序设计方法。因此,在嵌入式程序设计中经常会用到C语言程序设计。嵌入式C语言程序设计是利用基本的C语言知识,面向嵌入式工程实际应用进行程序设计。也就是说它首先是C语言程序设计,因此必须符合C语言基本语法,只是它是面向嵌入式的应用而设计的程序。为了使单独编译的C语言程序和汇编程序之间能够相互调用,必须为子程序之间的调用规定一定的规则。ATPCS就是ARM程序和Thumb程序中子程序调用的基本规则。PCS即ProcedureCallStandard(过程调用规范),ATPCS即ARM-ThumbProcedureCallStandard。ATPCS规定了一些子程序之间调用的基本规则,这些基本规则包括子程序调用过程中寄存器的使用规则,数据栈的使用规则,参数的传递规则。基本ATPCS规定了在子程序调用时的一些基本规则,包括以下3个方面的内容:各寄存器的使用规则及其相应的名字,数据栈的使用规则,参数传递的规则。相对于其他类型的ATPCS,满足基本ATPCS的程序的执行速度更快,所占用的内存更少。但是它不能提供以下的支持:ARM程序和Thumb程序相互调用,数据以及代码的位置无关的支持,子程序的可重入性,数据栈检查的支持。1.寄存器的使用规则ATPCS中定义的寄存器如表3-3所示。表3-3

ATPCS中定义的寄存器其中:R0~R3:用于传参,r0用于返回值。R4~R11:通用变量寄存器。

R12:用作过程调用中间临时过渡寄存器IP。R13:堆栈指针。R14:连接寄存器。R15:PC。另外,R9、R10和R11还有一个特殊作用,分别记为:静态基址寄存器SB,数据栈限制指针SL和桢指针FP。①子程序通过寄存器R0~R3来传递参数,这时寄存器可以记作A0~A3,被调用的子程序在返回前无须恢复寄存器R0~R3的内容。②在子程序中,使用R4~R11来保存局部变量,这时寄存器R4~R11可以记作V1~V8。如果在子程序中使用到V1~V8的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值,对于子程序中没有用到的寄存器则不必执行这些操作。在Thumb程序中,通常只能使用寄存器R4~R7来保存局部变量。③寄存器R12用作子程序间临时过渡寄存器,记作IP,在子程序的连接代码段中经常会有这种使用规则。④寄存器R13用作数据栈指针,记做SP,在子程序中寄存器R13不能用作其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。⑤寄存器R14用作连接寄存器,记作LR。它用于保存子程序的返回地址,如果在子程序中保存了返回地址,则R14可用作其他的用途。⑥寄存器R15是程序计数器,记作PC,它不能用作其他用途。⑦ATPCS中的各寄存器在ARM编译器和汇编器中都是预定义的。栈指针通常可以指向不同的位置。当栈指针指向栈顶元素(即最后一个入栈的数据元素)时,称为FULL栈。当栈指针指向与栈顶元素相邻的一个元素时,称为Empty栈。数据栈的增长方向也可以不同,当数据栈向内存减小的地址方向增长时,称为Descending栈;当数据栈向着内存地址增加的方向增长时,称为Ascending栈。综合这两种特点可以有以下4种数据栈,即FD、ED、FA、EA。ATPCS规定数据栈为FD类型,并对数据栈的操作是8字节对齐的,下面是一个数据栈的示例及相关的名词。①数据栈栈指针(stackpointer):指向最后一个写入栈的数据的内存地址。②数据栈的基地址(stackbase):指数据栈的最高地址。由于ATPCS中的数据栈是FD类型的,实际上数据栈中最早入栈数据占据的内存单元是基地址的下一个内存单元。③数据栈界限(stacklimit):数据栈中可以使用的最低的内存单元地址。④已占用的数据栈(usedstack):数据栈的基地址和数据栈栈指针之间的区域,其中包括数据栈栈指针对应的内存单元。⑤数据栈中的数据帧(stackframes):在数据栈中,为子程序分配的用来保存寄存器和局部变量的区域。(1)参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递;当参数超过4个时,还可以使用数据栈来传递参数。在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。然后,依次将各名字数据传送到寄存器R0,R1,R2,R3;如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递。(2)参数个数固定的子程序参数传递规则对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同,如果系统包含浮点运算的硬件部件,浮点参数将按照下面的规则传递:各个浮点参数按顺序处理;为每个浮点参数分配FP寄存器;分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器。第1个整数参数通过寄存器R0~R3来传递,其他参数通过数据栈传递。(3)子程序结果返回规则①结果为一个32位的整数时,可以通过寄存器R0返回。②结果为一个64位整数时,可以通过R0和R1返回,依此类推。③结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0或者s0来返回。④结果为一个复合的浮点数时,可以通过寄存器f0~fN或者d0~dN来返回。⑤对于位数更多的结果,需要通过调用内存来传递。在编译或汇编时,使用/intework告诉编译器或汇编器生成的目标代码遵守支持ARM程序和Thumb程序混合使用的ATPCS,它用在以下场合:程序中存在ARM程序调用Thumb程序的情况;程序中存在THUMB程序调用ARM程序的情况;需要连接器来进行ARM状态和Thumb状态切换的情况;在下述情况下使用选项nointerwork:程序中不包含Thumb程序;用户自己进行ARM程序和Thumb程序切换。需要注意的是:在同一个C/C++程序中不能同时有ARM指令和Thumb指令。在嵌入式系统开发中,目前使用的主要编程语言是C和汇编,C++已经有相应的编译器,但是现在使用还是比较少的。在稍大规模的嵌入式软件中,如含有OS,大部分的代码都是用C语言编写的,主要是因为C语言的结构比较好,便于人的理解,而且有大量的支持库。尽管如此,很多地方还是要用到汇编语言,如开机时硬件系统的初始化,包括CPU状态的设定,中断的使能,主频的设定,以及RAM的控制参数及初始化,一些中断处理方面也可能涉及汇编。另外一个使用汇编的地方就是一些对性能非常敏感的代码块,这是不能依靠C编译器的生成代码,而要手工编写汇编,达到优化的目的。而且,汇编语言是和CPU的指令集紧密相连的,作为涉及底层的嵌入式系统开发,熟练对应汇编语言的使用也是必须的。在C语言中内嵌的汇编指令包含大部分的ARM和Thumb指令,不过其使用与汇编文件中的指令有些不同,存在一些限制,主要有下面几个方面。①不能直接向PC寄存器赋值,程序跳转要使用B或者BL指令。②在使用物理寄存器时,不要使用过于复杂的C表达式,避免物理寄存器冲突。③R12和R13可能被编译器用来存放中间编译结果,计算表达式值时可能将R0到R3、R12及R14用于子程序调用,因此,要避免直接使用这些物理寄存器。④一般不要直接指定物理寄存器,而让编译器进行分配。GCC内嵌汇编内嵌汇编语法如下:

__asm__(汇编语句模板:输出部分:输入部分:破坏描述部分)

共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用“:”格开,相应部分内容为空。

例如:移位操作asm("mov%[result],%[value],ror#1" :[result]“=r”(y)/*移位结果*/ :[value]“r”(x)/*移位值*/:/*无破坏描述*/);asm("mov%0,%1,ror#1":"=r"(result):"r"(value));GCC内嵌汇编汇编语句模板

汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1,…,%9。指令中使用占位符表示的操作数,总被视为long型(4个字节),为了增加扩展性,占位符可使用%[symbol]代替。

"mov%[result],%[value],ror#1"输出部分

输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C语言变量组成。每个输出操作数的限定字符串必须包含“=”表示他是一个输出操作数。

[result]"=r"(y)GCC内嵌汇编输入部分

输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符由限定字符串和C语言表达式或者C语言变量组成。

[value]"r"(x)破坏描述部分

破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有“memory”int

value_convert(int

x)

{

int

y;

asm

volatile

(

"mov

%[result],

%[value],

ror

#1"

:

[result]

"=r"

(y)

:

[value]

"r"

(x)

:

);

return

y;

}

int

main()

{

printf("GCC

ARM

Inline

Assembler

CookBook

Demo!\n");

int

x

=

4;

printf("call

func

value_convert

with

input

x:%d,output

y:%d\n",x,value_convert(x));

return

0;

}

程序编译运行后的输出:

内嵌汇编不用单独编辑汇编语言文件,比较简洁,但是有诸多限制,当汇编的代码较多时一般放在单独的汇编文件中,这时就需要在汇编和C之间进行一些数据的传递,最简便的办法就是使用全局变量。汇编中使用C定义的全局变量。在C中调用汇编文件中的函数,要做的主要工作有两个,一是在C中声明函数原型,并加extern关键字;二是在汇编中用EXPORT导出函数名,并用该函数名作为汇编代码段的标识,最后用movpc,lr返回。然后,就可以在C中使用该函数了。从C的角度,并不知道该函数的实现是用C还是汇编。更深的原因是因为C的函数名起到表明函数代码起始地址的作用,这个和汇编的label是一致的。【例3-6】在C中调用汇编的函数(函数不多于4个参数)。

#include<stdio.h>

externvoidstrcopy(char*d,constchar*s);

intmain()

{

constchar*srcstr="Firststring-source";

chardststr[]="Secondstring-destination";

/*下面将dststr作为数组进行操作*/

printf("Beforecopying:\n");

printf("%s\n%s\n",srcstr,dststr);

strcopy(dststr,srcstr);

printf("Aftercopying:\n");

printf("%s\n%s\n",srcstr,dststr);

return(0);

}.globalstrcopystrcopy:;R0指向目的字符串;R1指向源字符串LDRBR2,[R1],#1;加载字节并更新源字符串指针地址STRBR2,[R0],#1;存储字节并更新目的字符串指针地址CMPR2,#0;判断是否为字符串结尾BNEstrcopy;如果不是,程序跳转到strcopy继续复制MOVpc,lr;程序返回【例3-8】在汇编语言中调用C语言的函数(参数不多于4个)。

;prog1_asm.asm.externprog1_c ;声明prog1_c函数.text_start:.globalprog1_asmprog1_asm:STRlr,[sp,#-4]! ;保存当前lrldrr0,=0x1 ;参数1ldrr1,=0x2 ;参数2ldrr2,=0x3 ;参数3blprog1_c ;调用C函数LDRpc,[sp],#4 ;将lr装进pc(返回main函数).end//prog1_c.cvoidprog1_c(intp1,intp2,intp3){printk("%0x%0x%0x\r\n",p1,p2,p3); //输出参数值}//main.cintmain(){prog1_asm();while(1);}【例3-9】在汇编语言中调用C语言的函数(参数多于4个)。

;prog2_asm.asm.externprog2_c ;声明prog2_c函数.section.text_start:.globalprog2_asmprog2_asm:STRlr,[sp,#-4]! ;保存当前lrldrr0,=0x1 ;参数1ldrr1,=0x2 ;参数2ldrr2,=0x3 ;参数3ldrr3,=0x4 ;参数4ldrr4,=0x6strr4,[sp,#-4]! ;参数6入栈ldrr4,=0x5strr4,[sp,#-4]! ;参数5入栈blprog2_cADDsp,sp,#4 ;清除栈中参数5,本语句执行完后sp指向参数6ADDsp,sp,#4 ;清除栈中参数6,本语句执行完后sp指向lrLDRpc,[sp],#4 ;将lr装进pc(返回main函数).end//prog2_c.c

voidprog2_c(intp1,intp2,intp3,intp4,intp5,intp6){printk("%0x%0x%0x%0x%0x%0x\r\n",p1,p2,p3,p4,p5,p6); //输出参数值}//main.c

intmain(){prog2_asm();while(1);}1.用汇编语言设计程序实现10!(10的阶乘)。2.实现字符串的逆序复制

TEXT1="HELLO"=〉TEXT2="OLLEH"。3.用调用子程序的方法实现1!+2!+3!+…+10!。4.什么是内嵌汇编?使用内嵌汇编时需要注意什么?5.C语言与汇编语言混合编程时的参数传递规则有哪些?

启动程序设计

启动代码启动代码内容启动代码工作流程启动代码内容(1)启动代码简介

广州致远电子有限公司为LPC2000系列芯片编写的启动代码由3个文件组成。(1)startup.s-异常向量表定义、各模式堆栈初始化、跳转到C程序main入口等。

(2)target.c-目标板初始化,如时钟分频、PLL设置、VIC设置等。

(3)irq.s-用于管理中断嵌套。(1)startup.s.text.global_start.globalirq_handler;中断向量表_start:bresetldrpc,_undefined_instructionldrPC,_software_interruptLDRPC,_prefetch_abortldrPC,_data_abortLDRPC,_no_usedldrPC,_irqLDRPC,_fiq_undefined_instruction:.word_undefined_instruction_software_interrupt:.word_software_interrupt_prefetch_abort:.word_prefetch_abort_data_abort:.word_data_abort_no_used:.word_no_used_irq:.word_irq_fiq:.word_fiq汇编入口异常向量表地址跳转表(1)startup.sreset:

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论