2008-12-07 26 views
7

我有一個32位(十六進制)字0xaabbccdd並且必須交換2.和3.字節。最後它應該看起來像0xaaccbbdd如何屏蔽ARM程序集中的字節?

我怎麼能「掩蓋」第二個和第三個字節首先加載它們註冊r1和r2和交換它們.. 我也知道我必須與lsl和lsr命令但不知道如何啓動。

對不起,我的壞英語。任何人都可以幫助我!

問候, 塞巴斯蒂安

回答

6

這不是ARM彙編一個簡單的任務,因爲你不能輕易使用32位的常數。你必須打破所有屏蔽字節的操作,每個操作使用8位常量(這些常量也可以旋轉)。

使用AND指令屏蔽掉字節2和3,稍後再進行轉換。在ARM彙編程序中,大多數指令都是免費的,所以移入位置和與其他位合併通常最終會成爲單個指令。

下面是一些未經測試的代碼,不會中間字節交換(的ARMv4,未大拇指指令集):

 .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 

即由線轉換線劃分成以下C代碼:

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

你會看到 - 這麼簡單的任務很多。 ARMv6架構甚至都沒有幫助。


編輯:ARMv6的版本(也未經測試,但較短的兩個指令)

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

呃,是不是使用32位的常數,在第一個例子嗎?混亂。 – unwind 2008-12-08 16:52:50

0

您vould只是使用指針交換兩個字節

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; 

而現在的結果是

swap.DWbuf == 0xaaccbbdd; 
2

H嗯,不知道發生了什麼,它在我真正開始之前提交了我的答案。

起初我並不認爲我只用兩個寄存器就可以做到,但後來我決定我可以做到。這些解決方案只有寄存器,沒有內存(除了ldr r0,=可以用四條指令替換)。如果你使用內存和嗯,兩個寄存器,你可以減少指令的數量,可能是str,bic,bic,ldrb,orr lsl,ldrb,orr lsl。好吧,我只用一個指令來完成它,但是你需要內存位置和存儲器並加載成本週期,所以我需要相同數量的內存和更多的週期來處理內存。其他人可能會有一些好的技巧。我認爲一些較新的內核有一個endian swap指令,可以使它更容易。

.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

早在過去,我們曾經嚴重依賴EOR來處理這種欺騙。

你可以在4個週期內完成。

首先,我們需要一個事實,即:a ^(A^B)= B

我們先從0xAABBCCDD,我們希望0xAACCBBDD。 爲了達到那裏,我們需要0x00EEEE00^0xAABBCCDD, 其中EE = BB^CC。

現在,我們需要幾個週期來構建00EEEE00:

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

在C:

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

每行後,計算出的結果是: 開始:AABBCCDD

eor XXXXEEXX 
and 0000EE00 
orr 00EEEE00 
eor AACCBBDD 

這將適用於任何32位ARM內核。

0

你可以使用BFI和UBFX他們將讓您的工作更容易