紧急求助!ARM-GCC对于函数指针调用的编译有错误?【已经找到原因】

函数指针是实现回调函数的基础,回调函数是C程序架构的基础。所以函数指针的重要性不言而喻。然而最近在ARM开发板上测试程序时,发现函数指针虽然能编译通过,但是运行时确总是报错。如下是一个最简单的测试程序源码。

static void test()
{
    puts("test\n");
}

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\012\000"
    .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()----------\012\000"
    .text
    .align  2
.LC1:
    .ascii  "-------hello from main()----------\012\000"
    .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中实现。

猜你喜欢

转载自blog.csdn.net/smstong/article/details/53897131
今日推荐