来自main的C函数未推动arm中的堆栈

来自main的C函数未推动arm中的堆栈,c,gcc,assembly,arm,cortex-m3,C,Gcc,Assembly,Arm,Cortex M3,我正在为stm32l152C发现板的arm cortex-m3执行C代码,但我观察到来自main的函数调用没有被推入堆栈。我已经分析了这个源代码的asm代码,但我发现它是好的。为了更好地理解,请在此处查看为C代码生成的asm代码: main.elf: file format elf32-littlearm *SYMBOL TABLE: 00000010 l d .text 00000000 .text 00000000 l d .debug_info 00000

我正在为stm32l152C发现板的arm cortex-m3执行C代码,但我观察到来自main的函数调用没有被推入堆栈。我已经分析了这个源代码的asm代码,但我发现它是好的。为了更好地理解,请在此处查看为C代码生成的asm代码:

main.elf:     file format elf32-littlearm

*SYMBOL TABLE:
00000010 l    d  .text  00000000 .text
00000000 l    d  .debug_info    00000000 .debug_info
00000000 l    d  .debug_abbrev  00000000 .debug_abbrev
00000000 l    d  .debug_aranges 00000000 .debug_aranges
00000000 l    d  .debug_line    00000000 .debug_line
00000000 l    d  .debug_str 00000000 .debug_str
00000000 l    d  .comment   00000000 .comment
00000000 l    d  .ARM.attributes    00000000 .ARM.attributes
00000000 l    d  .debug_frame   00000000 .debug_frame
00000000 l    df *ABS*  00000000 main.c
00000000 l    df *ABS*  00000000 clock.c
20004ffc g       .text  00000000 _STACKTOP
**00000028 g     F .text    000000e0 SystemClock_Config**
20000000 g       .text  00000000 _DATA_BEGIN
20000000 g       .text  00000000 _HEAP
**00000010 g     F .text    00000016 main**
20000000 g       .text  00000000 _BSS_END
00000108 g       .text  00000000 _DATAI_BEGIN
20000000 g       .text  00000000 _BSS_BEGIN
00000108 g       .text  00000000 _DATAI_END
20000000 g       .text  00000000 _DATA_END
Disassembly of section .text:
00000010 <main>:

#define LL_GPIO_MODE_OUTPUT    1

void SystemInit() ;
int main()
{
  10:   b580        push    {r7, lr}
  12:   b082        sub sp, #8
  14:   af00        add r7, sp, #0
    int i = 0;
  16:   2300        movs    r3, #0
  18:   607b        str r3, [r7, #4]
  SystemClock_Config(); 
  **1a: f000 f805   bl  28 <SystemClock_Config>
    for(;;)
        i++;
  1e:   687b        ldr r3, [r7, #4]
  20:   3301        adds    r3, #1**
  22:   607b        str r3, [r7, #4]
  24:   e7fb        b.n 1e <main+0xe>

}
00000028 <SystemClock_Config>:
  *            PLLDIV                         = 3
  *            Flash Latency(WS)              = 1
  * @retval None
  */
void SystemClock_Config(void)
{
  28:   b480        push    {r7}
  2a:   af00        add r7, sp, #0
  SET_BIT(FLASH->ACR, FLASH_ACR_ACC64);
  2c:   4a33        ldr r2, [pc, #204]  ; (fc <SystemClock_Config+0xd4>)
  2e:   4b33        ldr r3, [pc, #204]  ; (fc <SystemClock_Config+0xd4>)
  30:   681b        ldr r3, [r3, #0]
  32:   f043 0304   orr.w   r3, r3, #4
  36:   6013        str r3, [r2, #0]
  MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, LL_FLASH_LATENCY_1);
  38:   4a30        ldr r2, [pc, #192]  ; (fc <SystemClock_Config+0xd4>)
  3a:   4b30        ldr r3, [pc, #192]  ; (fc <SystemClock_Config+0xd4>)
  3c:   681b        ldr r3, [r3, #0]
  3e:   f043 0301   orr.w   r3, r3, #1
  42:   6013        str r3, [r2, #0]*
}

它应该跳转到0x1a处的0x28(系统时钟配置)

应用程序缺少中断表。结果,处理器将指令作为中断向量读取,并且由于这些指令不能被解释为无效地址而反复出错


使用中的支持文件生成适当的链接器脚本和中断表。

您的应用程序缺少中断表。结果,处理器将指令作为中断向量读取,并且由于这些指令不能被解释为无效地址而反复出错


使用中的支持文件生成适当的链接器脚本和中断表。

一个非常简单且完全有效的示例:

向量

.thumb

.globl _start
_start:

.word 0x20001000
.word reset

.thumb_func
reset:
    bl centry
done: b done
所以,c

乐趣

flash.ld

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
}
建造

整个计划

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000009    andeq   r0, r0, r9

00000008 <reset>:
   8:   f000 f802   bl  10 <centry>

0000000c <done>:
   c:   e7fe        b.n c <done>
    ...

00000010 <centry>:
  10:   b510        push    {r4, lr}
  12:   2005        movs    r0, #5
  14:   f000 f802   bl  1c <fun>
  18:   3001        adds    r0, #1
  1a:   bd10        pop {r4, pc}

0000001c <fun>:
  1c:   3001        adds    r0, #1
  1e:   4770        bx  lr
当然,这是一个有点无用的程序,但它演示了引导和调用函数(函数地址不显示在堆栈上,当您执行调用(bl)时,r14获取返回地址,r15获取要分支到的地址。如果您有像centry(C入口点main())这样的嵌套函数不是一个重要的函数名。只要引导匹配,您可以随意调用您的入口点)调用fun,然后您需要保留返回地址,不管您选择什么,通常将其保存在堆栈上。r4被推送只是为了使堆栈按照abi在64位边界上对齐

对于您的系统,通常将链接器脚本设置为0x08000000(stm32)

我们缺少的是二进制文件的开头,能否对内存图像/二进制文件进行十六进制转储,显示main之前的字节数,包括main的前几条指令

如果裸机程序没有正确地执行最简单的引导步骤,那么您要做的第一件事就是检查二进制文件,其中入口点或向量表取决于体系结构,并查看您是否正确地构建了它

在本例中,在我的示例中,这是一个cortex-m,因此堆栈指针初始化值(如果您选择使用它)是0x00000000,您可以将任何内容放在那里,然后只要在sp上写入即可,如果您愿意,您可以选择…然后地址0x00000004是重置向量,它是处理重置的代码地址,lsbit设置为指示thumb模式

所以0x00000008 | 1=0x00000009

如果你没有

0x2000xxxx 0x00000011

那么你的处理器将无法正常启动。我习惯于使用0x08000000,以至于我不记得0x00000000是否适用于stm,理论上应该是……但这取决于你如何加载闪存以及芯片当时处于何种模式/状态

您可能需要链接0x08000000,如果没有其他更改,则至少需要链接0x08000000

0x2000xxxx 0x0800011

作为二进制/内存映像中的前两个单词

编辑

注意,您可以创建一个二进制文件,该文件可以通过向量或引导加载程序输入

.thumb

.thumb_func
.global _start
_start:
bl reset
.word _start
reset:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang
.thumb_func
hang:   b .
.align 
stacktop: .word 0x20001000
在堆栈地址点中放置分支(填充空间的井bl),然后稍后加载堆栈指针

或者用树枝

.thumb

.thumb_func
.global _start
_start:
b reset
nop
.word _start
reset:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang
.thumb_func
hang:   b .
.align
stacktop: .word 0x20001000

一个非常简单且完全有效的示例:

向量

.thumb

.globl _start
_start:

.word 0x20001000
.word reset

.thumb_func
reset:
    bl centry
done: b done
所以,c

乐趣

flash.ld

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
}
建造

整个计划

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000009    andeq   r0, r0, r9

00000008 <reset>:
   8:   f000 f802   bl  10 <centry>

0000000c <done>:
   c:   e7fe        b.n c <done>
    ...

00000010 <centry>:
  10:   b510        push    {r4, lr}
  12:   2005        movs    r0, #5
  14:   f000 f802   bl  1c <fun>
  18:   3001        adds    r0, #1
  1a:   bd10        pop {r4, pc}

0000001c <fun>:
  1c:   3001        adds    r0, #1
  1e:   4770        bx  lr
当然,这是一个有点无用的程序,但它演示了引导和调用函数(函数地址不显示在堆栈上,当您执行调用(bl)时,r14获取返回地址,r15获取要分支到的地址。如果您有像centry(C入口点main())这样的嵌套函数不是一个重要的函数名。只要引导匹配,您可以随意调用您的入口点)调用fun,然后您需要保留返回地址,不管您选择什么,通常将其保存在堆栈上。r4被推送只是为了使堆栈按照abi在64位边界上对齐

对于您的系统,通常将链接器脚本设置为0x08000000(stm32)

我们缺少的是二进制文件的开头,能否对内存图像/二进制文件进行十六进制转储,显示main之前的字节数,包括main的前几条指令

如果裸机程序没有正确地执行最简单的引导步骤,那么您要做的第一件事就是检查二进制文件,其中入口点或向量表取决于体系结构,并查看您是否正确地构建了它

在本例中,在我的示例中,这是一个cortex-m,因此堆栈指针初始化值(如果您选择使用它)是0x00000000,您可以将任何内容放在那里,然后只要在sp上写入即可,如果您愿意,您可以选择…然后地址0x00000004是重置向量,它是处理重置的代码地址,lsbit设置为指示thumb模式

所以0x00000008 | 1=0x00000009

如果你没有

0x2000xxxx 0x00000011

那么你的处理器将无法正常启动。我习惯于使用0x08000000,以至于我不记得0x00000000是否适用于stm,理论上应该是……但这取决于你如何加载闪存以及芯片当时处于何种模式/状态

您可能需要链接0x08000000,如果没有其他更改,则至少需要链接0x08000000

0x2000xxxx 0x0800011

作为二进制/内存映像中的前两个单词

编辑

注意,您可以创建一个二进制文件,该文件可以通过向量或引导加载程序输入

.thumb

.thumb_func
.global _start
_start:
bl reset
.word _start
reset:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang
.thumb_func
hang:   b .
.align 
stacktop: .word 0x20001000
在堆栈地址点中放置分支(填充空间的井bl),然后稍后加载堆栈指针

或者用树枝

.thumb

.thumb_func
.global _start
_start:
b reset
nop
.word _start
reset:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang
.thumb_func
hang:   b .
.align
stacktop: .word 0x20001000

问题是什么?什么不是堆栈上的推力?参数-它们是pa