ARM中的字节序转换

16

我该如何在ARM中把大端序转换成小端序?

3个回答

22

您是在谈论ARM的字节序模式,还是阅读其他大端处理器编写的内容等?

通常转换大/小端序列需要交换字节顺序。例如,0xABCD按16位数字查看时变为0xCDAB,0x12345678按32位数字查看时变为0x78563412。

ARMv5及更早版本(ARM7、ARM9等)的ARM内核具有称为BE-32的字节序模式,表示大端字不变。而ARMv6及更高版本(mpcore、cortex-somethings等)则采用BE-8或大端字节不变模式。

因此,如果您使用的是ARMv4并处于大端模式和本机(小)端模式,则相同地址处的值为0x12345678的字读取(ldr)在大端字读取时仍然为0x12345678。字不变意味着字读取给出相同的答案。在小端模式下读取相同地址的字节零会得到0x78,而在大端字节读取(ldrb)中则会得到0x12。

因此,您需要进一步了解正在使用哪个指令,而不仅仅说它是大端或小端序列。

对于ARMv6或更新的处理器,如果某个地址上的ldr指令结果为0x12345678,则在big endian模式下,相同地址的ldr指令结果为0x78563412。请注意,在大端或小端模式下,对于该地址的指令获取在ARMv6或更新的处理器中会获取0x12345678。在ARMv6的little endian模式下,相同数据和地址的ldrb指令结果为0x78,而在ARMv6或更新的big endian模式下也是0x78。这是因为ARMv6及更新版本是字节不变的,即相同地址的字节访问结果相同,但是半字、字和双字访问在big endian模式下被交换。由于指令获取未被交换,并且endian位于PSR中,当运行小端编译程序时,可以切换到big endian模式,执行多个指令,然后返回native模式,这不会影响指令获取或发生的中断。

setend be
ldr r0,[r1]
add r0,r0,#7
str r0,[r1]
setend le

一些网页会提到这个四条指令的字节交换,在需要运行native little endian(一个很好的选择)并使用汇编程序执行交换时可以使用这些指令(并非总是一个好主意,取决于您要做什么)。

  eor r3,r1,r1, ror #16
  bic r3,r3,#0x00FF0000
  mov r0,r1,ror #8
  eor r0,r0,r3, lsr #8

其中r1是输入,r0是输出。

对于ARMv6或更高版本的处理器,可以使用以下指令执行上述操作:

  rev r0,r1

8

请查看是否有字节反转命令,例如(__REV(),__REV16(),__REVSH())。这些是内联汇编指令,利用硬件而不像上面那些更慢但可移植的解决方案。(链接1链接2)


3

想象一下如何在高级语言(例如C语言)中转换字节序,然后当你理解了它之后,你可以轻松地将其翻译成ARM汇编,例如:

uint16_t x = 0x0102;
uint16_t y = (x << 8) | (x >> 8); // y = 0x0201

对于16位情况,您需要进行两次移位(一次左移和一次右移)和一次按位或操作。您应该能够在3个指令中完成此操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接