实验二ARM指令系统试验讲师:杨行【实验目的】1、了解ARM汇编语言2、掌握简单C语言嵌套ARM汇编语言编程;3、了解APCS规范;【实验原理】一、介绍APCS,ARM 过程调用标准(ARM Procedure Call Standard),提供了紧凑的编写例程的一种机制,定义的例程可以与其他例程交织在一起。
最显著的一点是对这些例程来自哪里没有明确的限制。
它们可以编译自C、Pascal、也可以是用汇编语言写成的。
APCS 定义了:对寄存器使用的限制。
使用栈的惯例。
在函数调用之间传递/返回参数。
可以被‘回溯’的基于栈的结构的格式,用来提供从失败点到程序入口的函数(和给予的参数)的列表。
APCS 不一个单一的给定标准,而是一系列类似但在特定条件下有所区别的标准。
例如,APCS-R (用于RISC OS)规定在函数进入时设置的标志必须在函数退出时复位。
在32 位标准下,并不是总能知道进入标志的(没有USR_CPSR),所以你不需要恢复它们。
如你所预料的那样,在不同版本间没有相容性。
希望恢复标志的代码在它们未被恢复的时候可能会表现失常...如果你开发一个基于ARM 的系统,不要求你去实现APCS。
但建议你实现它,因为它不难实现,且可以使你获得各种利益。
但是,如果要写用来与编译后的C 连接的汇编代码,则必须使用APCS。
编译器期望特定的条件,在你的加入(add-in)代码中必须得到满足。
一个好例子是APCS 定义a1 到a4 可以被破坏,而v1 到v6 必须被保护。
二、C语言嵌套ARM汇编语言int (*my_printf)(const char *format, ...);int main(void){int n = 5;int m = 1;int ret;my_printf = (void *)0x33f963a8;// 1 + 2 * 3 - 5__asm__ __volatile__(/*汇编程序*/"mov r0, %1\n""mov r1, %2\n""sub r2, r0, r1\n""mov %0, r2\n":"=r"(ret) /*输出部,=代表输出*/:"r"(n),"r"(m) /*输入部,r代表和寄存器相关联*/:"r0","r1","r2" /*保护部*/);my_printf("[ ret = %d]\n", ret);return 0;}三、汇编语言编程.text.global _start_start: @这个是裸板程序的入口函数@lr寄存器是程序链接寄存器,是pc的备份stmfdsp!,{r0-r12,lr} @函数跳转的时候,保存现场bl mainldmfdsp!,{r0-r12,pc} @函数跳转的时候,恢复现场【实验仪器】1、装有Linux操作系统的PC机一台;2、mini2440实验开发平台一套【实验内容】1、在u-boot环境下,使用c语言嵌套ARM汇编语言实现从串口输入两个数,并计算两个数的和,通过串口输出;以下是输入两个个位数然后计算其和;int (*my_getc)();int (*my_printf)(const char *format,...);int _start(){char ch;my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;ch=my_getc();my_printf("a= %c\n",ch);a=ch-48;ch=my_getc();my_printf("b= %c\n",ch);b=ch-48;__asm__ __volatile__("mov r0,%1\n""mov r1,%2\n""add r2,r1,r0\n""mov %0,r2\n":"=r"(c):"r"(a),"r"(b):"r0","r2","r3");my_printf("%d+%d=%d\n",a,b,c);return 0;}2、在u-boot环境下,使用c语言嵌套ARM汇编语言实现从串口输入两个数,并计算两个数的积,通过串口输出;以下是计算两个个位数积的源程序int (*my_getc)();int (*my_printf)(const char *format,...);int _start(){char ch;inta,b,c;my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;ch=my_getc();my_printf("a= %c\n",ch);a=ch-48;ch=my_getc();my_printf("b= %c\n",ch);b=ch-48;__asm__ __volatile__("mov r0,%1\n""mov r1,%2\n""mul r2,r1,r0\n""mov %0,r2\n":"=r"(c):"r"(a),"r"(b):"r0","r2","r3");my_printf("%d*%d=%d\n",a,b,c);return 0;}3、在u-boot命令行输入一个数,先写入0x30008000地址然后从从0x30008000地址读出数据。
int (*my_getc)();int (*my_printf)(const char *format,...);int _start(){char ch;inta,b;my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;my_printf("please input a number from 0 to 9\n");ch=my_getc();a=ch-48;__asm__ __volatile__("mov r0,%0\n""ldr r1,=0x30008000\n""str r0,[r1]\n""mov %0,r2\n"::"r"(a):"r0","r1","r2");my_printf("write memory number is %d\n",a);__asm__ __volatile__("ldr r0,=0x30008000\n""ldr r1,[r0]\n""mov %0,r1\n":"=r"(b):my_printf("read memory number is %d\n",b);return 0;}4、使用u-boot从命令行中输入三个数,并且写入0x30008000起始的满递减栈中,并从栈中读出,输出到命令行;int (*my_getc)();int (*my_printf)(const char *format,...);int _start(){char ch;inta,b,c;my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;my_printf("please input a \n");ch=my_getc();a=ch-48;my_printf("a=%d \n",a);my_printf("please input b \n");ch=my_getc();b=ch-48;my_printf("b=%d \n",b);my_printf("please input c \n");ch=my_getc();c=ch-48;my_printf("c=%d \n",c);__asm__ __volatile__("mov r0,%0\n""mov r1,%1\n""mov r2,%2\n""ldrsp,=0x30008000\n""stmfdsp!,{r0-r2}\n"::"r"(a),"r"(b),"r"(c):"r0","r1","r2");my_printf("write memory from 0x30008000 is %d,%d,%d\n",a,b,c);__asm__ __volatile__("ldmfdsp!,{r0-r2}\n""mov %0,r0\n""mov %1,r1\n""mov %2,r2\n"::"r0","r1","r2");my_printf("read memory from 0x30008000 is %d,%d,%d\n",a,b,c);return 0;}5、使用bl实现函数调用int (*my_getc)();int (*my_printf)(const char *format,...);void test();int _start(){my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;my_printf("hello world\n");__asm__ __volatile__("bl test\n");my_printf("after test do\n");}void test(){my_printf("hello test\n");}6、实现C语言条件判断语句if(b==0)a++;elsea--;int (*my_getc)();int (*my_printf)(const char *format,...);int _start(){char ch;inta,b,c,d;my_getc=(void *)0x33f965f0;my_printf=(void *)0x33f963a8;my_printf("please input a \n");ch=my_getc();a=ch-48;my_printf("a=%d \n",a);my_printf("if you input 0 then output a+1 ,else a-1 \n");ch=my_getc();b=ch-48;my_printf("b=%d \n",c);__asm__ __volatile__("mov r0,%2\n""mov r1,%3\n""movs r2,r1\n""addeq r0,r0,#1\n""subne r0,r0,#1\n""mov %0,r0\n""mrs %1,cpsr\n":"=r"(c),"=r"(d):"r"(a),"r"(b):"r0","r1","r2");my_printf("output a=%d\n",c);my_printf("cpsr=%x,",d);return 0;}【思考题】1、使用u-boot自带函数与ARM汇编程序实现y=a+b*c-d操作2、函数之间共享内存传递参数,函数间寄存器传递参数;3、函数间通过堆栈传递参数;4、计算两个64位数的和;。