简体   繁体   中英

ARM Cortex-M3 startup file

I am modifying a startup file for an ARM Cortex-M3 microcontroller. Everything works fine so far, but I have a question regarding the need of using assembler code to perform the zero-filling of the BSS block.

By default the reset interrupt in the startup file looks as follows:

// Zero fill the bss segment.
__asm(  "    ldr     r0, =_bss\n"
        "    ldr     r1, =_ebss\n"
        "    mov     r2, #0\n"
        "    .thumb_func\n"
        "    zero_loop:\n"
        "    cmp     r0, r1\n"
        "    it      lt\n"
        "    strlt   r2, [r0], #4\n"
        "    blt     zero_loop"
);

Using that code everything works as expected. However if I change the previous code for the following it stops working:

// Zero fill the bss segment.
for(pui32Dest = &_bss; pui32Dest < &_ebss; )
{
    *pui32Dest++ = 0;
}

In principle both codes should do the same (fill the BSS with zeros), but the second one does not work for some reason that I fail to understand. I belive that the .thumb_func directive must play a role here, but I am not very familiar with ARM assembler. Any ideas or directions to help me understanding? Thanks!

Edit : By the way, the code to initialize the data segment (eg copy from Flash to RAM) is as follows and works just fine.

// Copy the data segment initializers from flash to SRAM.
pui32Src = &_etext;
for(pui32Dest = &_data; pui32Dest < &_edata; )
{
    *pui32Dest++ = *pui32Src++;
}

Edit : Added the dissasembled code for both functions.

Assembly for the first looks like:

  2003bc:   4806        ldr r0, [pc, #24]   ; (2003d8 <zero_loop+0x14>)
  2003be:   4907        ldr r1, [pc, #28]   ; (2003dc <zero_loop+0x18>)
  2003c0:   f04f 0200   mov.w   r2, #0

002003c4 <zero_loop>:
  2003c4:   4288        cmp r0, r1
  2003c6:   bfb8        it  lt
  2003c8:   f840 2b04   strlt.w r2, [r0], #4
  2003cc:   dbfa        blt.n   2003c4 <zero_loop>

Assembly for the second looks like:

  2003bc:   f645 5318   movw    r3, #23832  ; 0x5d18
  2003c0:   f2c2 0300   movt    r3, #8192   ; 0x2000
  2003c4:   9300        str r3, [sp, #0]
  2003c6:   e004        b.n 2003d2 <ResetISR+0x6e>
  2003c8:   9b00        ldr r3, [sp, #0]
  2003ca:   1d1a        adds    r2, r3, #4
  2003cc:   9200        str r2, [sp, #0]
  2003ce:   2200        movs    r2, #0
  2003d0:   601a        str r2, [r3, #0]
  2003d2:   9a00        ldr r2, [sp, #0]
  2003d4:   f644 033c   movw    r3, #18492  ; 0x483c
  2003d8:   f2c2 0300   movt    r3, #8192   ; 0x2000
  2003dc:   429a        cmp r2, r3
  2003de:   d3f3        bcc.n   2003c8 <ResetISR+0x64>

If the initial stack is in the .bss section as suggested, you can see from the disassembly why the C code fails - it's loading the current pointer from the stack, saving the incremented pointer back to the stack, zeroing the location, then reloading the incremented pointer for the next iteration. If you zero the contents of the stack while using them, Bad Things happen.

In this case, turning on optimisation might fix it (a smart compiler should generate pretty much the same as the assembly code if it actually tries). More generally, though, it's probably safer to consider sticking with assembly code when doing things like this that would normally be done at a level below the C runtime environment - bootstrapping a C environment from C code which expects that environment to exist already is risky at best, since you can only hope the code doesn't attempt to use anything that's not yet set up.

After a quick look around (I'm not overly familiar with the specifics of Cortex-M development), it seems an alternative/additional solution might be adjusting the linker script to move the stack somewhere else.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM