嵌入式系统基础教程第11讲第5章ARM汇编语言程序标准和范例.ppt
嵌入式系统基础教程第11讲第5章ARM汇编语言程序标准和范例 Still waters run deep.流静水深流静水深,人静心深人静心深 Where there is life,there is hope。有生命必有希望。有生命必有希望第第5章章 ARM指令集和汇编语言程序指令集和汇编语言程序l本章主要介绍以下内容:lARM指令集的基本特点l与Thumb指令集的区别l与x86处理器的区别lARM指令格式lARM寻址方式lARM指令集分类详解lARM汇编语句格式和程序格式lARM汇编语言的指示符lARM汇编程序标准与规范l典型ARM汇编语言程序举例2008年10月23日2南京大学计算机系本讲主要参考文献本讲主要参考文献lARM公司英文资料:公司英文资料:lADS_AssemblerGuide_B.pdflDDI0100E_ARM_ARM.pdfl中文图书中文图书lARM体系结构与编程,清华大学出版社l嵌入式系统基础教程,机械工业出版社2008年10月23日3南京大学计算机系讲授内容讲授内容lATPCS 和AAPCS规范要点lARM编译器保有的特定关键字l典型ARM汇编语言程序举例lARM汇编程序基本结构lC程序和CPP程序调用ARM汇编子程序lARM汇编程序调用ARM汇编子程序l整数除法子程序lS3C44B0X处理器的启动代码l44BInit.s、option.s、memcfg.s2008年10月23日4南京大学计算机系5.7 ARM汇编程序规范汇编程序规范l寄存器的使用规则l堆栈使用规则l参数传递规则2008年10月23日5南京大学计算机系ATPCSlATPCS(ARM-Thumb Procedure Call Standard)规定了一些子程序间调用的基本规则,这些规则包括子程序调用过程中寄存器的使用规则,数据栈的使用规则,参数的传递规则。有了这些规则之后,单独编译的C语言程序就可以和汇编程序相互调用。l使用ADS的C语言编译器编译的C语言子程序满足用户指定的ATPCS类型。而对于汇编语言来说,则需要用户来保证各个子程序满足ATPCS的要求。2008年10月23日6南京大学计算机系AAPCSl2007年ARM公司正式推出了AAPCS标准lARM Archtecture Procedure Call StandardlAAPCS是ATPCS的改进版l目前,AAPCS和ATPCS都是可用的标准2008年10月23日7南京大学计算机系寄存器的使用规则寄存器的使用规则l子程序间通过寄存器R0R3来传递参数。这时,寄存器R0R3可记作a0a3。被调用的子程序在返回前无需恢复寄存器R0R3的内容。l在子程序中,使用寄存器R4R11来保存局部变量。这时,寄存器R4R11可以记作v1v8。如果在子程序中使用了寄存器v1v8中的某些寄存器,则子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值。在Thumb程序中,通常只能使用寄存器R4R7来保存局部变量。l寄存器R12用作过程调用中间临时寄存器,记作IP。在子程序之间的连接代码段中常常有这种使用规则。2008年10月23日8南京大学计算机系寄存器的使用规则(续)寄存器的使用规则(续)l寄存器R13用作堆栈指针,记作SP。在子程序中寄存器R13不能用作其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。l寄存器R14称为连接寄存器,记作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14则可以用作其他用途。l寄存器R15是程序计数器,记作PC。它不能用作其它用途。2008年10月23日9南京大学计算机系堆栈使用规则堆栈使用规则lATPCS规定堆栈为FD类型,即满递减堆栈,并且对堆栈的操作是8字节对齐。l对于汇编程序来说,如果目标文件中包含了外部调用,则必须满足下列条件:(1)外部接口的堆栈必须是8字节对齐的。(2)在汇编程序中使用PRESERVE8伪指令告诉连接器,本汇编程序数据是8字节对齐的。2008年10月23日10南京大学计算机系参数传递规则参数传递规则l根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变化的子程序。l这两种子程序的参数传递规则是不一样的。2008年10月23日11南京大学计算机系参数个数可变子程序参数传递规则参数个数可变子程序参数传递规则 l对于参数个数可变的子程序,当参数个数不超过4个时,可以使用寄存器R0R3来传递参数;当参数超过4个时,还可以使用堆栈来传递参数。l在传递参数时,将所有参数看作是存放在连续的内存字单元的字数据。然后,依次将各字数据传递到寄存器R0,R1,R2和R3中。如果参数多于如果参数多于4个,则将剩余的字数据传递到堆栈中。个,则将剩余的字数据传递到堆栈中。入栈的顺序与参数传递顺序相反,即最后一个字数据先入栈。2008年10月23日12南京大学计算机系参数个数固定子程序参数传递规则参数个数固定子程序参数传递规则l如果系统不包含浮点运算的硬件部件,浮点参数会通过相应的规则转换成整数参数(若没有浮点参数,此步省略),然后依次将各字数据传送到寄存器R0R3中。如果参数多于4个,将剩余的字数据传送堆栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。在参数传递时,将所有参数看作是存放在连续的内存字单元的字数据。2008年10月23日13南京大学计算机系子程序结果返回规则子程序结果返回规则l子程序中结果返回的规则如下:l结果为一个32位整数时,可以通过寄存器R0返回;l结果为一个64位整数时,可以通过寄存器R0和Rl返回;l结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0或s0来返回;l结果为复合型浮点数(如复数)时,可以通过寄存器f0fn或d0dn来返回;l对于位数更多的结果,需要通过内存来传递。2008年10月23日14南京大学计算机系5.7.2 ARM编译器保有的特定关键字编译器保有的特定关键字lARM编译器支持一些对ANSI C进行扩展的关键词。这些关键词用于声明变量、声明函数、对特定的数据类型进行一定的限制。2008年10月23日15南京大学计算机系用于声明函数的关键词用于声明函数的关键词(双下划线起头)(双下划线起头)l_asm,内嵌汇编l_inline,内联展开l_irq,声明IRQ或FIQ的ISRl_pure,函数不修改该函数之外的数据l_softfp,使用软件的浮点连接件l_swi,软中断函数l_swi_indirect,软中断函数2008年10月23日16南京大学计算机系用于声明变量的关键词用于声明变量的关键词lregisterl声明一个变量,告诉编译器尽量保存到寄存器中。l_int64l该关键词是long long的同义词。l_global_regl将一个已经声明的变量分配到一个全局的整数寄存器中。2008年10月23日17南京大学计算机系5.8 典型典型ARM汇编语言程序举例汇编语言程序举例l请参看本课程教材嵌入式系统基础教程中第151页开始的第5.2节。2008年10月23日18南京大学计算机系5.8.1 条件执行举例条件执行举例l求a和b两整数最大公约数的C程序While a!=b)If(ab)a-=b;else b-=a;2008年10月23日19南京大学计算机系条件执行举例(续)条件执行举例(续)l如果用ARM汇编子程序来实现,就是求r1和r2两个寄存器中的两个整数的最大公约数。使用条件执行指令表示只有以下4句代码:gcdcmp r1,r2;cmp与subs功能类似但不存结果subgtr1,r1,r2;如果r1r2执行此指令subltr2,r2,r1;如果r1r2执行此指令bnegcd;如果r1r2则转gcd标号注:函数结束时r1=r2,都可以用作返回值。2008年10月23日20南京大学计算机系5.8.2 32位地址送入一个寄存器中位地址送入一个寄存器中l下面指令段中的load指令根据输入参数决定调用那个函数。具体做法是将函数的绝对地址通过LDR指令存入在r4寄存器中,由于是32的绝对地址,LDR会被解释成以下操作:将函数的绝对地址放入一个文字池(Literal pool,嵌入在代码中的用以存放常数的区域)。产生一条形如:LDR rn pc,#offset to literal pool的指令来将这个绝对地址读入到指定的寄存器中。l类似地LDR指令也通过上述方法读入一个32位的绝对数。在下例中,LDR指令将32位绝对数0 x11552634读入到r0寄存器中,用作调用routine1或者routine2的参数。2008年10月23日21南京大学计算机系32位地址送入一个寄存器中(续)位地址送入一个寄存器中(续);void load(int i);void routine1(int 1);void routine2(int 2);AREA LOAD,CODE,READONLYIMPORT routine1IMPORT routine2EXPORT loadloadstmfdr13!,r4,r14ldrr4,=routine1;首先将32位地址存放在附近的区域cmps r0,#1ldrner4,=routine2ldrr0=0 x11552634;函数的第1个int参数bxr4ldmfdr13!,r4,r14bxr142008年10月23日22南京大学计算机系5.8.3 从从IRQ和和FIQ异常处理程序返回异常处理程序返回l从IRQ和FIQ异常处理程序返回时,返回地址应该是LR-4。l有三种不同的编程方法,分别列出如下:l返回方式1INT_HANDLERSUBS PC,LR,#4;PC=R14-42008年10月23日23南京大学计算机系从从IRQ和和FIQ异常处理程序返回(异常处理程序返回(2)l返回方式2INT_HANDLERSUB R14,R14,#4;R14-=4MOVS PC,LR2008年10月23日24南京大学计算机系从从IRQ和和FIQ异常处理程序返回(异常处理程序返回(3)l返回方式3INT_HANDLERSUB R14,R14,#4;R14=R14 4STMFD R13!,R0-R3,R14LDMFD R13!,R0-R3,R152008年10月23日25南京大学计算机系5.8.4 调用调用ARM汇编语言子程序汇编语言子程序l在ARM汇编语言中,子程序调用是通过BL指令完成的。BL指令的语法格式如下:lBL subnamel其中,subname是调用的子程序的名称。lBL指令完成两个操作:将子程序的返回地址放在LR寄存器中,同时将PC寄存器值设置成目标子程序的第一条指令地址。l在子程序返回时可以通过将LR寄存器的值传送到PC寄存器中来实现。l子程序调用时通常使用寄存器R0R3来传递参数和返回结果。2008年10月23日26南京大学计算机系调用汇编子程序举例调用汇编子程序举例l子程序DOADD完成加法运算,操作数放在R0和R1寄存器中,结果放在R0中。AREA EXAMPLE2,CODE,READONLYENTRYstartMOV r0,#10;R0设置输入参数MOV r1,#3 ;R1设置输入参数BLdoadd;调用子程序doadddoaddADD r0,r0,r1;子程序实体MOV pc,lr;从子程序中返回END2008年10月23日27南京大学计算机系5.8.5 循环结构循环结构l在ARM汇编中,没有专门的指令用来实现循环,一般通过跳转指令加条件码的形式来实现。可以采用比较指令CMP或者减法指令SUB等实现。参看下面的指令段:LOOPADDR4,R4,R0ADDR0,R0,#1CMPR0,R1BLELOOP ;R0小于等于R1场合跳转l在做完了两次加法操作后,比较R0,R1的值,影响条件标志。最后的条件跳转语句根据CMP指令执行的结果来决定是否进行循环。2008年10月23日28南京大学计算机系5.8.6 数据块复制示范程序数据块复制示范程序l本程序将数据从源数据区复制到目标数据区l复制时,以8个字为单位进行。l对于最后所剩不足8个字的数据,以字为单位进行复制,这时程序跳转到copywords处执行。l在进行以8个字为单位的数据复制时,保存了所用的8个工作寄存器。程序清单如下面所示。2008年10月23日29南京大学计算机系数据块复制示范程序(数据块复制示范程序(1);设置本段程序的名称(Block)及属性AREA Block,CODE,READONLY;设置将要复制的字数num EQU 20;标识程序入口点 ENTRYStart;r0寄存器指向源数据区srcLDR r0,=src;r1寄存器指向目标数据区dstLDR r1,=dst2008年10月23日30南京大学计算机系数据块复制示范程序(数据块复制示范程序(2);r2指定将要复制的字数MOV r2,#num;设置数据栈指针(r13),用于保存工作寄存器数值MOV sp,#0 x400;进行以8个字为单位的数据复制blockcopy;需要进行的以8个字为单位的复制次数MOVS r3,r2,LSR#3;对于剩下不足8个字的数据,跳转到copywords,以字为单位复制BEQ copywords;保存工作寄存器,压栈STMFD sp!,r4r112008年10月23日31南京大学计算机系数据块复制示范程序(数据块复制示范程序(3)octcopy;从源数据区读取8个字的数据,放到8个寄存器中,并更新目标数据区指针r0LDMIA r0!,r4-r11;将这8个字数据写入到目标数据区中,并更新目标数据区指针r1STMIA r1!,r4-r11;将块复制次数减1SUBS r3,r3,#1;循环,直到完成以8个字为单位的块复制BNE octcopy;恢复工作寄存器值,出栈LDMFD sp!,r4-r11 2008年10月23日32南京大学计算机系数据块复制示范程序(数据块复制示范程序(4)copywords;剩下不足8个字的数据的字数ANDS r2,r2,#7;数据复制完成BEQ stopwordcopy;从源数据区读取1个字的数据,放到r3寄存器中,并更新目标数据区指针r0,后索引偏移LDR r3,r0,#4;将这r3中数据写入到目标数据区中,并更新目标数据区指针r1,后索引偏移STR r3,r1,#42008年10月23日33南京大学计算机系数据块复制示范程序(数据块复制示范程序(5);将字数减1SUBS r2,r2,#l;循环,直到完成以字为单位的数据复制BNE wordcopy;定义数据区BlockDataAREA BlockData,DATA,READWRITE;定义源数据区src及目标数据区dstsrc DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;结束汇编END2008年10月23日34南京大学计算机系5.8.7 内嵌汇编内嵌汇编l内嵌汇编(inline assembly)的语法如下:_asm指令;指令 /*注释*/指令2008年10月23日35南京大学计算机系内嵌汇编的指令用法内嵌汇编的指令用法l内嵌在C或者C+程序中的ARM汇编指令与普通(ADS)格式的ARM汇编指令有所不同。其主要原因在于C/C+编译器在编译C/C+源代码的同时要兼顾处理内嵌汇编程序,因此CPU的内部寄存器资源使用有额外约束。以下讲解内嵌ARM汇编指令的用法。2008年10月23日36南京大学计算机系ARM内嵌汇编程序的操作数内嵌汇编程序的操作数l内嵌汇编指令中作为操作数的寄存器和常量可以是表达式。这些表达式可以是char,short或int类型,而且这些表达式都是作为无符号数进行操作。若需要带符号,用户需要自己处理与符号有关的操作。编译器将会计算这些表达式的值,并为其分配寄存器。2008年10月23日37南京大学计算机系ARM内嵌汇编程序的物理寄存器内嵌汇编程序的物理寄存器l内嵌汇编程序中使用物理寄存器有以下限制。不能直接向PC寄存器赋值,程序跳转只能使用B或BL指令实现不要使用过于复杂的C表达式,因为将会需要较多的物理寄存器,这将导致与其他指令中用到的物理寄存器产生使用冲突。编译器可能会使用R12或R13存放编译的中间结果,在计算表达式的值时可能会将寄存器R0R3,R12和R14用于子程序调用。因此在内嵌的汇编指令中不要将这些寄存器同时指定为指令中的物理寄存器。通常内嵌的汇编指令中不要指定物理寄存器,因为这可能会影响编译器分配寄存器,进而影响代码的效率。2008年10月23日38南京大学计算机系其他内嵌汇编程序的编写注意点其他内嵌汇编程序的编写注意点l常量:常量:在内嵌汇编指令中,常量前面的“#”可以省略。l指令展开:指令展开:内嵌汇编指令中,如果包含常量操作数,该指令可能被内嵌汇编器展开成几条指令。l标号:标号:C程序中的标号可以被内嵌的汇编指令使用,但是只有指令B可以使用C程序中的标号,而指令BL则不能使用。l内存单元的分配:内存单元的分配:所有的内存分配均由C编译器完成,分配的内存单元通过变量供内嵌汇编器使用。内嵌汇编器不支持内嵌程序中用于内存分配的伪指令。2008年10月23日39南京大学计算机系内嵌汇编程序中的内嵌汇编程序中的SWI和和BL指令指令lSWI和BL指令:在两个指令使用到内嵌汇编中,除了正常的操作数域外,还必须增加以下3个可选的寄存器列表:用于输入参数的寄存器列表。用于存储返回结果的寄存器列表。用于表示那些寄存器将有可能会被修改的寄存器列表。2008年10月23日40南京大学计算机系内嵌汇编代码举例字符串复制(内嵌汇编代码举例字符串复制(1)#includevoid str_cpy(const char*src,char*dst)int ch;_asmloop:/普通ARM汇编代码中的标号后面不能跟冒号。C程序中/的标号可以被内嵌的汇编指令使用。ARM内嵌汇编代码中/只有B指令可以使用C的标号,而BL指令不能够使用C代码/的标号。C程序的标号后面跟冒号,由Goto语句转向标号处。LDRBch,src,#1STRBch,dst,#1CMPch,#0BNEloop2008年10月23日41南京大学计算机系内嵌汇编代码举例字符串复制(内嵌汇编代码举例字符串复制(2)int main(void)const char*a=Hello world!n;char b20;/do inline assembly routine str_cpy(a,b)_asmMOV R0,a /将串a的串首地址送到R0寄存器MOV R1,b /将串b的串首地址送到R1寄存器BL str_cpy,R0,R1 /调用C函数str_cpy()printf(Original string:%sn,a);printf(Copied string:%sn,b);/半主机方式显示复制前后的两个串return(0);2008年10月23日42南京大学计算机系5.8.8 ARM汇编、汇编、C和和C+混合编程混合编程l在C/C+程序中如果必须使用汇编指令来完成某些操作,可以采用两种方法:1.采用内嵌汇编,即在C/C+源程序中嵌入一块汇编代码,让这块汇编代码来完成特定的操作;2.将必须使用汇编代码的部分独立编写成在一个文件中,形成一个子程序,C/C+程序可以调用这些汇编程序来完成特定的操作。2008年10月23日43南京大学计算机系C/C+程序与程序与ARM汇编语言程序的汇编语言程序的相互调用相互调用 lC/C+程序与汇编程序相互调用时,应遵守相应的ATPCS,主要有五种调用。lARM汇编子程序调用C语言子程序lARM汇编子程序调用C+语言子程序lC语言程序调用ARM汇编语言子程序lC+语言程序调用ARM汇编语言子程序lC语言程序调用C+语言子程序l下面就每种具体情况逐一举例说明。2008年10月23日44南京大学计算机系C/C+程序调用程序调用ARM汇编子程序要点汇编子程序要点l设计汇编程序必须遵守ATPCS,保证程序调用时参数的正确传递。l在汇编程序中使用EXPORT指示符声明本程序可以被别的程序调用。l在C语言程序中使用extern关键词声明该汇编程序可以被调用,C+语言程序使用extern“C”来声明该汇编程序可以被调用。2008年10月23日45南京大学计算机系例例1 C程序调用程序调用ARM汇编子程序汇编子程序/*main_0522.c semihosting output mode*/#include extern int asmfile(int arg1,int arg2,int arg3);int main(void)int a1=1,a2=2,a3=4;printf(Example of C Program calling Assembly program!n);printf(%d+%d+%d)*600=%dn,a1,a2,a3,asmfile(a1,a2,a3);2008年10月23日46南京大学计算机系C程序调用程序调用ARM汇编子程序(续)汇编子程序(续);ASM_0522.s EXPORT asmfile AREA My_pro,CODE,READONLYasmfileSTMFD SP!,R4-R6,R8,R7 add r0,r0,r1add r0,r0,r2mov r4,#600mul r3,r0,r4mov r0,r3LDMFD SP!,R4-R6,R8,R7mov pc,lrEND2008年10月23日47南京大学计算机系例例2 ARM汇编程序调用汇编程序调用C语言子程序语言子程序l本案例程序比较两个IP地址的大小,a1a4存放IP地址1的值(按照ATPCS传递参数),b1b4存放IP地址2的值(通过栈传递参数),如果IP地址1的值大于IP地址2的值则返回1,如果IP地址1的值小于IP地址2的值则返回-1,如果两者相等则返回零。lIP地址1取值:192,168,1,152,lIP地址2取值:172,0,0,151 2008年10月23日48南京大学计算机系例例2 ARM汇编程序调用汇编程序调用C子程序(续)子程序(续)/*C代码部分*/#include extern int function(void);/*声明function是外部函数*/int compare_ip(int a1,int a2,int a3,int a4,int b1,int b2,int b3,int b4)if(a1!=b1)return a1b1?1:-1;if(a2!=b2)return a2b2?1:-1;if(a3!=b3)return a3b3?1:-1;if(a4!=b4)return a4b4?1:-1;return 0;int main()printf(This is a example of semihostingn);printf(result is%dn,function();2008年10月23日49南京大学计算机系例例2 ARM汇编调用汇编调用C子程序(续子程序(续2)AREA FUNCTION,CODE,READONLY ;ARM汇编子程序IMPORT compare_ipEXPORT functionfunctionSTMFDr13!,r0-r3,r14;保存寄存器到栈区MOVr3,#0 x97;存入IP地址2的4个数,0 x97=151MOVr2,#0;存入0MOVr1,#0;存入0MOVr0,#0 xac;存入0 xac=172STMIAr13,r0-r3;R0-R4覆盖存入栈区的R0-R4位置MOVr3,#0 x98;存入IP地址1的4个数,0 x98=152MOVr2,#1;存入1MOVr1,#0 xa8;存入0 xa8=168MOVr0,#0 xc0;存入0 xc0=192BLcompare_ip ;0 x0;调用C语言函数进行IP值比较ADDr13,r13,#0 x10;栈指针上移4个字(元素)LDRpc,r13,#4;将保存的r14值加载到PC,而后r13加4END;本段汇编代码的操作图解参看下一页2008年10月23日50南京大学计算机系例例2 ARM汇编调用汇编调用C子程序(续子程序(续3)lARM汇编语言子程序Function的栈区操作图解2008年10月23日51南京大学计算机系例例3 ARM汇编程序调用汇编程序调用 C+子程序子程序/这是这是C+调用调用ARM汇编的范例程序汇编的范例程序/文件名:文件名:try_C+_call_S/main函数位于这个函数位于这个.CPP文件文件extern C void asmfunc(void);int main(void)asmfunc();2008年10月23日52南京大学计算机系例例3 ARM汇编调用汇编调用 C+子程序(续)子程序(续);这个这个ARM汇编语言程序被汇编语言程序被main函数调用函数调用;该函数又调用该函数又调用ARM汇编函数汇编函数cppfunc;AREA mypro,CODE,READONLYIMPORT cppfuncEXPORT asmfuncasmfuncSTMFD sp!,lrBL cppfuncLDMFD sp!,pcEND2008年10月23日53南京大学计算机系例例3 ARM汇编调用汇编调用 C+子程序(续子程序(续2)#include#include using namespace std;const double PI=3.1415926;class pointpublic:point()x=0;y=0;point(double a,double b)x=a;y=b;point(point&a)x=a.x;y=a.y;point();2008年10月23日54南京大学计算机系例例3 ARM汇编调用汇编调用 C+子程序(续子程序(续3)double GetX()return x;double GetY()return y;point&Move(const point&a)this-x+=a.x;this-y+=a.y;return*this;double GetArea(point&a)return abs(this-x-a.x)*abs(a.y-this-y);point&Rotate(const int degree)double tempX=this-x,tempY=this-y,length,a;a=atan(tempY/tempX);length=sqrt(tempX*tempX+tempY*tempY);2008年10月23日55南京大学计算机系例例3 ARM汇编调用汇编调用 C+子程序(续子程序(续4)this-x=length*cos(a+degree*PI/180);this-y=length*sin(a+degree*PI/180);return*this;private:double x,y;2008年10月23日56南京大学计算机系例例3 ARM汇编调用汇编调用 C+子程序(续子程序(续5)extern C int cppfunc()point a(1.5,1.9);point b(2.0,0.0);point c(1.0,1.0);a.Move(b);c.Rotate(90);couta is(a.GetX(),a.GetY()endl;coutb is(b.GetX(),b.GetY()endl;coutc is(c.GetX(),c.GetY()endl;couta and b s retangle area is a.GetArea(b)endl;coutb and c s retangle area is b.GetArea(c)endl;couta and c s retangle area is a.GetArea(c)endl;2008年10月23日57南京大学计算机系例例3 ARM汇编程序调用汇编程序调用C+子程序的子程序的半主机方式运行结果输出截图半主机方式运行结果输出截图2008年10月23日58南京大学计算机系例例4 C语言程序调用语言程序调用 C+子程序子程序l/*main.c 源代码清单*/l#include lstruct S l char ca12;l;lextern void cppfunc(struct S*p);l/*Declaration of the C+function to be called from C*/lvoid f(struct S*s)/*f是C语言函数 */lchar*tmp=Hello;lchar*source=s-ca;lwhile(*source+=*tmp+);/copy hello to s-calcppfunc(s);/*调用C+函数cppfunc(),初始化 s */l2008年10月23日59南京大学计算机系例例4 C语言程序调用语言程序调用 C+子程序(续子程序(续1)lint main()lstruct S s;lf(&s);/*调用C语言的函数f()*/lprintf(%sn,s.ca);lreturn 0;l2008年10月23日60南京大学计算机系例例4 C语言程序调用语言程序调用 C+子程序(续子程序(续2)l/CPP.CPP函数清单lclass S /has no base classes or virtual functionslpublic:char ca12;l S()ca0=0;l;lextern C void cppfunc(S*p)l/Definition of the C+function to be called from C.l/The function is written in C+,only the linkage is Clchar*tmp=world!;lchar*source=p-ca;lwhile(*source!=0)/扫描过原先在c程序中的赋值lsource+;l*source+=;/将结束符改为空格lwhile(*source+=*tmp+);/copy world to p-ca 2008年10月23日61南京大学计算机系ARM汇编(子)程序的相互调用汇编(子)程序的相互调用l基本要点:l如果一个ARM汇编语言程序文件含有调用外部汇编语言程序文件中子程序(函数)的指令,则需要用IMPORT指示符来指明将要调用的子程序名称。l如果本汇编语言程序文件中的某个子程序(函数),需要被外部的ARM汇编语言程序文件中的语句调用,则需要用EXPORT指示符来指明将要被调用的子程序(函数)名称。l被执行的汇编子程序在运行前,要注意将寄存器组压入栈区,返回时要注意将栈区保存的工作现场恢复到处理器的寄存器组。2008年10月23日62南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-1l这里给出的ARM汇编程序嵌套调用范例程序做如下计算:l求自然数求自然数1到到n的阶乘的总和,半主机方式输出的阶乘的总和,半主机方式输出l运算结果如下图所示。第3行显示的是19的阶乘,第2行显示的是1!+2!+3!+4!+5!+6!+7!+8!+9!之总和。2008年10月23日63南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-2/*This program is semihosting output mode*/*First the main function call assembly summing subprogram*/*Then the summing subprogram call assembly factorial subprogram*/#include extern int asmFac(int n);struct factorial_sumint cal_fn;int sum_fn;int fn9;extern struct factorial_sum*summing(struct factorial_sum*arg1);2008年10月23日64南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-3int main(void)int j;struct factorial_sum fac=9,0,1,1,1,1,1,1,1,1,1;/设置参数struct factorial_sum*result;/申请变量作为返回值printf(Example of a multi Assembly program calling!n);result=summing(&fac);/调用求和函数 R0存放的是FAC变量的首地址printf(The total sum is%dn,result-sum_fn);/输出结果for(j=0;jfn)j);2008年10月23日65南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-4;the details of parameters transfer comes from ATPCS;if there are more than 4 args,stack will be used EXPORT summing IMPORT asmFac;说明用到了其他文件中的子汇编程序 AREA SUMMING,CODE,READONLYsummingSTMFD SP!,R4-R5ldr r1,r0;r1=cal_fnmov r2,#1;将r2设置为当前需要计算的阶乘数,;它从1变化到cal_fnadd r3,r0,#8;将r3指向fn数组movr5,#0;r5为总和,初始值置为0loopcmpr1,r2;将cal_fn与当前所需计算的阶乘值比较bltback;如果小于,则返回2008年10月23日66南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-5STMFD SP!,R0-R3,lr;保存ror3,lr;因为调用了外部文件的汇编子程序movr0,r2;将r0设置为当前所需计算的阶乘值blasmFac;调用阶乘函数movr4,r0;将返回值(阶乘)存在r4中ldmfdSP!,R0-R3,lr;恢复先前保存的寄存器值strr4,r3;将计算所得的阶乘值存入数组中addr3,r3,#4;将r3指向数组的下一个addr5,r5,r4;将阶乘值加入总和addr2,r2,#1;计算下一个阶乘b loop;循环backstrr5,r0,#4;将计算所得的总和存入结构体中ldnfd SP!,R4-R5;恢复寄存器值movpc,lr;summing子程序返回END;汇编代码结束2008年10月23日67南京大学计算机系例例5 ARM汇编子程序嵌套调用举例汇编子程序嵌套调用举例-6;the details of parameters transfer comes from ATPCS;if there are more than 4 args,stack will be used;这个ARM汇编函数也可以被C函数调用,符合ATPCS规范;int asmFac(int n)EXPORT asmFac AREA ASMFILE,CODE,READONLYasmFacmovr1,r0;r1=nloopsubsr1,r1,#1;将r1减1mulgtr0,r1,r0;如果大于0,则乘上r1(相当与n*(n-1)bgtloop;如果大于0,继续mov pc,lr;asmFac子程序返回END;汇编代码结束2008年10月23日68南京大学计算机系ARM9五级流水线互锁现象举例五级流水线互锁现象举例l互锁使得指令的执行周期增加,下面举例说明:lLDR r1,r2,#8lADD r0,r0,r1lMOV r2,#02008年10月23日69南京大学计算机系5.8.9 5级流水线的互锁问题级流水线的互锁问题 lARM9指令流水线有5级。五个流水线阶段分别是:取指、译码、ALU、LS1、