2011-10-11 51 views
1

下面是我的问题的背景:使用GCC codesourcedy的 如何在GCC中不使用堆栈和函数调用?

  • 编译

    • 我使用的是ARM7架构(ARM720T TDMI ...)(ARM-NONE-EABI版本4.5.2)
    • 我是一个新手,具有gcc和ARM架构,但已经嵌入了5年;-)

    在我的项目中,在初始化堆栈之前从一个程序集文件调用一个C函数。由于堆栈未初始化,因此该函数不得使用堆栈。

    是否有可能使用一些“编译指令”命令强制gcc不使用该特定功能的堆栈?

    附加信息:我的工作的目标是将之前用ARMASM编译的项目转换为gcc。所以在ARMASM中,在堆栈初始化工作之前调用这个C函数。也许最终的答案是,这是不可能做到这一点在海湾合作委员会...

    下面是在汇编代码中调用的C函数的ELF列表的摘录(正如你可以看到我试过always_inline,但从组装调用时,这似乎不够):

    000049d0 <CInit_Init>: 
    __attribute__((always_inline)) extern void CInit_Init(void) { 
    49d0: e52db004 push {fp}  ; (str fp, [sp, #-4]!) 
    49d4: e28db000 add fp, sp, #0 
    
    __attribute__((always_inline)) void COM1_Init(void); 
    
    __attribute__((always_inline)) extern inline void COM1_Init_I(void) { 
    // Skip if already enabled 
    if (TEST_BIT_CLR(HwrSysControl1, HwSysControl1UartEnable)) { 
    49d8: e59f3038 ldr r3, [pc, #56] ; 4a18 <CInit_Init+0x48> 
    49dc: e5933000 ldr r3, [r3] 
    49e0: e2033c01 and r3, r3, #256 ; 0x100 
    49e4: e3530000 cmp r3, #0 
    49e8: 1a000007 bne 4a0c <CInit_Init+0x3c> 
        HwrUart1Control = (
    49ec: e59f3028 ldr r3, [pc, #40] ; 4a1c <CInit_Init+0x4c> 
    49f0: e59f2028 ldr r2, [pc, #40] ; 4a20 <CInit_Init+0x50> 
    49f4: e5832000 str r2, [r3] 
          HwUartControlDataLength8| 
          HwUartControlFifoEnable| 
          HwUartControlRate115200); 
        BIT_SET(HwrSysControl1, HwSysControl1UartEnable); 
    49f8: e59f3018 ldr r3, [pc, #24] ; 4a18 <CInit_Init+0x48> 
    49fc: e59f2014 ldr r2, [pc, #20] ; 4a18 <CInit_Init+0x48> 
    4a00: e5922000 ldr r2, [r2] 
    4a04: e3822c01 orr r2, r2, #256 ; 0x100 
    4a08: e5832000 str r2, [r3] 
    
    COM1_Init_I(); 
    } 
    4a0c: e28bd000 add sp, fp, #0 
    4a10: e49db004 pop {fp}  ; (ldr fp, [sp], #4) 
    4a14: e12fff1e bx lr 
    4a18: 80000100 .word 0x80000100 
    4a1c: 800004c0 .word 0x800004c0 
    4a20: 00070001 .word 0x00070001 
    

    在此先感谢!

  • 回答

    1

    只需设置堆栈。否则,如果你不想要一个堆栈没有局部变量,并有足够的代码,你不会用完寄存器,不要从这个函数中调用任何函数,等等。如果你真的需要变量,那么使用全局变量。如果导致代码用尽寄存器和全局变量,编译器无法在不使用堆栈的情况下生成代码。没有编译器开关会发明存储器,我不相信编译器有一些非堆栈的非标准技巧,它可能会尝试使用..

    简单,没有局部变量,甚而不需要中间寄存器:

    unsigned int fun (unsigned int a, unsigned int b) 
    { 
        return(a+b); 
    } 
    

    没有堆栈:

    00000000 <fun>: 
        0: e0810000 add r0, r1, r0 
        4: e12fff1e bx lr 
    

    你可以随时更改堆栈你打电话给你最初的C代码之后,它需要一个到几个指令来设置您的C调用之前的堆栈,只需设置堆栈指针。你不需要所有的堆栈指针,只需要一个。要么设置堆栈指针,要么在汇编程序中写入函数而不是C.您应该在com端口之前初始化堆栈。这是一个指令,两个字的位置,你打电话给C,所以成本可以忽略不计。

    .globl _start 
    _start: 
        b reset 
    reset: 
         ldr sp,=0x20008000 
         bl more_fun 
         b . 
    
    .globl fun 
    fun: 
        bx lr 
    
    .globl fun_out 
    fun_out: 
        bx lr 
    
    
    
    unsigned int fun (unsigned int , unsigned int); 
    void fun_out (unsigned int, unsigned int, unsigned int, unsigned int); 
    unsigned int more_fun (unsigned int a, unsigned int b, unsigned int c) 
    { 
        unsigned int d; 
        d = fun(a,b); 
        fun_out(a,b+c,b,a+c); 
    } 
    

    的指令,两个词,你可以调用C

    4: e59fd00c ldr sp, [pc, #12] ; 18 <fun_out+0x4> 
        8: eb000003 bl 1c <more_fun> 
    
    ... 
    
        18: 20008000 andcs r8, r0, r0 
    
    0000001c <more_fun>: 
        1c: e92d4070 push {r4, r5, r6, lr} 
        20: e1a05002 mov r5, r2 
        24: e1a06000 mov r6, r0 
        28: e1a04001 mov r4, r1 
        2c: ebfffff7 bl 10 <fun> 
        30: e1a00006 mov r0, r6 
        34: e0853006 add r3, r5, r6 
        38: e0851004 add r1, r5, r4 
        3c: e1a02004 mov r2, r4 
        40: ebfffff3 bl 14 <fun_out> 
        44: e8bd8070 pop {r4, r5, r6, pc} 
    
    +0

    谢谢!我会研究你的解决方案,并在几天后回到你身边。我特别喜欢设置临时堆栈指针的想法... –

    +0

    最后我在调用C函数之前设置sp。但我仍然不明白为什么/如何使用另一个编译器的相同汇编代码能够在不使用堆栈指针的情况下调用C函数... –

    +0

    看一下反汇编,或者没有使用堆栈,或者在堆栈的系统上是为你设置的,等等,它可能内联第二级调用等。 –

    1

    您有关于两种选择:

    1. 设置堆栈,并忘掉它。不管怎么样,你不得不在C中设置堆栈指针,因为在C中你不能这样做(除非 编译器支持一些允许直接 访问寄存器的非标准扩展)。
    2. 注释掉原来的C函数,其 拆卸你在上面呈现,复制的反汇编代码,更换 推/流行/ BX与STR/LDR/B为适当,(你需要 分配一个全局变量来保存/恢复这些非易失性寄存器(fp?)),如有必要修复其他内容,并在汇编模块中重新编译 。 编辑:第二个想法是,代替 进行拆卸,将该函数转换为程序集,使用 -S开关,例如, gcc -c cfile.c -S -o asmfile.s。那 可能会为你节省一些工作。

    我宁愿立即有一个有效的堆栈。

    +0

    我明白我应该之前设置堆栈。但我想保留原始文件。 我会尝试-S好奇心切换! –