How to mask bytes in ARM assembly?

Tags: arm assembly
By : buk
Source: Stackoverflow.com
Question!

i have got an 32bit (hexadecimal)word 0xaabbccdd and have to swap the 2. and the 3. byte. in the end it should look like 0xaaccbbdd

how can i "mask" the 2nd and the 3rd byte to first load them up to register r1 and r2 and the swap them.. i also know that i have to work with lsl and lsr commands but dont know how to start.

sorry for my bad english.hope anyone could help me out!

regards, sebastian

By : buk


Answers

That's not a simple task in ARM assembly because you can't easily use 32 bit constants. You have to break up all your operations that mask out bytes to use 8 bit constants each (also these constants can be rotated).

You mask out byte2 and 3 using the AND instruction and do the shift later. in ARM-assembler you have with most instruction one shift for free, so the shift-into-position and merge with the other bits often end up being a single instruction.

Here is some untested code that does the middle byte swap (ARMv4, not thumb-instruction set):

        .text

swap_v4:
        AND     R2, R0, #0x00ff0000     @ R2=0x00BB0000 get byte 2
        AND     R3, R0, #0x0000ff00     @ R3=0x0000CC00 get byte 1
        BIC     R0, R0, #0x00ff0000     @ R0=0xAA00CCDD clear byte 2
        BIC     R0, R0, #0x0000ff00     @ R0=0xAA0000DD clear byte 1
        ORR     R0, R2, LSR #8          @ R0=0xAA00BBDD merge and shift byte 2
        ORR     R0, R3, LSL #8          @ R0=0xAACCBBDD merge and shift byte 1
        B       LR

That translate line by line into the following c-code:

int swap (int R0)
{
  int R2,R3;
  R2 = R0 & 0x00ff0000;
  R3 = R0 & 0x0000ff00;
  R0 = R0 & 0xff00ffff;
  R0 = R0 & 0xffff00ff;
  R0 |= (R2>>8);
  R0 |= (R3<<8);
  return R0;
}

You'll see - lots of lines for such a simple task. Not even the ARMv6 architecture helps here much.


EDIT: ARMv6 version (also untested, but two instructions shorter)

swap_v6:
        @ bits in R0: aabbccdd
        ROR     R0, R0, #8              @ r0 = ddaabbcc
        REV     R1, R0                  @ r1 = ccbbaadd
        PKHTB   R0, R0, R1              @ r0 = ddaaccbb
        ROR     R0, R0, #24             @ r0 = aaccbbdd
        BX      LR


Can you use BFI and UBFX they will make your job easier

By : mSO


Back in the day we used to rely heavily on EOR for this kind of trickery.

You can do it in 4 cycles.

First off, we need the fact that: A ^ (A^B) = B

We start with 0xAABBCCDD, and we want 0xAACCBBDD. To get there, we need 0x00EEEE00^0xAABBCCDD, where EE = BB^CC.

Now, we need a few cycles to build 00EEEE00:

eor     r1,r0,r0,lsr #8
and     r1,r1,#0xFF00
orr     r1,r1,r1,lsl #8
eor     r0,r0,r1

In c:

t=x^(x>>8);
t=t&0xFF00;
t=t|(t<<8);
x^=t;

After each line, the result calculated is: starting with: AABBCCDD

eor  XXXXEEXX
and  0000EE00
orr  00EEEE00
eor  AACCBBDD

This will work on any 32bit ARM core.



This video can help you solving your question :)
By: admin