saurav
saurav

Reputation: 31

C function from main is not pushing on stack in arm

I am executing C code for arm cortex-m3 for stm32l152C-discovery board but I observed that the function call from main is not getting pushed into the stack. I have analyzed the asm code of this source but I find it is OK. To understand better, please look the asm code generated for C code here:

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]*
}

the execution loops around 0x1a, 0x1c, 0x1e, 0x20 in PC register.

halted: PC: 0x0000001a
halted: PC: 0x0000001c
halted: PC: 0x0000001e
halted: PC: 0x00000020
halted: PC: 0x0000001a
halted: PC: 0x0000001c
halted: PC: 0x0000001e
halted: PC: 0x00000020
halted: PC: 0x0000001a
halted: PC: 0x0000001c
halted: PC: 0x0000001e
halted: PC: 0x00000020

It should jump to 0x28 (SystemClock_Config) at 0x1a.

Upvotes: 1

Views: 534

Answers (2)

old_timer
old_timer

Reputation: 71516

A very simple completely working example:

vectors.s

.thumb

.globl _start
_start:

.word 0x20001000
.word reset

.thumb_func
reset:
    bl centry
done: b done

so.c

unsigned int fun ( unsigned int );
unsigned int centry ( void )
{
    return(fun(5)+1);
}

fun.c

unsigned int fun ( unsigned int x )
{
    return(x+1);
}

flash.ld

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

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

build

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 vectors.s -o vectors.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0 -mthumb -c so.c -o so.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0 -mthumb -c fun.c -o fun.o
arm-none-eabi-ld -o so.elf -T flash.ld vectors.o so.o fun.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary

the whole program

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

a simulation of the program:

read32(0x00000000)=0x20001000
read32(0x00000004)=0x00000009
--- 0x00000008: 0xF000 
--- 0x0000000A: 0xF802 bl 0x0000000F
--- 0x00000010: 0xB510 push {r4,lr}
write32(0x20000FF8,0x00000000)
write32(0x20000FFC,0x0000000D)
--- 0x00000012: 0x2005 movs r0,#0x05
--- 0x00000014: 0xF000 
--- 0x00000016: 0xF802 bl 0x0000001B
--- 0x0000001C: 0x3001 adds r0,#0x01
--- 0x0000001E: 0x4770 bx r14
--- 0x00000018: 0x3001 adds r0,#0x01
--- 0x0000001A: 0xBD10 pop {r4,pc}
read32(0x20000FF8)=0x00000000
read32(0x20000FFC)=0x0000000D
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B
--- 0x0000000C: 0xE7FE b 0x0000000B

sure it is a somewhat useless program but it demonstrates booting and calling functions (the function address does not show up on the stack, when you do a call (bl) the r14 gets the return address and r15 gets the address to branch to. if you have nested functions like centry (the C entry point main() is not an important function name you can call your entry point whatever you want so long as your bootstrap matches) calling fun, then you need to preserve the return address however you choose, typically save it on the stack. r4 is being pushed just to keep the stack aligned on a 64 bit boundary per the abi.

for your system you would set the linker script for 0x08000000 normally (stm32).

What we are missing from you is the beginning of your binary, can you do a hexdump of the memory image/binary showing the handfuls of byte before main including the first few instructions of main?

If a bare metal program doesnt do the simplest boot steps right, the first thing you do is to examine the binary where the entry point or vector table is depending on the architecture and see that you built it right.

In this case in my example this is a cortex-m so the stack pointer initialization value (if you choose to use it) is at 0x00000000, you can put anything there and then simply write over the sp if you want, your choice...then address 0x00000004 is the reset vector which is the address of the code to handle the reset with the lsbit set to indicate thumb mode.

so 0x00000008|1 = 0x00000009.

If you dont have

0x2000xxxx 0x00000011

then your processor is not going to boot right. I am so much in the habit of using 0x08000000 that I dont remember if 0x00000000 works for an stm, it in theory should...but depends on how you are loading the flash and what mode/state the chip is in at that time.

you might need to link for 0x08000000 and at a minimum if nothing else changed

0x2000xxxx 0x08000011

as the first two word in your binary/memory image.

EDIT

note you can make a single binary that can be entered both with a vector or a bootloader

.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

placing a branch (well bl to fill the space) in the stack address spot then loading the stack pointer later.

Or use a branch

.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

Upvotes: 3

user149341
user149341

Reputation:

Your application is missing an interrupt table. As a result, the processor is reading instructions as interrupt vectors, and faulting repeatedly as those instructions cannot be interpreted as invalid addresses.

Use the support files from the STM32L1xx standard peripheral library to generate an appropriate linker script and interrupt table.

Upvotes: 1

Related Questions