第 4 章 特定于编译器的内部函数
总结了 ARM® 编译器特定的内在函数,它们是 C 和 C++ 标准的扩展。
要使用这些内在函数,您的源文件必须包含#include <arm_compat.h>。
它包含以下部分:
4.1 __breakpoint intrinsic.
4.2 __current_pc intrinsic.
4.3 __current_sp intrinsic.
4.4 __disable_fiq intrinsic.
4.5 __disable_irq intrinsic.
4.6 __enable_fiq intrinsic.
4.7 __enable_irq intrinsic.
4.8 __force_stores intrinsic.
4.9 __memory_changed intrinsic.
4.10 __schedule_barrier intrinsic.
4.11 __semihost intrinsic.
4.12 __vfp_status intrinsic.
4.1 __breakpoint 内在函数
这个内在将BKPT 指令插入到编译器生成的指令流中。要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
它使您能够在 C 或 C++ 代码中包含断点指令。
语法
void __breakpoint(int
) val
其中:
val
是一个编译时常量整数,其范围是:
0 ... 65535
如果您将源代码编译为 ARM 代码
0 ... 255
如果您将源代码编译为 Thumb 代码。
错误
为不支持 BKPT 指令的目标进行编译时,__breakpoint 内在函数不可用。在这种情况下,编译器会产生错误。
示例
void func(void) { ... __breakpoint(0xF02C); ... }
4.2 __current_pc 内在函数
此内在函数使您能够确定程序中使用内在函数的点处的程序计数器的当前值。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
语法
unsigned int __current_pc(void)
返回值
__current_pc 内在函数返回程序中使用内在函数的点处的程序计数器的当前值。
4.3 __current_sp 内在函数
这个内在函数返回程序中当前点的堆栈指针的值。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
语法
unsigned int __current_sp(void)
返回值
__current_sp 内在函数返回堆栈指针在程序中使用内在函数的点的当前值。
4.4 __disable_fiq 内在函数
这个内在禁用 FIQ 中断。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
注意:
通常,此内在函数通过设置 CPSR 中的 F 位来禁用 FIQ 中断。但是,对于 v7-M 和 v8-M.mainline,它会设置故障屏蔽寄存器 (FAULTMASK)。 v6-M 和 v8-M.baseline 不支持此内在函数。
语法
int
__disable_fiq(void
)
用法
int __disable_fiq(void);禁用快速中断并返回 FIQ 中断掩码在禁用中断之前在 PSR 中的值。
返回值
int __disable_fiq(void);返回禁用 FIQ 中断之前 FIQ 中断掩码在 PSR 中的值。
限制
__disable_fiq 内部函数只能在特权模式下执行,即在非用户模式下。在用户模式下,此内在函数不会更改 CPSR 中的中断标志。
示例
void foo(void) { int was_masked = __disable_fiq(); /* ... */ if (!was_masked) __enable_fiq(); }
4.5 __disable_irq 内在函数
这个内在禁用IRQ 中断。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
注意:
通常,此内在函数通过设置 CPSR 中的 I 位来禁用 IRQ 中断。然而,对于 M-profile,它设置了异常屏蔽寄存器 (PRIMASK)。
语法
int
__disable_irq(void
)
用法
int __disable_irq(void);禁用中断并返回禁用中断前 IRQ 中断掩码在 PSR 中的值。
返回值
int __disable_irq(void);返回禁用 IRQ 中断之前 IRQ 中断掩码在 PSR 中的值。
示例
void foo(void) { int was_masked = __disable_irq(); /* ... */ if (!was_masked) __enable_irq(); }
限制
__disable_irq 内部函数只能在特权模式下执行,即在非用户模式下。在用户模式下,此内在函数不会更改 CPSR 中的中断标志。
4.6 __enable_fiq 内在函数
这个内在启用FIQ 中断。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
注意:
通常,此内在函数通过清除 CPSR 中的 F 位来启用 FIQ 中断。但是,对于 v7-M 和 v8-M.mainline,它会清除故障屏蔽寄存器 (FAULTMASK)。 v6-M 和 v8-M.baseline 不支持此内在函数。
语法
void __enable_fiq(void)
限制
__enable_fiq 内部函数只能在特权模式下执行,即在非用户模式下。在用户模式下,此内在函数不会更改 CPSR 中的中断标志。
4.7 __enable_irq 内在函数
这个内在启用IRQ 中断。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
注意:
通常,此内在函数通过清除 CPSR 中的 I 位来启用 IRQ 中断。但是,对于 Cortex M-profile 处理器,它会清除异常屏蔽寄存器 (PRIMASK)。
语法
void __enable_irq(void)
限制
__enable_irq 内部函数只能在特权模式下执行,即在非用户模式下。在用户模式下,此内在函数不会更改 CPSR 中的中断标志。
4.8 __force_stores 内在函数
这个内在导致所有在当前函数之外可见的变量,例如具有指向它们的指针传入或传出函数的变量,如果它们已被更改,则将它们写回内存。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
此内在函数也充当 __schedule_barrier 内在函数。
语法
void __force_stores(void)
4.9 __memory_changed 内在函数
这个内在函数使编译器表现得好像所有 C 对象都在该时间点读取和写入了它们的值。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
编译器确保每个 C 对象的存储值在该时间点是正确的,然后将存储的值视为未知。
此内在函数也充当 __schedule_barrier 内在函数。
语法
void __memory_changed(void)
4.10 __schedule_barrier 内在
这个内在创造了一个特殊的序列点,它可以防止有副作用的操作在任何情况下都经过它。如果不影响程序行为,正常序列点允许具有过去副作用的操作。没有副作用的操作不受内在限制,编译器可以将它们移动到序列点之外。
具有副作用的操作不能在 __schedule_barrier 内在函数之上或之下重新排序。要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
与 __force_stores 内在函数不同,__schedule_barrier 内在函数不会导致内存更新。 __schedule_barrier 内部函数类似于 __nop 内部函数,不同之处在于它不生成 NOP 指令。
语法
void __schedule_barrier(void)
4.11 __semihost 内在函数
这个内在将SVC 或BKPT 指令插入到编译器生成的指令流中。它使您能够从独立于目标体系结构的 C 或 C++ 进行半主机调用。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
语法
int __semihost(int
, const void *val
)ptr
其中:
val
是半主机请求的请求代码。
ptr
是指向参数/结果块的指针。
返回值
半主机调用的结果作为显式返回值或作为指向数据块的指针传递。
用法
使用 C 或 C++ 中的此内在函数为您的目标和指令集生成适当的半主机调用:
SVC 0x123456
处于 ARM 状态,不包括 M-profile 架构。
SVC 0xAB
处于 Thumb 状态,不包括 M-profile 架构。 ARM 或第三方的所有调试目标都不能保证此行为。
HLT 0xF000
处于 ARM 状态,不包括 M-profile 架构。
HLT 0x3C
处于 Thumb 状态,不包括 M-profile 架构。
BKPT 0xAB
用于 M-profile 架构(仅限 Thumb)。
实现
对于非 Cortex-M 配置文件的 ARM 处理器,使用 SVC 或 HLT 指令实现半主机。对于 Cortex M-profile 处理器,半主机是使用 BKPT 指令实现的。要使用基于 HLT 的半主机,您必须在 #include <arm_compat.h> 之前定义预处理器宏 __USE_HLT_SEMIHOSTING。默认情况下,ARM® 编译器发出 SVC 指令而不是 HLT 指令来进行半主机调用。如果您定义此宏 __USE_HLT_SEMIHOSTING,则 ARM 编译器会发出 HLT 指令而不是 SVC 指令以进行半主机调用。
这个宏 __USE_HLT_SEMIHOSTING 的存在不会影响仍然使用 BKPT 进行半主机的 M-profile 架构。
示例
char buffer[100]; ... void foo(void) { __semihost(0x01, (const void *)buffer); }
使用选项 -mthumb 编译此代码会显示生成的 SVC 指令:
foo: ... MOVW r0, :lower16:buffer MOVT r0, :upper16:buffer ... SVC #0xab ... buffer: .zero 100 .size buffer, 100
4.12 __vfp_status 内在函数
这个内在读取或修改 FPSCR。
要使用此内在函数,您的源文件必须包含#include <arm_compat.h>。这仅适用于 AArch32。
语法
unsigned int __vfp_status(unsigned int
, unsigned int mask
)flags
用法
使用此内在函数来读取或修改 FPSCR 中的标志。
如果掩码和标志为 0,则内部函数返回未修改的 FPSCR 的值。
您可以使用 mask 和 flags 中的位清除、设置或切换 FPSCR 中的各个标志,如下表所示。如果掩码和标志不都是 0,则内部函数返回 FPSCR 的修改值。
表 4-1 修改 FPSCR 标志
mask bit | flags bit | Effect on FPSCR flag |
---|---|---|
0 | 0 | Does not modify the flag |
0 | 1 | Toggles the flag |
1 | 1 | Sets the flag |
1 | 0 | Clears the flag |
注意:
如果您只想读取或修改 FPSCR 中的异常标志,那么 ARM 建议您使用 <fenv.h> 中的标准 C99 功能。
错误
如果您在为没有 VFP 的目标进行编译时尝试使用此内在函数,编译器会生成错误。