ARM-elf-gcc的C语言内嵌汇编语言

来源:互联网 发布:swagger ui 搭建mac 编辑:程序博客网 时间:2024/05/30 23:03

 在用embest ide调试s3c44b0的时候,想在C环境下操作内部寄存器。查了很多资料可是编译始终通不过。照着书上__ASM格式还是错。后来经过一天一夜的努力,终于实现了,现在传上来大家一起研究一下~~
    网上说的都是80x86的内嵌汇编,跟据那上面的格式来编译是通不过的。还有 arm-elf-gcc和arm-linux-gcc的语法也是不同的。
     刚开始时在网上看到一位仁兄写的调试笔记,他说自己没有钱买仿真器,只可以烧程序。他是用ADS调试的,要想看内部寄存器(R0-R15)级必须读这些寄存器,然后通过串口来观察。但是在C的环境下操作内部寄存器是不可能的,只能在C中内嵌汇编。
    我用的是embest ide ,因为给的例子都是GCC环境下的,所以我就用的这个环境在调,刚开始我把上面那位仁兄的程序COPY过来,完全编译不同,后来我一句一句的删 发现两个环境下的语法完全不同,于是我就到晚上找例子,没什么收获。下面是那位仁兄的代码,在ADS下可能适用(没有测试过)
int ReadPC(int argc, char *argv[])
{
     U32 i;
     U16 j,k;
 __asm
 {
      mov i,R15
 }
 j=i/0x10000;
 k=i%0x10000;
 printf("PC Value = 0x%x /n",i);
 printf("PC Value = %d - %d /n" ,j,k);
 __asm
 {
      MRS i,CPSR
 }
 j=i/0x10000;
 k=i%0x10000;
 printf("CPSR Value = 0x%x /n",i);
 printf("CPSR Value = %d - %d /n" ,j,k);
 return 0;
}

书上倒是有一个例子,不过只有一句:
__ASM("MOV R0,R0");
我把这一句写上去 结果编译通过了,我还以为解决了。但是接下来又遇到一个问题 怎么把寄存器的值传给C中的变量呢?我也尝试着直接在汇编中使用变量MOV I,R15结果又报错。
    再后来在CSDN上看到有人说:定义    int get_R0(void){}
                                                           然后调用int I=get_R0;
    我想不太可能吧 但是事实是确实得到了R0的值,刚开始想不同,还以为get_R0()是一个库函数,我把R0换成R15,结果奇怪的是得到的也是R0的值。我把get_R0换成mm__R0结果还是可以到R0的值。虽然不懂为什么,但是我把程序改了下达到了我的目的。在int I=get_R0;前面用__ASM("MOV R0,R15");这样就得到了R15也就是PC的值。一看手机都凌晨3.半了,关机睡觉。
     第二天早上起了个早,有摸索了几个小时,意外发现用LDR R1 ,=I这句编译居然没有错,呵呵。太好了总算和C链接起来了,这下好办了,直接把R15的值给R0然后STR R0,[R1]这样就把R15的值赋给变量了。
__ASM("LDR R1,=I
               MOV R0,R15
               STR R0,[R1]
              ")
编译、链接,运行。串口没有反应。还好我有仿真器,单步调试发现出现了未定义指令异常,程序跳到0X00000004处去了。我打开汇编窗口发现在这几句指令后面多了一条不认识的东西:
0x0c0019a4  stfeqd     f3, [r0], -#800
我把所有的语句删了 这条语句还是会出现,也就说是只要用到__ASM就会出现这个东西。
每次运行到这里就发生异常,于是我就把程序改成这样了:运行,结果完全显示了PC的值:
 __asm("ldmfd sp,{r0,r1}
   ldr r1,=Mr15
   mov r0,r15
   sub r0,r0,#0x16     //还原当前PC的值
   str r0,[r1]
   stmfd sp!,{r0,r1}
   add pc,pc,#0x01   //为了跳过那条未定义的指令
   ");
 Uart_Printf("/npc=0x%x/n",Mr15);
本来想把这段定义为宏,以后要用就直接展开。可是这个__ASM的格式太苛刻了,没有成功,只能这样了。不过应该可以包装成函数,到时候直接读LC-8就是PC的值了。。。。