__svc_indirect关键字

本文详细解释了ARM Cortex-M3中断处理函数svc_indirect的使用方式,包括svc_num、real_num、return-type参数的作用及示例应用。
2013-11-04
--luoqindong 
__svc_indirect是armcc的关键字之一(__irq也是armcc的关键字),用来修饰函数.
格式:
__svc_indirect(int svc_num) return-type function-name(int real_num[, argument-list]);
svc_num是汇编指令SVC的immediate value,在Thumb指令中该值范围为0-255 (an 8-bit value).
real_num该值通过r12寄存器传递到中断处理函数中(异常时r12会入栈, 得从栈里取出),该参数是必须有的。
return-type是函数的返回类型,该返回类型也可以放在最前面.
例子:
int __svc_indirect(0) ioctl(int svcino, int fn, void *argp);
当调用ioctl(4, RESET, NULL)时,相当于:
r12 = 4;
SVC #0 ;


触发了SVC中断,cortex-m3产生中断时,会将xPSR, PC, LR, R12, R3-R0这8个寄存器入栈,
所以ioctl的svcino参数需要从栈中取出.
<think>好的,用户现在问的是关于“__indirect”的问题。我需要先回忆一下之前对话的内容。之前用户询问了PFlash和PSRAM地址相差超过16MB的情况,我详细介绍了可能的原因和解决方案。现在这个“__indirect”可能是在嵌入式编程中的某个关键字或修饰符。 首先,我需要确定“__indirect”的具体含义。根据我的知识库,在嵌入式开发中,特别是使用某些编译器如IAR或Keil时,__indirect通常用于函数指针的间接调用。这通常涉及到处理器的特定架构,比如函数指针的大小可能比普通指针大,或者在分页内存中需要特殊处理。 接下来,用户可能的背景是什么?他们可能正在处理函数指针相关的错误,或者在移植代码时遇到了问题。例如,当使用函数指针调用时,编译器报错,提示需要__indirect修饰符。用户可能不太理解为什么需要这个关键字,或者如何正确使用它。 我需要解释__indirect的作用,例如在某些架构中,函数指针可能需要额外的信息来正确跳转,比如段选择器或扩展地址。例如,8051架构中的内存分页,或者某些处理器的大内存模型需要更大的指针。使用__indirect告诉编译器生成正确的调用代码,处理这些额外信息。 同时,用户可能想知道如何正确使用这个修饰符,比如在函数声明或函数指针定义时添加__indirect。还要注意不同编译器的差异,比如IAR使用__indirect而SDCC可能使用其他关键字。此外,错误使用可能导致程序崩溃或效率问题,所以需要强调正确使用的重要性。 可能用户遇到的问题包括:函数指针调用出错,编译器提示需要__indirect修饰符;或者移植代码到不同架构时出现兼容性问题。需要给出示例代码,说明如何声明和使用带有__indirect的函数指针,以及常见错误的解决方法。 另外,需要注意用户的开发环境,比如是否在使用特定的嵌入式处理器,如8051、ARM Cortex-M等,不同处理器可能有不同的内存模型,影响__indirect的使用方式。因此,建议用户查阅具体编译器和处理器的手册,以获取准确的信息。 总结来说,我的回答需要涵盖__indirect的定义、使用场景、示例代码、常见问题及解决方法,并提醒用户注意编译器和处理器的差异。确保解释清晰,帮助用户理解如何正确应用该关键字解决他们遇到的问题。</think>嵌入式开发(尤其是某些特定架构或编译器中),**`__indirect`** 是一个用于修饰函数指针或间接调用(Indirect Call)的关键字或编译器扩展属性。其核心目的是处理 **函数指针调用时的特殊寻址需求**,尤其是在 **分段内存模型** 或 **特殊地址空间** 的处理器中。 --- ### **1. 基本作用** - **`__indirect`** 通常用于告诉编译器:**某个函数指针的调用需要特殊处理**,例如: - 函数指针的地址可能位于非连续或分段的存储区域(如某些8/16位处理器的分页内存)。 - 间接调用需要额外的指令或硬件支持(如扩展地址加载)。 - 避免编译器对间接调用进行优化(如函数指针的跳转地址需动态计算)。 --- ### **2. 常见应用场景** #### **(1) 分段内存架构** - 在 **8051、某些DSP或旧式微控制器** 中,内存被划分为多个段(Banks/Pages),函数指针需包含段号信息。 - 示例代码(伪代码): ```c // 使用 __indirect 修饰函数指针,确保跨段调用正确 void (__indirect *func_ptr)(void) = 0x8000; func_ptr(); // 调用时自动处理段切换 ``` #### **(2) 扩展寻址模式** - 当处理器地址总线宽度大于默认指针大小时(如16位指针访问24位地址),需通过 `__indirect` 强制生成扩展指令: ```c // 假设处理器支持24位地址,但默认指针是16位 void __indirect far_function(void) { // 编译器生成特殊指令(如LJMP/LJSR)访问扩展地址 } ``` #### **(3) 动态加载代码** - 在支持动态链接或代码重定位的系统中,`__indirect` 可标记需运行时解析的跳转地址。 -- ### **3. 具体编译器中的实现** 不同编译器对 `__indirect` 的支持可能不同: | **编译器/架构** | **行为** | |-----------------------|--------------------------------------------------------------------------| | **IAR Embedded Workbench** | 用于扩展函数指针大小(如从16位扩展到24位),常见于8051、MSP430等架构。 | | **Keil C51** | 类似 `__indirect`,需配合 `using` 关键字指定寄存器组。 | | **SDCC(小型设备C编译器)** | 使用 `__sfr __indirect` 访问特殊功能寄存器(SFR)的间接地址。 | --- ### **4. 示例代码分析** #### **(1) IAR 中的典型用法** ```c // 定义间接函数指针(假设地址为24位) typedef void (__indirect *IndirectFuncPtr)(void); // 将函数地址赋值给指针 IndirectFuncPtr func = (IndirectFuncPtr)0x123456; // 调用时,编译器自动生成扩展寻址指令(如MOVX, LJMP) func(); ``` #### **(2) 错误使用的影响** 若未正确使用 `__indirect`: - 代码跳转到错误地址(因地址截断或段未切换)。 - 程序崩溃或不可预测行为(如堆栈损坏)。 --- ### **5. 常见问题与解决** #### **(1) 编译器报错 "indirect call requires __indirect"** - **原因**:函数指针调用未声明为 `__indirect`,但目标地址超出默认寻址范围。 - **解决**:显式修饰函数指针或函数声明: ```c void (__indirect *func_ptr)(void) = &target_function; ``` #### **(2) 性能影响** - **间接调用** 通常比直接调用慢(需额外指令),需权衡灵活性与效率。 --- ### **6. 扩展知识:间接调用与虚函数** 在C++中,虚函数表(vtable)的机制本质上也是一种间接调用,但由编译器自动处理。而 `__indirect` 是更底层的显式控制机制,常见于资源受限的嵌入式环境。 --- ### **总结** `__indirect` 是嵌入式开发中处理 **分段内存**、**扩展寻址** 或 **动态跳转** 的重要工具,其核心是指导编译器生成正确的间接调用指令。使用时需注意: 1. 查阅编译器和处理器的文档。 2. 确保地址范围和内存模型匹配。 3. 避免滥用以防止性能下降。 如果需要进一步分析,请提供具体芯片型号或编译器类型!
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值