我有一个 32 位(十六进制)字 0xaabbccdd 并且必须交换 2. 和 3. 字节。最后它应该看起来像 0xaaccbbdd
我如何“屏蔽”第二个和第三个字节以首先将它们加载到寄存器 r1 和 r2 并交换它们。我也知道我必须使用 lsl 和 lsr 命令,但不知道如何开始。
对不起我的英语不好。希望有人能帮助我!
问候,塞巴斯蒂安
过去,我们过去常常严重依赖 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 内核。
这不是 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
嗯,不知道发生了什么,它在我真正开始之前提交了我的答案。
起初我不认为我可以只用两个寄存器来做到这一点,但后来我决定我可以并且做到了。这些解决方案只有寄存器,没有内存(除了 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
你能用 BFI 和 UBFX 吗?它们会让你的工作更轻松
您只需使用指针来交换两个字节
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;