如何在GCC中不使用具有函数调用的堆栈?

时间:2011-10-11 19:38:07

标签: gcc assembly stack arm

以下是我的问题的背景:

  • 我使用的是ARM7架构(ARM720T TDMI ...)
  • 使用codeourcedy的GCC进行编译(arm-none-eabi ver 4.5.2)
  • 我是gcc和ARM架构的新手,但已经嵌入了5年; - )

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

  

是否有可能使用某些“pragma like”命令强制gcc不使用具有该特定功能的堆栈?

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

下面是汇编代码中调用的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

提前致谢!

2 个答案:

答案 0 :(得分:2)

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

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

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}

答案 1 :(得分:1)

您有两个选择:

  1. 设置堆栈并忘记它。你必须设置堆栈 无论如何,在装配中指针,因为你不能在C中做到这一点(除非 编译器支持一些允许直接的非标准扩展 访问寄存器)。
  2. 注释掉原来的C函数 您在上面展示的反汇编,复制反汇编代码,替换 适当地使用str / ldr / b按/ pop / bx(你需要 分配全局变量来保存/恢复那些非易失性 register(fp?)),必要时修复其他内容并重新编译 在装配模块中。 编辑:再想一想,而不是 进行反汇编,使用将该函数转换为汇编 -S开关,例如gcc -c cfile.c -S -o asmfile.s。那会的 可能会省你一些工作。
  3. 我宁愿立即拥有一个有效的堆栈。