8

我有一个 32 位(十六进制)字 0xaabbccdd 并且必须交换 2. 和 3. 字节。最后它应该看起来像 0xaaccbbdd

我如何“屏蔽”第二个和第三个字节以首先将它们加载到寄存器 r1 和 r2 并交换它们。我也知道我必须使用 lsl 和 lsr 命令,但不知道如何开始。

对不起我的英语不好。希望有人能帮助我!

问候,塞巴斯蒂安

4

5 回答 5

9

过去,我们过去常常严重依赖 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 内核。

于 2009-07-08T20:24:42.937 回答
6

这不是 ARM 汇编中的一项简单任务,因为您不能轻易使用 32 位常量。您必须分解所有屏蔽字节的操作,以便每个使用 8 位常量(这些常量也可以旋转)。

您可以使用 AND 指令屏蔽 byte2 和 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
于 2008-12-07T20:12:41.503 回答
2

嗯,不知道发生了什么,它在我真正开始之前提交了我的答案。

起初我不认为我可以只用两个寄存器来做到这一点,但后来我决定我可以并且做到了。这些解决方案只有寄存器,没有内存(除了 ldr r0,= 您可以用四个指令替换)。如果你使用 memory 和 hmmm,两个寄存器你可以减少指令的数量,str、bic、bic、ldrb、orr lsl、ldrb、orr lsl。好的,我用更少的一条指令完成了它,但是你需要内存位置以及存储和加载成本周期,所以相同数量的内存和更多周期让我用内存来完成它。其他人可能有一些好的技巧。我认为一些较新的内核有一个字节序交换指令,这将使它更容易。

.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
于 2009-04-29T04:26:11.673 回答
1

你能用 BFI 和 UBFX 吗?它们会让你的工作更轻松

于 2014-04-30T06:24:12.187 回答
0

您只需使用指针来交换两个字节

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;
于 2008-12-08T16:39:28.360 回答