2008-12-07 7 views
7

Ich habe ein 32-Bit (hexadezimales) Wort 0xaabbccdd und muss das 2. und das 3. Byte tauschen. am Ende sollte es wie 0xaaccbbdd aussehenWie maskieren Bytes in ARM-Assembly?

wie kann ich "maskieren" das 2. und das 3. Byte zuerst laden sie bis registrieren R1 und R2 und die tauschen sie .. ich weiß auch, dass ich arbeiten muss lsl und lsr Befehle, aber nicht wissen, wie ich anfangen soll.

Entschuldigung für mein schlechtes Englisch.hope jemand könnte mir helfen!

Grüßen, sebastian

Antwort

6

Das in ARM Montage keine einfache Aufgabe ist, weil man nicht einfach 32-Bit-Konstanten verwenden kann. Sie müssen alle Ihre Operationen aufteilen, die Bytes ausmaskieren, um jeweils 8-Bit-Konstanten zu verwenden (auch diese Konstanten können rotiert werden).

Sie maskieren Byte2 und 3 mit der AND-Anweisung und führen die Verschiebung später aus. Im ARM-Assembler haben Sie bei den meisten Befehlen eine Verschiebung umsonst, so dass die Verschiebung in die Position und das Zusammenführen mit den anderen Bits oft zu einer einzigen Anweisung führt.

Hier einige ungetesteten Code, der das mittlere Byte swap (ARMv4, nicht Daumen-Befehlssatz) tut:

 .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 

diese Linie in den folgenden c-Code Zeile übersetzen:

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; 
} 

Sie werden sehen - viele Zeilen für so eine einfache Aufgabe. Nicht einmal die ARMv6-Architektur hilft hier sehr.


EDIT: ARMv6 Version (auch nicht getestet, aber zwei Befehle kürzer)

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 
+0

Uh machen, ist nicht, dass 32-Bit-Konstanten, im ersten Beispiel? Verwirrend. – unwind

+1

Ja, das sind 32-Bit-Konstanten, aber wenn man genauer hinschaut, werden nur 8 aufeinanderfolgende Bits in ihren Konstanten verwendet. ARM kann 8 Bits machen, aber die Position dieser kann frei in den gewünschten Ort gedreht werden. Der Assembler ist intelligent genug, um die Konstanten für Sie zu kodieren. –

+2

jeder * sogar * Ort, den Sie wollen; 0x1fe ist zum Beispiel kein direkt darstellbares, aber 0x3fc ist. –

0

Sie vould nur Zeiger verwenden zwei Bytes

static union { 
BYTE BBuf[4]; 
WORD WWBuf[2]; 
DWORD DWBuf; 
}swap; 

unsigned char *a; 
unsigned char *b; 
swap.DWBuf = 0xaabbccdd; 

a = &swap.BBuf[1]; 
b = &swap.BBuf[2]; 

*a ^= *b; 
*b ^= *a; 
*a ^= *b; 

Und nun das Ergebnis ist

zu tauschen
swap.DWbuf == 0xaaccbbdd; 
2

H mmm, weiß nicht, was passiert ist, es hat meine Antwort eingereicht, bevor ich wirklich angefangen habe.

Zuerst dachte ich nicht, ich könnte es mit nur zwei Registern tun, aber dann entschied ich, dass ich konnte und tat. Diese Lösungen sind nur Register, kein Speicher (außer dem ldr r0, = was Sie durch vier Befehle ersetzen können). Wenn Sie Speicher und hmmm, zwei Register verwenden, können Sie die Anzahl der Anweisungen vielleicht str, bic, bic, ldrb, orr lsl, ldrb, orr lsl reduzieren. Okay, ich habe es in einer Anweisung weniger gemacht, aber dann brauchen Sie den Speicherort und die Speicher und lädt die Kostenzyklen so viel Speicher und mehr Zyklen für mich, um es mit Speicher zu tun. Jemand anderes mag gute Tricks haben. Ich denke, einige der neueren Kerne haben eine Endian-Swap-Anweisung, die es noch einfacher machen würde.

.globl midswap 
midswap: 
    mov r2,r0,lsl #8  ;@ r2 = BBCCDDAA 
    mov r3,r0,lsr #8  ;@ r3 = DDAABBCC (this might drag a sign bit, dont care) 
    and r2,r2,#0x00FF0000 ;@ r2 = 00CC0000 
    and r3,r3,#0x0000FF00 ;@ r3 = 0000BB00 
    bic r0,r0,#0x00FF0000 ;@ r0 = AA00CCDD 
    bic r0,r0,#0x0000FF00 ;@ r0 = AA0000DD 
    orr r0,r0,r2   ;@ r0 = AACC00DD 
    orr r0,r0,r3   ;@ r0 = AACCBBDD 
    bx lr ;@ or mov pc,lr for older arm cores 


.globl tworegs 
tworegs: 
    mov r2,r0,ror #8  ;@ r2 = DDAABBCC 
    bic r2,r2,#0xFF000000 ;@ r2 = 00AABBCC 
    bic r2,r2,#0x00FF0000 ;@ r2 = 0000BBCC 
    orr r2,r2,ror #16  ;@ r2 = BBCCBBCC 
    bic r2,r2,#0xFF000000 ;@ r2 = 00CCBBCC 
    bic r2,r2,#0x000000FF ;@ r2 = 00CCBB00 
    bic r0,r0,#0x00FF0000 ;@ r0 = AA00CCDD 
    bic r0,r0,#0x0000FF00 ;@ r0 = AA0000DD 
    orr r0,r0,r2   ;@ r0 = AACCBBDD 
    bx lr 

testfun: 
    ldr r0,=0xAABBCCDD 
    bl midswap 
8

Früher waren wir für diese Art von Tricks sehr abhängig von EOR.

Sie können es in 4 Zyklen tun.

Zunächst einmal müssen wir die Tatsache, dass: A^(A^B) = B

Wir mit 0xAABBCCDD beginnen, und wir wollen 0xAACCBBDD. Um dorthin zu gelangen, brauchen wir 0x00EEEE00^0xAABBCCDD, wo EE = BB^CC.

Jetzt brauchen wir ein paar Zyklen 00EEEE00 zu bauen:

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; 

Nach jeder Zeile das Ergebnis berechnet ist: beginnend mit: AABBCCDD

eor XXXXEEXX 
and 0000EE00 
orr 00EEEE00 
eor AACCBBDD 

Dies funktioniert auf jedem 32-Bit-ARM-Core.

0

Können Sie BFI und UBFX werden sie Ihre Arbeit leichter