• ARM汇编与C混合编程


    GNU内联汇编

    内联汇编即在C中直接使用汇编语句进行编程,使程序可以在C程序中实现C语言不能完成的一些工作,例如,在下面几种情况中必须使用内联汇编或嵌入型汇编

    1. 程序中使用饱和算术运算(Saturating Arithmetic)
    2. 程序需要对协处理器进行操作
    3. 在C程序中完成对程序状态寄存器的操作
    __asm__ __volatile__("asm code":output:input:changed registers);
    

    Note:

    1. 使用__asm____volatile__表示编译器将不检查后面的内容,而是直接交给汇编器。
    2. 如果希望变压器你优化,__volatile__可以不加
    3. 没有asm code也不能省略""
    4. 没有前面的和中间的部分,不可以相应的省略:
    5. 没有changed 部分,必须相应的省略:
    6. 最后的;不能省略,对于C语言来说这是一条语句
    7. 汇编代码必须放在一个字符串内,且字符串中间不能直接按回车换行,可以写成多个字符串,注意中间不能有任何符号,这样就会将两个字符串合并为一个
    8. 指令之间必须要换行,还可以使用 使指令在汇编中保持整齐

    asm code

    "mov r0, r0
    	"
    "mov r1,r1
    	"
    "mov r2,r2"
    

    output(asm->C)

    :"constraint" (variable)
    

    "constraint"用于定义variable的存放位置:
    r表示使用任何可用的寄存器
    m表示使用变量的内存地址
    +可读可写
    =只写
    &表示该输出操作数不能使用输入部分使用过的寄存器,只能用"+&""=&"的方式使用

    input(C->asm)

    :"constraint" (variable/immediate)
    

    "constraint"用于定义variable的存放位置:
    r表示使用任何可用的寄存器(立即数和变量都可以)
    m表示使用变量的内存地址
    i表示使用立即数

    例子

    int a=100,b=200;
    int result;
    __asm__ __volatile__(
        "mov %0,%3
    	"             //%0是一个占位符,表示result,之后的类推
        "ldr r0,%1
    	"
        "ldr r1,%2
    	"
        "str r0,%2
    	"
        "str %1,%1
    	"
        :"=r"(result),"+m"(a),"+m"(b)   
        :"i"(123)
    );
    

    ATPCS

    1. 子程序间通过寄存器R0R3来传递参数,如果参数多于四个,则多出的部分用堆栈传递,被调用的子程序在返回前无须恢复寄存器R0R3的内容
    2. 在子程序中,使用寄存器R4R11来保存局部变量,如果在子程序中使用到了R4R11中的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值;对于子程序中没有用到的寄存器则不必进行这些操作,在Thumb程序中,通常只能使用寄存器R4~R7来保存局部变量
    3. R12用作子程序间scrtach寄存器(用于保存SP,在函数返回时使用该寄存器出栈),记作ip
    4. R13用作数据栈指针,记作sp
    5. R14用作连接寄存器,记作lr
    6. R15记作程序寄存器,记作pc

    相互调用

    C和汇编相互调用要特别注意遵守相应的ATPCS规则

    C调用汇编

    //.c
    #include <stdio.h>
    extern void strcopy(char* des, const char* src);
    int main(){
        const char* srcstr = "src string";
        char desstr[]="des string";
        strcopy(desstr, srcstr);
        return 0;
    }
    
    ;.asm
    .global strcopy
    strcopy:                ;R0指向目的字符串
                            ;R1指向源字符串
        LDRB R2, [R1], #1   ;加载字节并更新源字符串指针地址
        STRB R2, [R0], #1   ;存储季节并更新目的字符串指针地址
        CMP  R2, #0         ;判断是否为字符串结尾
        BNE strcopy         ;如果不是,程序跳转到strcopy继续循环
        MOV pc, ir          ;程序返回
    

    汇编调用C

    //.c
    int fcn(int a, int b , int c, int d, int e){
        return a+b+c+d+e;
    }
    
    ;.asm
    ;假设程序进入f时,R0中的值为i
    ;int f(int i){return fcn(i, 2*i, 3*i, 4*i, 5*i);}
    .text
    .global _start
    _start:
        STR lr, [sp, #-4]!  ;保存返回地址lr
        ADD R1, R0, R0      ;计算2*i(第2个参数)
        ADD R2, R1, R0      ;计算3*i(第3个参数)
        ADD R3, R1, R2      ;计算5*i
        STR R3, [SP, #-4]!  ;第5个参数通过堆栈传递
        ADD R3, R1, R1      ;计算4*i(第4个参数)
        BL fcn              ;调用C程序
        ADD sp, sp, #4      ;从堆栈中删除第五个参数
        .end
    
  • 相关阅读:
    关于如在本地虚拟机上linux系统上设置静态的ip地址
    编程规约(下)-阿里巴巴Java开发手册
    编程规约(上) -- 阿里巴巴Java开发手册
    eclipse项目导入到idea
    博客收藏
    springboot springcloud
    idea配置maven仓库
    理项目
    日志管理
    [置顶] 2016年终总结
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/6064253.html
Copyright © 2020-2023  润新知