ARM体系结构与编程-第六章

第六章 ATPCS 介绍

为了使单独编译的C语言和汇编程序之间能够相互调用,必须为子程序间的调用规定一定的规则。ATPCS就是ARM和Thumb程序中子程序调用的基本规则

6.1 ATPCS 概述

基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则、参数的传递规则。根据需要分为

  • 支持数据栈限制检查的ATPCS

  • 支持只读段位制无关(ROPI)的 ATPCS

  • 支持可读写段位置无关(RWPI)的 ATPCS

  • 支持ARM程序和Thumb程序混合使用的ATPCS

  • 处理浮点运算的ATPCS

汇编语言子程序必须满足:

  • 在子程序编写时必须遵守相应的ATPCS规则

  • 数据栈的使用要遵守相应的ATPCS规则

  • 在汇编编译器中使用-atpcs选项

6.2 基本ATPCS

规定了在子程序调用时的一些基本规则,包括:

  • 各寄存器的使用规则及其相应的名称

  • 数据栈的使用规则

  • 参数传递的规则

相对于其他ATPCS,满足基本ATPCS的程序的执行速度更快,所占用的内存更少。但是它不能提供以下的支持:

  • ARM程序和Thumb程序相互调用

  • 数据以及代码的位置无关的支持

  • 子程序的可重入性

  • 数据栈检查支持

6.2.1 寄存器的使用规则

  • 子程序通过寄存器R0~R3来传递参数。

  • 在子程序中,使用寄存器R4~R11来保存局部变量

  • 寄存器R12用作子程序间scratch寄存器,记作ip

  • 寄存器R13用作数据栈指针,记作sp

  • 寄存器R14称为连接寄存器,记作lr

  • 寄存器R15是程序计数器,记作pc

6.2.2 数据栈使用规则

栈指针的位置,指向栈顶位置称为FULL栈;指向与栈顶元素相邻的一个可用数据单元时,称为EMPTY栈

栈的增长方向,当向内存地址减小的方向增长时,称为DESCENDING栈;当向内存地址增加的方向增长时,称为ASCENDING栈。

4种数据栈:

  • FD 满递减

  • ED 空递减

  • FA 满递增

  • EA 空递增

6.2.3 参数传递规则

  1. 参数个数固定的子程序

    如果系统包含浮点运算的硬件部件,浮点运算将按照下面的规则传递:

    • 各个浮点参数按顺序处理

    • 为每个浮点参数分配FP寄存器

    • 分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器。

    第一个整数参数,通过寄存器R0~R3来传递。其他参数通过数据栈传递。

  2. 参数个数可变的子程序

    当不超过4个时,可以使用寄存器R0~R3来传递参数;超过4个时,还可以使用数据栈来传递参数。

  3. 子程序结果返回规则:

    • 结果为32位整数时,可以通过寄存器R0返回

    • 结果为64位整数时,可以通过寄存器R0和R1返回,一次类推

    • 结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0或者s0来返回

    • 结果为复合型的浮点数时,可以通过寄存器f0~fN或者d0~dN来返回

    • 对于位数更多的结果,需要通过内存来传递。

6.3 几种特定的ATPCS

6.3.1 支持数据栈限制检查的ATPCS

  1. 基本原理

    在进行数据栈检查时,使用寄存器R10作为数据栈限制指针,这时寄存器R10又记作sl.用户在程序中不能控制该寄存器。

    这种ATPCS要满足以下规则:

    • 在已经占用的栈的最低低至和sl之间必须有256字节的空间。
    • 用户在程序中不能修改sl的值
    • 数据栈栈指针sp的值必须不小于sl的值

    支持的相关编译/汇编选项:

    • /swst(software stack limit checking)指示编译器生成的代码遵守支持数据栈限制检查的ATPCS
    • /noswst 指示编译器生成的代码不支持数据栈限制检查功能
    • /swsna(software stack limit checking applicable)如果汇编程序对于是否进行数据栈检查无所谓,而与该汇编程序连接的其他程序指定了选项/swst或选项/noswst,这时该汇编程序使用选项/swstna
  2. 编写汇编程序

    叶子子程序是指不调用别的程序的子程序

    编写支持数据栈限制检查的APTCS的汇编程序

    • 数据栈小于256字节的叶子子程序不需要进行数据栈检查

    • 数据栈小于256字节的非叶子子程序使用下面代码段

      ARM程序

      SUB sp, sp, #size  ;#size为sp和sl
      CMP sp, sl
      BLLO __ARM_stack_overflow

      Thumb程序

      ADD sp, #-size
      CMP sp, sl
      BLO __Thumb_stack_overflow
    • 数据栈大于256字节的子程序

      为了保证sp的值不小于数据栈可用的内存单元最小的地址值,需引入相应的寄存器

      ARM程序

      SUB ip, sp, #size
      CMP ip, sl
      BLLO __ARM_stack_overflow

      Thumb程序

      LDR wr, #-size
      ADD wr, sp
      CMP wr, sl
      BLO __Thumb_stack_overflow

6.3.2 支持只读段位置无关(ROPI)的APTCS

  1. 支持只读段位置无关(ROPI)的ATPCS的应用场合

    可以避免必须将程序放在特定的位置

    应用场合:

    • 程序在运行期间动态加载到内存中
    • 程序在不同的场合,与不同的程序组合后加载到内存中
    • 在运行期间映射到不同的地址。
  2. 遵守支持只读段位置无关(ROPI)的ATPCS的程序设计

    • 当ROPI段中的代码引用同一个ROPI段中的符号时,必须是基于PC的
    • 当ROPI段中的代码引用另一个ROPI段中的符号时,必须是基于PC的,并且两个ROPI段的位置关系必须固定
    • 其他被ROPI段中的代码引用的必须是绝对地址,或是基于sb的可写数据
    • ROPI段移动后,对ROPI中符号的引用要作相应的调整

6.3.3 支持可读写段位置无关(RWPI)的ATPCS

​ 如果一个程序中所有的可读可写都是位置无关的,则称程序遵守支持可读可写段位置无关(RWPI)的APTCS。使用支持可读写段位置无关(RWPI)的ATPCS可以避免必须将程序存放到特定的位置。这时R9通常作为静态基址寄存器,记作sb。可重入的子程序可以在内存中同时有多个实例。各个实例拥有独立的可读写段。在生成一个新的实例时,sb指向该实例的可读写段。RWPI段中的符号的计算方法:连接器首先计算出该符号相对于RWPI段中某特定位置的偏移量,通常该特定位置选为RWPI段的第一个字节处,在程序运行时,将该偏移量加到sb上即可生成该符号的地址。

6.3.4 支持ARM程序和Thumb程序混合使用的ATPCS

在编译或汇编时,使用/interwork告诉编译器(或汇编器)生成的目标代码遵守支持ARM程序和Thumb程序混合使用的ATPCS,用在以下场合:

  • 程序中存在ARM程序调用Thumb程序的情况
  • 程序中存在Thumb程序调用ARM程序的情况
  • 需要连接器来进行ARM状态和Thumb状态切换的情况
  • 在下述情况下,使用选项/nointerwork
    • 程序中不包含Thumb程序
    • 用户自己进行ARM状态和Thumb状态切换

6.3.5 处理浮点运算的ATPCS

ATPCS支持VFP和FPA体系两种不同的浮点硬件体系和指令集。两种体系对应的代码不兼容。

上一篇:wordpress任意文件删除漏洞修复方法


下一篇:_start可以是thumb函数吗?