zoukankan      html  css  js  c++  java
  • ARM相关

    ARM-Thumb子程序调用规则—ATPCS

    能使C语言程序和汇编程序之间能够互相调用,必须为子程序间的调用制定规则。在ARM处理器中,这个规则被称为ATPCS:ARM程序和Thumb程序中子程序调用的规则。

    基本的ATPCS规则包括寄存器使用规则、数据栈使用规则、参数传递规则

    1.寄存器使用规则

    ARM处理器中有r0-r15共16个寄存器,它们的用途是有一些约定的习惯的,并依据这些用途定义了别名。

    1)子程序间通过寄存器r0-r3来传递参数,这时可以使用它们的别名a1-a4,被调用的子程序返回前无需回复r0-r3的内容。

    2)在子程序中,使用r4-r11来保存局部变量,这时可以使用它们的别名v1-v8,如果在子程序中使用了它们的某些寄存器,子程序进入时要保存这些寄存器的值,返回时再次恢复它们;

    对于子程序中没有使用到的寄存器,则不必进行这些操作,在Thumb指令中,通常只能使用寄存器r4-r7来保存局部变量

    3)寄存器r12用作子程序间scratch寄存器,别名为ip。

    4)寄存器r13用作数据栈指针,别名为sp,在子程序中寄存器r13不能用作它用,它的值在进入、退出子程序时必须相等。

    5)寄存器r14称为连接寄存器,别名为lr,它用于保存子程序的返回地址。

    如果在子程序中保存了返回地址(比如将lr值保存到数据栈中),r14可用作它用。

    6)寄存器r15是程序计数器,别名pc

    2.数据栈使用规则

    数据栈有两个增长方向;向内存地址减小的方向增长时,称为DESCENDING栈;向内存地址增加的方向增长时,称为ASCENDING栈。

    所谓数据栈的增长就是移动栈指针。当栈指针指向栈顶元素(最后一个入栈的数据)时,称为FULL栈;当栈指针指向栈顶元素相邻的一个空的数据单元时,称为EMPTY栈。

    综合这两个特点,数据栈可以分为以下4种:

    1)FD: Full Descending,满递减。

    2)ED:Empty Descending,空递减。

    3)FA:Full Ascending,满递增。

    4)EA:Empty Ascending,满递增。

    ATPCS规定数据栈为FD类型,并且对数据栈的操作是8字节对齐的。使用stmdb/ldmia批量内存访问指令来操作FD数据栈。

    使用stmdb命令往数据栈中保存内容时,先递减sp指针,再保存数据,

    使用ldmia命令从数据栈中恢复命令时,先获得数据,再递增sp指针,sp指针总是指向栈顶元素,这刚好是FD栈的定义。

    stmdb和ldmia指令一般配对使用,stmdb用于将寄存器压栈,ldmia用于将寄存器弹出栈,作用是保存使用到的寄存器

    https://blog.csdn.net/minsophia/article/details/53080183

    3.参数传递规则

    一般来说,当参数个数不超过4个时,使用r0-r3这4个寄存器来传递参数;如果参数个数超过4个,剩余的参数通过数据栈来传递。

    同样,对于一般的返回结果,通常使用a0-a3来传递。

    例程:

    假设CopyCode2SDRAM函数使用C语言实现的,数据原型为:

    int CopyCode2SDRAM(unsigned char *buf,unsigned long StartAddr,int size)

    在汇编代码中,使用下面的代码调用,同时判断返回值:

    1 ldr r0,=0x30000000     @ 1、目标地址=0x30000000,这是SDRAM的起始地址
    2 
    3 mov r1,#0              @ 2、源地址=0
    4 
    5 mov r2,#16*1024        @ 3、复制长度=16K
    6 
    7 bl  CopyCode2SDRAM     @ 4、调用C函数CopyCode2SDRAM
    8 
    9 cmp a0,#0              @ 5、进行判断

    参考链接: https://blog.csdn.net/wangpengqi/article/details/8443462

                       https://blog.csdn.net/chun_1959/article/details/46604979

    LDR指令格式:

    LDR{条件} 目的寄存器 <存储器地址>
    作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。

    LDR指令的寻址方式比较灵活,实例如下:
    LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0 


    LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
    LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
    LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,然后R1=R1+8。
    LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。
    LDR R0,[R1,R2]! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。
    LDR R0,[R1,LSL #3] ;将存储器地址为R18的字数据读入寄存器R0。
    LDR R0,[R1,R2,LSL #2] ;将存储器地址为R1+R2
    4的字数据读入寄存器R0。
    LDR R0,[R1,,R2,LSL #2]! ;将存储器地址为R1+R24的字数据读入寄存器R0,并将R1+R24的值存入R1。
    LDR R0,[R1],R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
    LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

    要注意的是
    LDR Rd,[Rn],#0x04 ;这里Rd不允许是R15。

    另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。
    LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。

    LDR R0,=0xff
    这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-0XFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。

    LDR R,label 和 LDR R,=label的区别

    LDR 是ARM中的指令,也是伪指令。
    当用 LDR r, =imd // r 为寄存器, imd为立即数
    LDR 是一条伪指令。编译器会根据 立即数的大小,决定用 ldr 指令或者是mov或mvn指令。
    当imd能用mov或者mvn操作时,就将它翻译成一条mov或mvn指令。当imd大于mov或mvn能够操作的数时,编译器会将imd存在一个内存单元中,然后再用一条ldr指令加载这个内存单元的的值到寄存器中。
    LDR r, label 和 LDR r, =label的区别:
    LDR r, =label 会把label表示的值加载到寄存器中,而LDR r, label会把label当做地址,把label指向的地址中的值加载到寄存器中。
    譬如 label的值是 0x8000, LDR r, =label会将 0x8000加载到寄存器中,而LDR r, label则会将内存0x8000处的值加载到寄存器中。




     
     
     
  • 相关阅读:
    简单明了的带你理解springboot原理和三大核心注解
    Spring Boot(一):入门篇
    【Mysql优化】聚簇索引与非聚簇索引概念
    Mysql索引原理与优化
    Mysql全文索引的使用
    索引的优缺点,如何创建索引
    184 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 04 例:字符串与byte(即:字节)数组间的相互转换
    183 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 03 String常用方法(下)
    182 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 02 String常用方法(上)
    181 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 01 String常用方法简介
  • 原文地址:https://www.cnblogs.com/darren-pty/p/13928707.html
Copyright © 2011-2022 走看看