cancel
Showing results for 
Search instead for 
Did you mean: 

Very basic assembly fails on ARM Cortex-M3 (STM32F103VE)

oys_mo
Associate II
Posted on December 11, 2010 at 01:33

Very basic assembly fails on ARM Cortex-M3 (STM32F103VE)

13 REPLIES 13
Posted on May 17, 2011 at 14:18

Doesn't ARM's assembler use a different syntax than GNU's. And ARM's is pretty well documented, and several books covering it in assorted detail.

When you export names from an assembler file, they typically need to be defined public/global, rather than local to the file itself.

If you must use GNU, and want Cortex-M3, there is a WinARM/GNU build for the STM32 with assorted .S files, startup code, etc. One of the selling points of the M3 was you could write code almost entirely in C and not need much assembler, and it doesn't support any 32-bit classic ARM opcodes.

Pretty sure that the ST STM32 firmware library comes with some RIDE/ATOLLIC/GNU assembler code too. There's not much, but people aren't writing vast tracts of Thumb2 code, cause assembler and in-line assembler, isn't terribly portable.

So look at some of the startup_*.s files for the STM32, and add subroutines and code. When you get more comfortable with the syntax and definitions, move on to more code, and writing the entire thing from scratch. Look at how things are linked, and what structures and code need to be put in place before the processor even gets to main()

Some simplistic GNU assembler might look like this (personally I'd use KEIL/ARMASM)

 

  .syntax unified

 

  .cpu cortex-m3

 

  .fpu softvfp

 

  .thumb

 

 

/* some blythe or pithy comment */

 

 

 .global main

 

 

    .section  .text.main

 

    .type  main, %function

 

main:

 

    movs r0, #0

 

    bx lr

 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
oys_mo
Associate II
Posted on May 17, 2011 at 14:18

Thanks a bunch! I thought GNU's M3 assembler was compatible with ARM's. I'll look into the resources you mentioned 🙂

Posted on May 17, 2011 at 14:18

The opcodes tend to be compatible, what's biting you is most likely all the directives which tend to be assembler specific. Now if you've used GNU/AS across multiple platforms and architectures, it is likely more consistent. Most books on ARM assembler however are likely to focus on ARMASM, and it's derivatives.

So with RealView/Keil's assembler you have some thing like this

 

        PRESERVE8

 

        THUMB

 

 

        AREA    |.text|, CODE, READONLY

 

 

; Pithy Comment

 

 

main    PROC

 

        EXPORT  main

 

        MOVS    R0, #0

 

        BX      LR

 

        ENDP

 

 

        END

http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/DUI0068.pdf

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
oys_mo
Associate II
Posted on May 17, 2011 at 14:18

Okay I got the syntax down, I think, as the program assembles successfully. Trying to debug it with the simulator provided does not work as expected, though. The program seems to start executing the reset interrupt vector handler, and never reaches main at all. I thought the linker script would take care of setting up such things for me, but apparently that is not the case?

My current program:

[main.s]

.cpu cortex-m3 .fpu softvfp .syntax unified .thumb .text .global main main: mov R0, #0xF add R0, #1 loop: b loop /* return 0 */ mov.w   R0, #0 bx     LR

Andrew Neil
Chief II
Posted on May 17, 2011 at 14:18

''I thought the linker script would take care of setting up such things for me''

 

For 'C', yes - but not for assembler.

Think about it: in 'C', the linker ''knows'' that the entry point must be a function called main() - but, in assembler, you can make your entry point anything you like!

The whole point of assembler is that you have absolute & complete freedom to do whatever you like - this means, of course, that you also have to take absolute & complete responsibility for setting things up the way you want them!

If you want the tools to ''hold your hand'', then assembler is not the language for you!

Posted on May 17, 2011 at 14:18

A GNU skeleton would look something like this, it should be relatively self contained, needing the linker script to specify the stack. The M3 needs it's boot vectors, and the code in startup.s normally prepares the execution environment for C code (clear the heap/bss and move the static initalization)

        .syntax unified

 

        .cpu cortex-m3

 

    .fpu softvfp

 

    .thumb

 

 

        .global    g_pfnVectors

 

        .global    Default_Handler

 

 

        .section    .text.Reset_Handler

 

    .weak    Reset_Handler

 

    .type    Reset_Handler, %function

 

Reset_Handler:

 

 

    bl    main

 

 

        b       Infinite_Loop

 

 

        .size    Reset_Handler, .-Reset_Handler

 

 

        .section    .text.Default_Handler,''ax'',%progbits

 

Default_Handler:

 

Infinite_Loop:

 

 

    b    Infinite_Loop

 

 

    .size    Default_Handler, .-Default_Handler

 

 

main:

 

        movs    r0,#0

 

        bx      lr

 

 

/******************************************************************************

 

*

 

* The minimal vector table for a Cortex M3.  Note that the proper constructs

 

* must be placed on this to ensure that it ends up at physical address

 

* 0x0000.0000.

 

*

 

******************************************************************************/

 

 

     .section    .isr_vector,''a'',%progbits

 

    .type    g_pfnVectors, %object

 

    .size    g_pfnVectors, .-g_pfnVectors

 

 

g_pfnVectors:

 

    .word    _estack

 

    .word    Reset_Handler

 

    .word    NMI_Handler

 

    .word    HardFault_Handler

 

    .word    MemManage_Handler

 

    .word    BusFault_Handler

 

    .word    UsageFault_Handler

 

 

/*******************************************************************************

 

*

 

* Provide weak aliases for each Exception handler to the Default_Handler.

 

* As they are weak aliases, any function with the same name will override

 

* this definition.

 

*

 

*******************************************************************************/

 

 

        .weak    NMI_Handler

 

    .thumb_set NMI_Handler,Default_Handler

 

 

        .weak    HardFault_Handler

 

    .thumb_set HardFault_Handler,Default_Handler

 

 

        .weak    MemManage_Handler

 

    .thumb_set MemManage_Handler,Default_Handler

 

 

        .weak    BusFault_Handler

 

    .thumb_set BusFault_Handler,Default_Handler

 

 

    .weak    UsageFault_Handler

 

    .thumb_set UsageFault_Handler,Default_Handler

 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
oys_mo
Associate II
Posted on May 17, 2011 at 14:18

Huh, clearly 🙂 I must admit that I am looking forward to programming in C, but I have to do some work in asm first.

Does anyone know where I can find detailed information on setting up these things? The aforementioned startup_* files seem to be doing this job (possibly more) - can I just link them in, or are they meant for C?

EDIT: Did not see your post, clive1, thank you so much for your efforts! I'll look into it

oys_mo
Associate II
Posted on May 17, 2011 at 14:18

It works! Question 3 fixed 😉 Solution was to disable the ''Use default startup file'' linker option in the IDE, since your code does the startup itself. That made the ''.global main'' unnecessary too, so basically your code worked fine 🙂 Thank you!!

Still wondering about questions #1 & #2 though...?

EDIT: We have a new Question #3....:

How does multiple source files work? I tried cutting & pasting the startup code into a separate .s file, but it stopped working (code execution never reached main).. Do I have to include something, like in C?

EDIT 2: I read on an AVR forum that an AVR-asm build process (do not know if this applies to all AVR asms) does not contain any linking, so all source code had to be placed in one file - ultimately. Code could only be split up by the relatively primitive .include directives. Is this how the GNU assembler works too? If it is, that would explain my issues with using the default startup file to begin with (because it is not linked with assembly, but was designed to be linked with C).

oys_mo
Associate II
Posted on May 17, 2011 at 14:18

Just two quick questions:

#1: The .size and .type directives you use are ELF directives, right? Are they required?

#2: What is the .section directive, really? I found this line particularly confusing:

    .section .text.Default_Handler, ''ax'', %progbits

I take it that it means that upcoming code is to be grouped in the .text section, under the Default_Handler subsection, with the ax flags, meaning ''allocate only'' + ''execute''. I don't get the ''%progbits''-part, though... Would it be correct to assume that the .size directive denotes the end of the code to be included in this section?

EDIT: 3rd question - ''It doesn't work!™''

I get a multiple definition error from the g_pfnVectors symbol. Removing the .global directive fixes this, but when debugging I get the same behavior as before, never reaching main. I can't see it reaching any of the code, actually, but that might be due to my own incompetence when it comes to using this debugger... Also I had to add the line

    .global main

for it to pass the linking stage.