函数指针是实现回调函数的基础,回调函数是C程序架构的基础。所以函数指针的重要性不言而喻。然而最近在ARM开发板上测试程序时,发现函数指针虽然能编译通过,但是运行时确总是报错。如下是一个最简单的测试程序源码。
static void test()
{
puts("testn");
}
static void(*f)() = test;
void Main(void)
{
led_init();
key_init();
io_init(0);
f();
while(1){
puts("-------hello from main()----------n");
delay(100000);
}
}
使用gcc -S编译得到的汇编代码如下:
.cpu arm10tdmi
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file "main.c"
.section .rodata
.align 2
.LC0:
.ascii "test 12 00"
.text
.align 2
.syntax unified
.arm
.fpu softvfp
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
push {fp, lr}
add fp, sp, #4
ldr r0, .L2
bl puts
nop
pop {fp, pc}
.L3:
.align 2
.L2:
.word .LC0
.size test, .-test
.data
.align 2
.type f, %object
.size f, 4
f:
.word test
.section .rodata
.align 2
.LC1:
.ascii "-------hello from main()---------- 12 00"
.text
.align 2
.LC1:
.ascii "-------hello from main()---------- 12 00"
.text
.align 2
.global Main
.syntax unified
.arm
.fpu softvfp
.type Main, %function
Main:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
push {fp, lr}
add fp, sp, #4
bl led_init
bl key_init
mov r0, #0
bl io_init
ldr r3, .L6
ldr r3, [r3]
blx r3
.L5:
ldr r0, .L6+4
bl puts
ldr r0, .L6+8
bl delay
b .L5
.L7:
.align 2
.L6:
.word f
.word .LC1
.word 100000
.size Main, .-Main
.ident "GCC: (GNU) 6.2.0"
.section .note.GNU-stack,"",%progbits
可见函数指针调用时,被编译成了BLX指令。这个指令是跳转并且换运行状态(ARM和THUMB切换)。显然这样编译是错误的,还请高手帮忙分析一下,到底是哪里出了问题?
是需要特殊的编译参数吗?
头疼!!!
2016-12-20 更新:
已经找到原因,关键点如下:
GCC把绝对地址调用(包括函数指针调用)编译为BLX Rn指令。BX,BLX指令用于绝对跳转(B,BL则用于跳转),转到Rn中包含的地址。总之,其中的X有两个意思:(1)表示根据Rn的最低位是否为0,确定是否进行ARM/Thum切换。(2)可以绝对地址跳转。
S3C2440A的指令集中没有BLX,只有BX。故运行时会无效指令错误。
解决思路:
(1)给GCC适当的参数运行,来避免生成BLX指令。目前尚不清楚需要什么参数选项。
(2)利用Undefined异常处理程序来模拟BLX指令。这个看起来复杂,实现起来其实非常简单,已经在v0.9中实现。
上一篇:从NAND Flash读取数据,把代码搬运到SDRAM运行
下一篇:GNU Freestanding(Naked)C ARM交叉开发环境创建与测试
设计资源 培训 开发板 精华推荐
- ADV3227-EVALZ,ADV3227模拟交叉点开关评估板
- LTC3265HDHC 低噪声 +7V/-2V 电源的典型应用电路来自一个单端 5V 输入电源(频率 = 200kHz)
- #第二届立创大赛#基于脚本语言的可设置界面的真彩LCD液晶双路电压电流表头
- 英飞凌TC264
- 用于 2 相无桥 PFC 的 FPDB60PH60B PFC SPM 3 系列的典型应用
- 电阻网络
- CN0363
- EVAL-ADuM4120-1EBZ,用于具有 2A 输出的 ADuM4120-1 隔离式精密栅极驱动器的评估板
- DC2268A-E,用于 LTM4630IY-1 双路 18A/单路 36A 降压模块稳压器的演示板,4.5V=VIN=15V,Vout1 = 1V @ 18A,Vout2 = 1.5V @ 18A
- LT3502A 演示板、2.2MHz、500mA、2mm-2mm DFN 降压稳压器