ARM 中的字节顺序转换

发布于 2024-10-04 18:21:54 字数 25 浏览 1 评论 0原文

如何在 ARM 中将大端转换为小端?

How do I convert big endian to little endian in ARM?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无敌元气妹 2024-10-11 18:21:54

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

通常,在大端/小端之间转换时需要交换字节。因此,当作为 16 位数字查看时,0xABCD 是 0xCDAB;当作为 32 位数字查看时,0x12345678 是 0x78563412。

ARM 内核 armv5 及更早版本(ARM7、ARM9 等)具有称为 BE-32 的字节序模式,意思是大字节序字不变。 armv6 和更新版本(mpcore、cortex-somethings)具有 BE-8,或大端字节不变式。

因此,如果您在大端模式和本机(小)端模式下使用 armv4,则对于在同一地址读取的大端字,值 0x12345678 的字读取 (ldr) 将是 0x12345678。单词不变意味着单词读取给出相同的答案。在同一地址的小端模式下,地址零的字节读取将为 0x78,大端字节读取 (ldrb) 将为 0x12。

因此,您不仅要说它是大端还是小端,还要知道正在使用什么指令。

对于armv6或更新版本,如果某个地址的ldr结果为0x12345678,那么在大端模式下,来自同一地址的ldr将结果为0x78563412。请注意,在大端或小端模式下,在 armv6 或更高版本上对该地址进行指令提取将获取 0x12345678。 ldrb 小端模式armv6 相同数据相同地址会产生0x78,ldrb 大端模式armv6 或更新版本也会产生0x78。这是因为 armv6 和更新版本是字节不变的,这意味着对相同地址的字节访问会导致相同的值,在大端模式下,半字、字和双字访问在这些架构上会交换。因为指令获取不会交换,并且因为在运行小端编译程序时,字节序位位于 psr 中,所以您可以切换到大端,执行一些指令,然后返回到本机模式,它不会影响指令获取,也不会中断发生。

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

一些网页会提到这个四指令字节交换,以防您想运行本机小端(一个非常好的主意)并使用汇编程序执行交换(并不总是一个好主意,取决于您在做什么)。

  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

Are you talking about ARM's endian modes, or reading something written by some other big endian processor, etc?

Normally converting to/from big/little endian you swap the bytes around. So 0xABCD is 0xCDAB when viewed as a 16 bit number 0x12345678 is 0x78563412 when viewed as a 32 bit number.

ARM cores armv5 and older (ARM7, ARM9, etc) have an endian mode known as BE-32, meaning big endian word invariant. armv6 and newer (mpcore, cortex-somethings) have BE-8, or big endian byte invariant.

So if you are using an armv4 for example in big endian mode and native (little) endian mode a word read (ldr) of the value 0x12345678 would be 0x12345678 for a big endian word read at the same address. Word invariant meaning word reads give the same answer. A byte read of address zero in little endian mode of the same address would be 0x78 and big endian byte read (ldrb) would be 0x12.

So you have to go beyond just saying is it big or little endian but what instruction is being used.

For an armv6 or newer, if an ldr at some address results in 0x12345678 then in big endian mode the ldr from the same address would result in 0x78563412. Note that big or little endian mode an instruction fetch for that address on an armv6 or newer would fetch 0x12345678. An ldrb little endian mode armv6 same data same address results in 0x78, ldrb big endian armv6 or newer also results in 0x78. this is because the armv6 and newer are byte invariant meaning byte accesses to the same address result in the same value, halfword, word and double word accesses are swapped on these architectures when in big endian mode. Because instruction fetches are not swapped, and because the endian bit is in the psr while running a little endian compiled program you can switch to big endian, do a number of instructions then return to native mode and it wont affect the instruction fetches nor interrupts that occur.

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

Some web pages will mention this four instruction byte swap, in case you want to run native little endian (a very good idea) and perform the swap using assembler (not always a good idea, depends on what you are doing).

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

with r1 being the input it appears and r0 being the output

For armv6 or newer the above can be performed with

  rev r0,r1
樱&纷飞 2024-10-11 18:21:54

查看是否有字节反转命令即(__REV()、__REV16()、__REVSH())。这些是利用硬件的内联汇编指令,与上面的较慢但可移植的解决方案不同。 (链接1,< a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/CHDDIGAC.html" rel="noreferrer">链接2)

See if there is a byte reversal command i.e. (__REV(), __REV16(), __REVSH()). These are inline assembly instructions that utilizes the hardware unlike the slower but portable work around answers above. (link1, link2)

攒一口袋星星 2024-10-11 18:21:54

考虑一下如何在 C 等高级语言中转换字节顺序,然后当您了解可以轻松地将其转换为 ARM 汇编时,例如

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

,对于 16 位情况,您有两个移位(左移和右移)和一个移位或者。您应该能够通过 3 条指令来完成此操作。

Think about how you would convert endianness in a high level language like C, and then when you understand that you can easily translate it into ARM assembly, e.g.

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

So for the 16 bit case you have two shifts (one left and one right) and an OR. You should be able to do this in 3 instructions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文