1

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 (e.g. 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>
artless noise
  • 21,212
  • 6
  • 68
  • 105
Pere Tuset
  • 11
  • 1
  • 4
  • In what sense does it "stop working"? – ooga Jun 22 '14 at 14:17
  • It hangs, execution does not reach the main function. To me it could be either something related to ARM vs. Thumb mode or that the loop is wrong (e.g. it does not end). – Pere Tuset Jun 22 '14 at 14:22
  • generally you dont want to do C until you have finished the C bootstrap, chicken and egg, problems like this are expected. setup the stack, clear .bss and copy .data in asm (ideally not-inline) at a minimum before the first C is touched... – old_timer Jun 23 '14 at 00:32
  • The startup code from codered/lpcXpresso/precision32 uses c/c++, and looks very similar to what you're doing. There's no reason this can't or shouldn't be in c. – escrafford Jun 29 '14 at 08:56

1 Answers1

2

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.

Notlikethat
  • 20,095
  • 3
  • 40
  • 77
  • why would stack be in bss? – escrafford Jun 29 '14 at 08:57
  • @escrafford I don't see any good reason, but someone suggested it was in a now-deleted answer, and in my brief search I found an example of a linker script that did so, so I guess there's at least one toolchain out there that does it. There are of course other possibilities, like a leftover bootloader `sp` that just happens to coincide with the application `.bss`, or something else (on a second look those addresses in the C disassembly do look a bit dodgy) – Notlikethat Jul 01 '14 at 11:15