ARM Assembly - Endianness Transformation
This is currently a homework project that my teammate and I are stuck with. We didn't get a lot of attention in the Assembly, and this should be our first lesson in the house. The challenge is to create a program that converts 0xAABBCCDD to 0xDDCCBBAA.
I am not looking for an answer as it will defeat the objective, but we are very upset about the complexity of this silly thing. We think we have a good start to create a viable solution, but we just can't come up with the rest of the program.
First, we'll mask every one blunt (aa), (bb), (cc), (dd) to a different register:
LDR R0, LittleEndian // 0xAABBCCDD
AND R1, R0, #0xFF000000 // 0xAA
AND R2, R0, #0x00FF0000 // 0xBB
AND R3, R0, #0x0000FF00 // 0xCC
AND R4, R0, #0x000000FF // 0xDD
Then we try to reset them to register R0, but heck if we can find a good solution ...
Our best efforts have resulted in:
ORR R0, R1, LSL #24
ORR R0, R2, LSL #8
ORR R0, R3, LSR #8
ORR R0, R4, LSR #24
which produced 0xBBBBCCDD for some odd reason; we really don't know.
Any hints would be greatly appreciated. Again, we ask for help, but not for a solution.
Hooray!
a source to share
I think you need to do (ARM is a bit rusty):
MOV R0, R1, LSR #24
ORR R0, R2, LSR #8
ORR R0, R3, LSL #8
ORR R0, R4, LSL #24
That is, MOV
in the first statement, since you do not want anything from the old to R0
affect the new value.
I don't see any way to make it more of a "hint" since you've done all the work anyway.
a source to share
On ARMv6 and up, you can just use the instruction rev
, but I assume you are not allowed to do this for whatever reason.
As for why you got the result you did, I went through your code and commented out the actual values โโof the registers used:
LDR R0, LittleEndian // r0 = 0xAABBCCDD
AND R1, R0, #0xFF000000 // r1 = 0xAA000000
AND R2, R0, #0x00FF0000 // r2 = 0x00BB0000
AND R3, R0, #0x0000FF00 // r3 = 0x0000CC00
AND R4, R0, #0x000000FF // r4 = 0x000000DD
ORR R0, R1, LSL #24 // r0 = 0xAABBCCDD | 0x00000000 = 0xAABBCCDD
ORR R0, R2, LSL #8 // r0 = 0xAABBCCDD | 0xBB000000 = 0xBBBBCCDD
ORR R0, R3, LSR #8 // r0 = 0xBBBBCCDD | 0x000000CC = 0xBBBBCCDD
ORR R0, R4, LSR #24 // r0 = 0xBBBBCCDD | 0x00000000 = 0xBBBBCCDD
What's happening here is that you have a direction to shift backward; instead of left shift 0xAA000000
by 24, you want to shift it right by 24 by specifying 0x000000AA
. Plus, you've never zeroed out the content r0
, which you'll also need to do for this approach to work. If you fix these issues, your code will work as intended (although there are more compact ways to accomplish the same task).
a source to share
Your code looks good.
Your mistake is that you changed the LSL and LSR values.
Take R0 for example:
AND R1, R0, #0xFF000000 // 0xAA
The result of this operation does not generate 0xAA. It generates 0xAA000000.
Second command processing R1:
ORR R0, R1, LSL #24
Retrieves data from a register. There are only 8 bits left.
If you translate data to the right as follows:
ORR R0, R1, LSR #24
The data ends in the least significant byte. Where do you want it to be. That should give you enough help to get your homework done. :-)
a source to share
While the question is quite old, I wanted to add my suggestion for the code because it just needs 6 instructions instead of 8. It also only needs 3 registers instead of 5. This should be the best solution for anything armv6 (which has a rev instruction).
// We're starting with r0 = 4321
mov r2, r0, lsr #24 // r2 = 0004
and r1, r0, #16711680 // r1 = 0300
orr r2, r2, r0, lsl #24 // r2 = 1004
orr r2, r2, r1, lsr #8 // r2 = 1034
and r0, r0, #65280 // r0 = 0020
orr r0, r2, r0, lsl #8 // r0 = 1234
a source to share