2010-12-10 04:33 PM
Very basic assembly fails on ARM Cortex-M3 (STM32F103VE)
2011-05-17 05:18 AM
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
2011-05-17 05:18 AM
Thanks a bunch! I thought GNU's M3 assembler was compatible with ARM's. I'll look into the resources you mentioned :)
2011-05-17 05:18 AM
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 thisPRESERVE8
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
2011-05-17 05:18 AM
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
2011-05-17 05:18 AM
''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!
2011-05-17 05:18 AM
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
2011-05-17 05:18 AM
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 it2011-05-17 05:18 AM
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).2011-05-17 05:18 AM
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.