0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ATPCS基本规则

安芯教育科技 来源:极术社区 作者:Nuoeriris 2022-05-27 10:12 次阅读

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

1. ATPCS


ATPCS即ARM Thumb Procedure Call Standard(ARM-Thumb过程调用标准)的简称,ATPCS规定了一些调用和被调用程序之间调用的基本规则,这些基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则、参数的传递规则。为适应一些特定的需要,对这些基本的调用规则进行一些修改得到几种不同的子程序调用规则,这些特定的调用规则包括:

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

  • 支持只读段位置无关的ATPCS

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

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

有调用关系的所有子程序必须遵守同一种ATPCS,编译器或者汇编器在ELF格式的目标文件中设置相应的属性,标识用户选定的ATPCS类型。对应不同类型的ATPCS规则,有相应的C语言库,连接器根据用户指定的ATPCS类型连接相应的C语言库。使用ADS的C语言编译器编译的C语言子程序满足用户指定的ATPCS类型。而对于汇编语言程序来说,完全要依赖用户来保证各子程序满足选定的ATPCS类型。具体来说,汇编语言子程序必须满足下面三个条件:在子程序编写时必须遵守相应的ATPCS规则;数据栈的使用要遵守ATPCS规则;在汇编编译器中使用“--apcs”选项,使用“--apcs”选项并不影响代码的产生,编译器只是在各段中放置相应的属性,标识用户选定的属性。

2. ATPCS基本规则


基本ATPCS规定了在子程序调用时的一些基本规则,包括以下四个方面的内容:
  • 寄存器的使用规则及其相应的名字

  • 数据栈的使用规则

  • 参数传递的规则

  • 函数结果返回的规则

相对于其他类型的TPCS,满足基本ATPCS的程序的执行速度更快,所占用的内存更少。但是它不能提供以下的支持:ARM程序和THUMB程序相互调用;数据以及代码的位置无关的支持;子程序的可重入性;数据栈检查的支持。而派生的其他几种特定的ATPCS就是在基本ATPCS的基础上再添加其他的规则而形成的 ,其目的就是提供上述的功能。
2.1 寄存器的使用规则
16f6f982-dd5a-11ec-ba43-dac502259ad0.png  前四个寄存器R0~R3用于将参数值传递到例程中并将结果值传递出例程,并在例程中保存中间值(但通常仅在子例程调用之间),子程序通过寄存器R0~R3来传递参数,这时寄存器可以记作:A1~A4,被调用的子程序在返回前无需恢复寄存器R0~R3的内容。在子程序中,使用R4~R11来保存局部变量,这时寄存器R4~R11可以记作:V1~V8 。如果在子程序中使用到V1~V8的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值,对于子程序中没有用到的寄存器则不必执行这些操作。在THUMB程序中,通常只能使用寄存器R4~R7来保存局部变量。寄存器R12用作子程序间暂存寄存器,记作IP;在子程序的连接代码段中经常会有这种使用规则。寄存器R13用作数据栈指针,记做SP,在子程序中寄存器R13不能用做其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。寄存器R14用作连接寄存器,记作LR;它用于保存子程序的返回地址,如果在子程序中保存了返回地址,则R14可用作其它的用途。寄存器R15是程序计数器,记作PC;它不能用作其它用途。ATPCS中的各寄存器在ARM编译器和汇编器中都是预定义的。
2.2 数据栈的使用规则
栈指针通常可以指向不同的位置,当栈指针指向栈顶元素(即最后一个入栈的数据元素)时,称为Full栈。当栈指针指向与栈顶元素相邻的一个元素时,称为Empty栈。数据栈的增长方向也可以不同,当数据栈向内存减小的地址方向增长时,称为Descending栈。当数据栈向着内存地址增加的方向增长时,称为Ascending栈。综合这两种特点可以由以下4种数据栈:

	FD(FULL Descending):递增满栈 ED(Empty Descending):递增空栈 FA(FULL Ascending):递减满栈 EA(Empty Ascending):递减空栈 ATPCS规定数据栈为FD类型,并对数据栈的操作是8字节对齐的,下面是一个数据栈的示例及相关的名词:
  1. 数据栈栈指针,stack pointer指向最后一个写入栈的数据的内存地址。

  2. 数据栈的基地址,stack base是指数据栈的最高地址。由于ATPCS中的数据栈是FD类型的,实际上数据栈中最早入栈数据占据的内存单元是基地址的下一个内存单元。

  3. 数据栈界限,stack limit是指数据栈中可以使用的最低的内存单元地址。

  4. 已占用的数据栈,used stack是指数据栈的基地址和数据栈栈指针之间的区域,其中包括数据栈栈指针对应的内存单元。

  5. 数据栈中的数据帧(stack frames) 是指在数据栈中,为子程序分配的用来保存寄存器和局部变量的区域。

VAL(SP) <= stack base, VAL(SP) >= VAL(SL) >= stack limit + 256, VAL(LR) = return address

异常中断的处理程序可以使用被中断程序的数据栈,这时用户要保证中断的程序数据栈足够大。使用ADS编译器产生的目标代码中包含了DRFAT2格式的数据帧。在调试过程中,调试器可以使用这些数据帧来查看数据栈中的相关信息。而对于汇编语言来说,用户必须使用FRAME伪操作来描述数据栈中的数据帧。ARM汇编器根据这些伪操作在目标文件中产生相应的DRFAT2格式的数据帧。在ARMv5TE中,批量传送指令LDRD/STRD要求数据栈是8字节对齐的,以提高数据的传送速度。用ADS编译器产生的目标文件中,外部接口的数据栈都是8字节对齐的,并且编译器将告诉连接器:本目标文件中的数据栈是8字节对齐的。而对于汇编程序来说,如果目标文件中包含了外部调用,则必须满足以下条件:外部接口的数据栈一定是8位对齐的,也就是要保证在进入该汇编代码后,直到该汇编程序调用外部代码之间,数据栈的栈指针变化为偶数个字;在汇编程序中使用PRESERVE8伪操作告诉连接器,本汇编程序是8字节对齐的。17248938-dd5a-11ec-ba43-dac502259ad0.png
2.3 参数的传递规则
根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变的子程序。这两种子程序的参数传递规则是不同的。参数个数可变的子程序参数传递规则,对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递,当参数超过4个时,还可以使用数据栈来传递参数。在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。然后,依次将各名字数据传送到寄存器R0,R1,R2,R3;如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递。参数个数固定的子程序参数传递规则,对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同,如果系统包含浮点运算的硬件部件,浮点参数将按照下面的规则传递:各个浮点参数按顺序处理;为每个浮点参数分配FP寄存器;分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器。第一个整数参数通过寄存器R0~R3来传递,其他参数通过数据栈传递。
2.4 子程序结果返回规则
  1. 结果为一个32位的整数时或小于32位的整数值以保留符号和符号的方式扩展为32位值的范围,可以通过寄存器R0返回。

  2. 结果为一个64位整数时,一个64位整数值被视为两个32位整数值,可以通过R0和R1返回,依此类推。

  3. 对于位数更多的结果,需要通过调用内存来传递,任何其它类型的值(例如结构化值)将转换为32位整数字序列,通过将其复制到连续的内存字中。

175d7626-dd5a-11ec-ba43-dac502259ad0.png  根据上面简单的测试可以看出:

	MOVS r2,#0x03 MOVS r1,#0x02 MOVS r0,#0x01 通过寄存器R0~R3来传递参数:

	ADDS r0,r3,r1 ADDS r0,r0,r2 通过寄存器R0返回。

3. 特定的ATPCS


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

如果在程序设计期间能够准确地计算出程序所需的内存总量,就不需要进行数据栈的检查,但是在通常情况下这是很难做到的,这时需要进行数据栈的检查。在进行数据栈的检查时,使用寄存器R10作为数据栈限制指针,这时寄存器R10又记作SL。用户在程序中不能控制该寄存器。具体来说,支持数据栈限制的ATPCS要满足下面的规则:在已经占有的栈的最低地址和SL之间必须有256字节的空间,也就是说,SL所指的内存地址必须比已经占用的栈的最低地址低256个字节。当中断处理程序可以使用用户的数据栈时,在已经占用的栈的最低地址和SL之间除了必须保留的256个字节的内存单元外,还必须为中断处理预留足够的内存空间;用户在程序中不能修改SL的值;数据栈栈指针SP的值必须不小于SL的值。与支持数据栈限制检查的ATPCS相关的编译/汇编选项有下面几种:选项./ swst (编译过程中对输入文件使用堆栈检测)指示编译器生成的代码遵守支持数据栈限制检查的ATPCS,用户在程序设计期间不能够准确计算程序所需的数据栈大小时,需要指定该选项;选项./ noswst (编译过程中对输入文件不使用堆栈检测,这是编译器默认选项)指示编译器生成的代码不支持数据栈限制检查的功能,用户在程序设计期间能够准确计算出程序所需的数据栈大小,可以指定该选项;选项./ swst如果汇编程序对于是否进行数据栈检查无所谓,而与该汇编程序连接的其他程序指定了选项./ swst。对于256字节或更少的帧,可以按如下方式检查:

	CMP sp, sl BHS no_ovf BL |__16__rt_stkovf_split_small| no_ovf 对于大于 256 字节的帧,可以如下方式检查:

	LDR wr, framesize ADD wr, sp CMP wr, sl BHS no_ovf BL |__16__rt_stkovf_split_big| no_ovf MOV sp,wr ; ... ALIGN Framesize DCD –Framesize 
3.2 编写遵守支持数据栈限制检查的ATPCS的汇编语言程序
对于C程序和C++程序来说,如果在编译时指定了选项./swst,生成的目标代码将遵守支持数据栈限制检查的ATPCS。对于汇编语言程序来说,如果要遵守支持数据栈限制检查的ATPCS,用户在编写程序时必须满足支持数据栈限制检查的ATPCS所要求的规则,然后指定选项./swst,下面介绍用户编写汇编语言程序时的一些要求。178aa7f4-dd5a-11ec-ba43-dac502259ad0.png
3.3 叶子子程序是指不调用别的程序的子程序
数据栈小于256字节的叶子子程序不许要进行数据栈检查,如果几个子程序组合起来构成的叶子子程序数据栈也小于256字节,这个规则同样适用;数据栈小于256字节的非叶子子程序可以使用下面的代码段来进行数据栈检查。ARM程序使用:

	SUB sp,sp,#size ; #size 为sp和sl之间必须保留的空间大小 CMP sp,sl; BLLO _ARM_stack_overflow THUMB程序使用:

	ADD sp,#-size ; #size为sp和sl之间必须保留的空间大小 CMP sp,sl; BLLO _THUMB_stack_overflow 数据栈大于256字节的子程序,为了保证SP的值不小于数据栈可用的内存单元最小的地址值,需要引入相应的寄存器。在使用超过 256 字节堆栈空间的例程中检查溢出更为复杂,不能简单地从SP减去帧大小。在这种情况下,必须使用如下序列向限制检查代码建议SP的新值:ARM程序使用下列代码:

	SUB ip,sp,#size; CMP ip,sl; BLLO _ARM_stack_overflow THUMB程序使用下列代码:

	LDR wr,#-size; ADD wr,sp; CMP wr,sl; BLLO _THUMB_stack_overflow 在编译或汇编时,/interwork (指定输入文件符合ARM/Thumb交互标准)告诉编译器或汇编器生成的目标代码遵守支持ARM-THUMB的ATPCS,它用在以下场合:
  • 程序中存在ARM程序调用THUMB程序的情况

  • 程序中存在THUMB程序调用ARM程序的情况

  • 需要连接器来进行ARM状态和THUMB状态切换的情况

在下述情况下使用选项/nointerwork:程序中不包含THUMB程序;用户自己进行ARM程序和THUMB程序切换。需要注意的是:在同一个C/C++程序中不能同时有ARM指令和THUMB指令。17b3d426-dd5a-11ec-ba43-dac502259ad0.png  \_\_asm 关键字用于调用内联汇编程序,可以用在C或C++源码中内嵌汇编语言,如下所示:17e3495e-dd5a-11ec-ba43-dac502259ad0.png  ATPCS规则就是定义了函数传参以及返回数据的标准,定义了寄存器在函数调用时的作用。

						

						

						

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7591

    浏览量

    135795
  • 函数
    +关注

    关注

    3

    文章

    4276

    浏览量

    62314
  • 系统控制
    +关注

    关注

    0

    文章

    33

    浏览量

    16205

原文标题:技术分享 | Cortex-M0中断控制和系统控制(七)

文章出处:【微信号:Ithingedu,微信公众号:安芯教育科技】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    网关的设置规则

    网关的设置规则涉及多个方面,包括硬件安装、网络连接、基本配置、高级配置以及安全设置等。以下是一篇关于网关设置规则的详细指南,旨在帮助用户正确配置和管理网关设备。
    的头像 发表于 09-30 11:48 943次阅读

    AD9元器件间距规则如何设置

    在Altium Designer 9(简称AD9)中设置元器件间距规则,主要是为了确保PCB(Printed Circuit Board,印刷电路板)上的元器件之间保持适当的距离,以避免短路、干扰或
    的头像 发表于 09-02 15:26 2156次阅读

    高速pcb布线规则有哪些

    高速pcb布线规则有哪些 高速PCB布线规则 摘要:随着电子技术的快速发展,高速PCB设计变得越来越重要。为了确保信号完整性和电磁兼容性,遵循一定的布线规则至关重要。本文将详细介绍高速PCB布线
    的头像 发表于 06-10 17:33 714次阅读

    Altium Designer电气规则设置后无报错原因解析

    可是很多时候我们明明是在规则编辑器里面设置了规则的,为什么在我们规则之外的时候它竟然不报错呢?是哪里设置不对吗?
    发表于 03-28 09:35 1728次阅读
    Altium Designer电气<b class='flag-5'>规则</b>设置后无报错原因解析

    如何优化 PCB 布线规则

    本文要点在PCB布线中不使用规则可能会出现的问题。设计中可使用的不同类型PCB布线规则。如何在PCB布线中应用规则和约束。“限制”一词通常具有负面色彩,会引起人们的警惕。但实际上,对于整体的正向发展
    的头像 发表于 02-19 13:00 1128次阅读
    如何优化 PCB 布线<b class='flag-5'>规则</b>?

    pcb设计布局布线原则及规则

    一站式PCBA智造厂家今天为大家讲讲pcb设计布局布线原则及规则有哪些?PCB设计六大布线规则。在PCB设计中,布线是至关重要的一步。合理有效的布线能够保证电路的稳定性和可靠性,避免电路布线错误带来
    的头像 发表于 01-22 09:23 2014次阅读

    pcb走线的规则设置方法介绍

    随着电子产品的迅速发展,PCB(Printed Circuit Board)在电子设计中扮演着重要的角色。设计PCB走线时,合理设置规则是确保电路在安全、稳定、高效工作的基础。本文将详细介绍PCB走
    的头像 发表于 01-09 10:45 2332次阅读

    移轴相机对焦规则概述

    移轴相机可能被认为仅由两个基本规则来管理:Scheimpflug Rule 和 Hinge Rule。虽然标准的“镜头方程式” 也是一个因素, 但它已经被刚刚引用的两条规则所涵盖。
    的头像 发表于 01-08 11:47 522次阅读
    移轴相机对焦<b class='flag-5'>规则</b>概述

    ad覆铜规则怎么设置距离

    AD覆铜规则是指在PCB板上通过化学方法将铜层覆盖在绝缘层上,用于实现电路连接和信号传输。距离是指AD覆铜之间的间距,通常也称为覆铜间距。合理的AD覆铜规则设置能够保证电路的正常工作和可靠性,同时也
    的头像 发表于 12-20 10:46 4393次阅读

    什么叫电气规则呢?电气规则检查-ERC

    ERC全称为electrical rule checking,翻译为电气规则检查。检测的是GDS版图中是否存在电学连接问题,属于PV(physical verification)的一个项目。
    的头像 发表于 12-06 14:30 1824次阅读

    了解SiC器件的命名规则

    了解SiC器件的命名规则
    的头像 发表于 11-27 17:14 782次阅读
    了解SiC器件的命名<b class='flag-5'>规则</b>

    python变量命名规则

    规则和约定。本文将详尽、详实、细致地探讨Python变量的命名规则,帮助读者了解如何正确命名变量并在编程中遵循最佳实践。 一、变量命名规则的重要性 合适的变量命名对于编写清晰、易读和易于维护的代码至关重要。当我们编写代码时,变
    的头像 发表于 11-23 15:44 1156次阅读

    英飞凌IGBT模块命名规则

    英飞凌IGBT模块命名规则
    的头像 发表于 11-23 09:09 1505次阅读
    英飞凌IGBT模块命名<b class='flag-5'>规则</b>

    英飞凌IGBT单管命名规则

    英飞凌IGBT单管命名规则
    的头像 发表于 11-23 09:09 1291次阅读
    英飞凌IGBT单管命名<b class='flag-5'>规则</b>

    pcb设计元器件布局布线基本规则是什么

    一站式PCBA智造厂家今天为大家讲讲 pcb设计常见布线规则有哪些?PCB设计常见布线规则
    的头像 发表于 11-14 09:17 1205次阅读
    pcb设计元器件布局布线基本<b class='flag-5'>规则</b>是什么