I'm a really beginner with ARM. I write a very simple program to find the sum of three values Q,R,S and store it in the memory. However it doesn't works. Someone can show me what is my mistake. Thanks for your help.
AREA Example3, CODE, READONLY
EXPORT SystemInit
EXPORT __main
ENTRY
SystemInit
__main
LDR R1,Q ;load r1 with Q
LDR r2,R ;load r2 with R
LDR r3,S ;load r3 with S
ADD r0,r1,r2;add Q to R
ADD r0,r3;add in S
LDR r4,=Q
STR r0,[R4] ;store result in Q
;Stop B Stop
P SPACE 4 ;save one word of storage
Q DCD 2 ;create variable Q with initial value 2
R DCD 4
S DCD 5
END
Mike, you're right in that 'text' section does not guarantee that the code is in flash memory or read-only memory.
On a Cortex-A microcontroller, it's very likely that the 'read-only' memory is protected.
It's also very likely that an operating system is installed on a Cortex-A.
However, on most Cortex-M microcontrollers you upload the program to flash-memory, not to RAM.
Storing the code in flash-memory is especially a good idea if you need to power-cycle the chip at some point.
It's normally the easiest way to program the microcontroller.
-But storing the code in the internal RAM is also very beneficial, the code executes faster and it also extends your flash memory life.
Let's assume that the code was uploaded to RAM on a Cortex-M device. The STR would fail writing to RAM only if the RAM is protected.
This would happen if you're running an operating system on your device, but on most Cortex-M microcontrollers this is unlikely.
-So yes, it's correct to pick a DATA or BSS section (or a custom section for that matter), where you store the data.
Jens
Fascinating! So, is it the case that for the Cortex -M series only, the assembler regime of TEXT/DATA/BSS only applies if the code is running under an OS, or does the same apply for Cortex -A and -R? Does the T/D/B regime apply automatically to an MMU-based processor, even in bare-metal mode?
And, does anyone know of any good documentation on bare-metal ARM Assembler programming?
Mike - well, it's actually quite simple; you may need to look at it from the oposite side of the road.
Imagine that you have a piece of code. This code is of course just binary data.
Let's assume these binary data are placed somewhere in RAM on a generic CPU (we don't know which architecture).
There is no intelligent loader on this CPU. The only thing it can do is to store a block of data into RAM and change register values (for instance the Program Counter).
The program is then stored in RAM, and PC is set to the beginning. This simple CPU does not have any read-only memory, so you can actually write data directly into your code (this could be used for self-modifying code, but self-modifying code isn't really necessary any longer; except for on-the-fly generated code).
A Microcontroller / Microprocessor is not required to have any RAM (or Flash memory) or a Memory Protection Unit.
This means the data in RAM can be modified as you wish. Even though it's marked "executable" in your linker-script.
-But these attributes are for the linker only. They may make it to the binary file in the form of attributes, but attributes may be ignored by what we call a "bootloader"; a small piece of code, which resides in ROM of many microcontrollers.
On some systems, for instance a computer running Mac OS X, Windows or Linux, there might be a memory protection unit and a part of the operating system, which loads the code from - say - a harddisk, relocates it and executes it.
Similarly on a microcontroller such as Cortex-M, you can make a "loader" subroutine, which reads a file from a SD-card, store it in RAM and change the Program Counter to point to the beginning of the code (after you've applied any relocation offset to all address-pointers that need relocation).
Since your "loader" subroutine could write the binary data, your loaded code can also write to it, unless your loader subroutine instructs a Memory Protection Unit to protect the executable part of the code. Thus the .text section and .rodata sections may be writable in this case.
The "read-only" attributes does not really mean that the code/data is stored in a read-only memory.
A more correct way of looking at it, is to see it as "the code /data is allowed to be placed in read-only memory."
Thus ... the BSS section would not be allowed to be placed in read-only memory; there's no point in doing so. It *must* have a read/write location.
So even the following variable in C code will not be guaranteed to be "write-protected":
static const char __attribute__((section(".rodata"))) sHexTable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-Because what if it ends up in RAM on a device that does not have memory protection ?
However, the above C-example does help you, the programmer, to avoid writing to your lookup-table. It helps you to spot any mistakes that would result in a memory-protection error on those devices that actually place the code in read-only memory.
Again: Even if a C program "prevents" you from making these mistakes, you can send the pointer to an assembly routine, where you write to the data that the pointer points to. It may result in the data being changed, it may have no effect or it may result in an exception being triggered.
All that said: It's a good idea to split your code into .text, .data, .rodata and .bss sections as you wrote earlier.
In some cases, it may be a good idea to invent a few extra sections, for instance a ".table" section, where you would have sub-sections like ".table.pointer", ".table.word", ".table.halfword", ".table.byte", ".table.float" or ".table.wood"
-Having the table-sections will help saving padding for alignment. It may also be desirable to have some of the tables in special RAM (for instance CCMRAM on a STM32F4 device).