Category:ARM Assembly: Difference between revisions

Content added Content deleted
Line 162: Line 162:
===Limitations of the ARM===
===Limitations of the ARM===
While the ARM has a rich amount of features that other processors only dream of having, there are a few limitations.
While the ARM has a rich amount of features that other processors only dream of having, there are a few limitations.
The biggest one (which was more of an issue on earlier versions such as the ARM7TDMI CPU in the Game Boy Advance) is the limitation of the <code>MOV</code> command. Arguably the most important command any processor has (apart from <code>JMP</code>), the <code>MOV</code> command on the ARM is often limited in what can be loaded into a register in a single command. Depending on the pattern of bits, some immediate values cannot be loaded into a register directly. The key features of the ARM instructions (barrel shifter, conditional commands, etc) all take up bytes in each command, whether they are used in a given instance of a command or not. So in order to store 32 bit numbers in a <code>MOV</code> command, the value has to be "8-bit rotatable," meaning that it can be expressed as an 8 bit number if you shift it enough times. Basically if there are too many 1s in the binary equivalent of the number you're trying to load, it can't be done in one go.
The biggest one is the limitation of the <code>MOV</code> command. Arguably the most important command any processor has (apart from <code>JMP</code>), the <code>MOV</code> command on the ARM is often limited in what can be loaded into a register in a single command. Depending on the pattern of bits, some immediate values cannot be loaded into a register directly. The key features of the ARM instructions (barrel shifter, conditional commands, etc) all take up bytes in each command, whether they are used in a given instance of a command or not. So in order to store 32 bit numbers in a <code>MOV</code> command, the value has to be "8-bit rotatable," meaning that it can be expressed as an 8 bit number if you shift it enough times. Basically if there are too many 1s in the binary equivalent of the number you're trying to load, it can't be done in one go.


Looking at the following in C and its ARM assembly equivalent (I've cut the stack twiddling and the return statement for clarity) we can see just what exactly happens:
Most of the time, this isn't a huge deal, as the easiest way around this is to define a data block nearby containing the value you wish to load. Since each command on the ARM takes 4 bytes of storage, this is guaranteed to take equal or fewer bytes than loading the number into a register piece-by-piece.


<lang ARM Assembly>mov r0,#0x04000000
<lang C>int main(){
return 0xFFFF;
add r0,r0,#0x130
}</lang>

<lang ARM Assembly>
mov r0, #255 ;MOV R0,#0xFF
orr r0, r0, #65280 ;ORR R0,#0xFF00 (0xFF00|0x00FF = 0xFFFF)</lang>


It's very common to store "complicated" numbers into a nearby data block and just load from that data block with PC-relative addressing. These data blocks are usually placed after the nearest return statement so that they don't get executed as instructions.
<lang ARM Assembly>ldr r0,testData ;load 0xABCD1234 into R0
bx lr ;return
testData:
.long 0xABCD1234</lang>


;compare to:
TestDataAddr: .word 0x04000130
ldr r0,TestDataAddr</lang>


Thankfully, there's an even easier solution than this. The GNU Assembler saves the day with the following special notation.
Thankfully, there's an even easier solution than this. The GNU Assembler saves the day with the following special notation.