GCC优化损坏ARM/Thumb系统调用存根,如何添加注解修复?
问题:GCC 12+过程间分析导致ARM/Thumb系统调用存根失效
包括GCC 12在内的新版本实现了过程间分析,会严重破坏ARM/Thumb平台下以下仅适用于GCC的系统调用存根代码:
typedef struct { int sender; int arg; } message; #define syscall(op) asm volatile ("svc %0" :: "i"(op)) #define SYS_SEND 9 #define NOINLINE __attribute((noinline)) void NOINLINE send(int dest, int type, message *msg) { syscall(SYS_SEND); } void send_int(int d, int t, int v) { message msg; msg.arg = v; send(d, t, &msg); }
该代码的设计意图是让操作系统陷阱处理程序通过访问陷阱异常帧中保存的参数寄存器r0-r2的值,获取send函数的三个参数。但问题在于,编译器优化器认为send函数的message参数字段未被使用,因此会删除send_int函数中对msg.arg的赋值操作。
可通过以下命令编译代码并反汇编目标文件复现该问题:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -O -g -Wall -ffreestanding -c trial.c
以下是几种可能的注解方案分析:
- 为
send函数添加额外的noipa属性可解决问题,但该属性非标准,GCC文档称其主要用于编译器调试。需保留原有的noinline属性以兼容不支持noipa的旧版GCC,GCC会忽略未实现的属性吗? - 将
send_int函数中的msg缓冲区标记为volatile(并在调用send时添加强制类型转换以抑制警告)也能解决问题,但这种方式过于晦涩。 - 在
svc指令的asm volatile中添加"memory"作为clobber项无法解决问题。
此外,将send这类系统调用存根单独编写为汇编语言例程也能修复问题,这可能是最稳健的解决方案。
内容的提问来源于stack exchange,提问作者Mike Spivey
相关产品推荐
相关产品推荐

