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
Of course - I didn't get it at first.
The reason that the assembler is not optimizing the ldr r4,=q into for instance MOVW + MOVT or just a single MOV, is that the address needs to be calculated by the linker. Thus the linker needs to be able to patch the address, and that is too complicated for it, if the address is split into pieces (especially if it's only an 8-bit integer).
I think that the instruction set descriptions should be changed slightly too.
The ADR "instruction" isn't really an instruction; it's a pseudo-instruction.
The LDR instruction *is* an instruction, but if specifying =value, then it's not an instruction any longer, then it's a pseudo-instruction, which may choose one or two out of several instructions. The idea is good, but perhaps it should have been renamed to something like "LDRI" or "MOVI" instead.
Technically, I think that the name "MOVW" might be confusing too; it should probably have been named "MOVH".
jensbauer wrote: Of course - I didn't get it at first. The reason that the assembler is not optimizing the ldr r4,=q into for instance MOVW + MOVT or just a single MOV, is that the address needs to be calculated by the linker. Thus the linker needs to be able to patch the address, and that is too complicated for it, if the address is split into pieces (especially if it's only an 8-bit integer). I think that the instruction set descriptions should be changed slightly too. The ADR "instruction" isn't really an instruction; it's a pseudo-instruction. The LDR instruction *is* an instruction, but if specifying =value, then it's not an instruction any longer, then it's a pseudo-instruction, which may choose one or two out of several instructions. The idea is good, but perhaps it should have been renamed to something like "LDRI" or "MOVI" instead. Technically, I think that the name "MOVW" might be confusing too; it should probably have been named "MOVH".
jensbauer wrote:
Well ADR is a pseudo-instruction, but it usually resolves to a single instruction (that is the point) of a very specific form. There are good reasons to use aliases and pseudo-instructions, but most of them have a time and a place to be useful. As long as you can guarantee you can meet the requirements, it uses less space in the code and doesn't generate literal pools so it is quite ideal - and, of course, there is no such STR= equivalent. It is essentially some form of arithmetic on the PC (r15) and anything that is doing that on the PC is decoded by disassemblers as above - you can see fromelf knows we coded in an ADR. All pseudo-instructions have a preferred disassembly, as above, but some are indistinguishable from other instructions. For example, LDR= to get an address vs. a value is not distinguishable once you get to disassembly, and therefore it is just shown a PC-relative load (i.e. it is always something close to LDR rD, [PC, #imm]) from a literal pool. Your guess is as good as anyone's what that value actually means to the code. In terms of readable output code and paucity of output, and especially to be executable without generating any kind of memory system access (as long as you are in range of arithmetic to the PC), ADR (and ADRL) is great. In terms of defining it as a pseudo-instruction, it is defined as such in the docs, however you might never notice that it isn't a real instruction -- the preferred disassembly is easy to detect, and on ARMv8 AArch64 it is an actual instruction (along with ADRP which is a 4KiB-scaled version).
This gets very, very important as the move to ARMv8 increases, since there are very few actual instructions and MOST of what you enter into an assembly file are aliases to very powerful forms of a single instruction type (the bitfield manipulation (insert, clear, etc.) and sign extension operations, for example, are all aliases to Bitfield Move (BFM). If the disassembler just showed you arbitrary combinations of BFM you wouldn't be able to read the output of your own code . Luckily the ARM architecture is not just an opcode format and some behaviours, but dictates preferred behaviours for assemblers and disassemblers as well.
LDR= is a pseudo-instruction in that it is still a LDR at the end of the day, it just allows you to use a different syntax to load values which are not immediate(ly) encodable in an easy way and implies generating a literl pool or potentially expanding to multipe instructions. This is super friendly for 16-bit Thumb code, and where you could never guarantee the positioning of a branch which is out of range (for instance to put it in a register for BX rN) or where you don't want to maintain and micromanage your own literal pool. For values you have specifically placed in a literal pool for specific reasons, ADR will give you the address so you can load or store to it (to make up for the non-existance of an equivalent store pseudo-instruction).