arm汇编语言与C语言的混合编程

在C代码中实现汇编语言的方法有内联汇编和嵌入型汇编两种,使用它们可以在C语言中实现C语言不能完成的一些工作。例如,在下面几种情况必须使用内联汇编或嵌入式型汇编。

(1)、程序中使用饱和算术运算,如SSAT16和USAT16指令

(2)、程序需要对协处理器进行操作

(3)、在C语言中完成对程序状态寄存器的操作

 

1、        内联汇编

  a)     语法:

__asm

{

      汇编语句

}

因为内联汇编嵌入在C或C++程序中,所以在用法上有其自身的一些特点:

  i.          如果同一行中包含多条指令,用分号隔开。

  ii.          如果一条指令不能在一行中完成,使用“/”将其连接。

  iii.          内联汇编中使用逗号“,”作为指令操作数的分隔符,所以如果在C语言中使用逗号必须用圆括号括起来。如”__asm {ADD x, y, (f(),z)}”。

  iv.          内联汇编语言中的寄存器名被编译器视为C或C++语言中的变量,所以内联汇编中出现的寄存器名不一定和同名的物理寄存器相对应。这些寄存器咋使用前必须声明,否则编译器将提示警告信息。

  v.          内联汇编中的寄存器(除程序状态寄存器CPSR和SPSR外)在读取前必须先赋值,否则编译器将产生错误信息。

  例如:

int f(int x)    // 函数声明的方式和C语言一样
{    
    int R0;      // 声明R0寄存器    
    __asm        
    {        
        ADD R0,x,1 // 对R0赋值,之后才能对其读取操作            
        EOR x,R0,x            
    }    
    return x;    
}

  b)     例:中断使能

  该例只能运行于系统模式下,因为用户模式是无权修改程序状态寄存器的。

  参考文件(enable_irq.c)

// 内联汇编示例----中断使能
// 该例只能运行于系统模式下,因为用户模式是无权修改程序状态寄存器的。

__inline void enable_IRQ(void)
{
    int tmp;
    __asm
    {
        MRS tmp,CPSR
        BIC tmp,tmp,#0x80
        MRS CPSR_c,tmp
    }
}

__inline void disable_IRQ(void)
{
    int tmp;
    __asm
    {
        MRS tmp,CPSR
        ORR tmp,tmp,#0x80
        MRS CPSR_c,tmp
    }
}

int main(void)
{
    disable_IRQ();
    enable_IRQ();
    return 0;
}

2、        嵌入型汇编

  a)     语法:

__asm  return_type  function_name(parameter_list)
// 函数声明的方式和C语言一样
{
      汇编语句
}

  另外,如果嵌入型汇编器使用—asm选线,则初始状态为ARM状态,若使用—thumb选项,则初始状态为Thumb状态。参数是通过R0-R3传递的,不能使用参数列表中的变量。

例:字符串复制(str_cpy.c)

// 嵌入型汇编示例:字符串复制
#include <stdio.h>
__asm void my_strcpy(const char *src, const char *dst)
{
    loop
        LDRB R3,[R0],#1
        STRB R3,[R1],#1
        CMP R3, #1
        BNE loop
        MOV pc,lr
}

void main()
{
    const char *a = "Hello world";
    char b[20];
    my_strcpy(a,b);
    printf("Original string: '%s'\n", a);
    printf("Copied string: '%s'\n", b);
}

  b)     嵌入式汇编程序表达式和C表达式之间的差异

    i.          汇编程序表达式总是无符号的。相同的表达式在汇编和C语言总有不同值。

    例如:

    MOV R0,#(-33554432 / 2)    // 结果为0x7f000000

    MOV R0,#__cpp(-33554432 / 2)  // 结果为0xff000000,cpp指明的部分表示访问的是C表达式

    ii.          以0开头的汇编程序编码仍然是十进制。

    汇编程序运算符优先级顺序与C不同。例如:

    MOV R0,#(0x23 :AND: 0Xf + 1)  // ((0x23 & 0xf) + 1) =>4

    MOV R0, #__cpp(0x23 :AND: 0Xf + 1) // (0x23 & (0xf + 1)) =>0

    iii.          汇编程序字符串不是以空字符为终止标志的。

  c)     关键字__cpp

  可用__cpp关键字从汇编代码中访问C或C++ 编译时的常量表达式,其中包括含有外部链接的数据或函数地址。

3、        汇编代码访问C全局变量

  在汇编代码中访问C全局变量,只能通过 地址间接访问全局变量。例如:

  IMPORT globvar

  Start

  LDR R1,=globvar ;从内存池中读取globvar变量的地址,加载到R1中

  STR R0, [R1]

          

posted on 2013-03-16 17:02  suwen  阅读(1126)  评论(0编辑  收藏  举报

导航