Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Endianness conversion in ARM

Tags:

arm

endianness

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

like image 266
seyoung Avatar asked Nov 26 '10 15:11

seyoung


2 Answers

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
like image 198
old_timer Avatar answered Sep 20 '22 17:09

old_timer


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)

like image 20
nimig18 Avatar answered Sep 18 '22 17:09

nimig18