Explain the concept of big-endian and little-endian in the ARM architecture

Explain the concept of big-endian and little-endian in the ARM architecture

Every time a computer stores a number bigger than a single byte in memory, it has to decide the order in which the bytes go. That decision — endianness — sounds trivial, but it’s a source of subtle, hard-to-debug problems in networking, file formats, cross-platform code, and firmware. ARM, uniquely among mainstream architectures, actually supports both byte orders. This article explains what endianness is, how ARM implements it, and why it still matters today.

What Is Endianness?

Endianness describes the order in which bytes of a multi-byte value (like a 32-bit integer) are stored in memory.

Take the 32-bit hexadecimal value 0x12345678. It’s made up of four bytes: 12, 34, 56, 78.

Address:        0x00   0x01   0x02   0x03
Big-endian:     12     34     56     78
Little-endian:  78     56     34     12

The term comes from Jonathan Swift’s Gulliver’s Travels, where a war breaks out over which end of a boiled egg to crack — “big-endians” vs. “little-endians.” Danny Cohen borrowed the metaphor in a famous 1980 paper on byte-order arguments in computer networking, and the name stuck.

Why Does Endianness Exist At All?

Different early processor designers chose different conventions based on hardware implementation trade-offs — how carry propagation worked in arithmetic units, how it simplified type-casting between different sized integers, and how it interacted with I/O hardware. Neither choice is objectively “better” for all purposes:

Endianness in the ARM Architecture

Unlike x86 (which is always little-endian) or older SPARC (always big-endian), ARM is bi-endian. This means the architecture defines mechanisms for operating in either mode, and the actual endianness in effect can, on many ARM implementations, be configured — sometimes even switched at runtime.

BE-32 and BE-8: The Two Big-Endian Flavors

ARM’s history here is genuinely a bit messy, and understanding it requires knowing two distinct big-endian models it has supported over the decades:

How ARM Selects Endianness

Modern ARM cores (ARMv7 and ARMv8/AArch64) determine endianness through configuration bits:

Critically, in almost every real ARM deployment — Android phones, iPhones, embedded Linux boards, Raspberry Pi — the system is configured to run in little-endian mode, because:

  1. It’s compatible with the overwhelmingly little-endian software ecosystem (most C/C++ code, most Linux distributions, and all mainstream compilers default to assuming little-endian on ARM).
  2. It matches the byte order used by x86, easing porting of software between desktop/server (x86) and mobile/embedded (ARM) platforms.

So while ARM can do big-endian, and it’s occasionally used in specialized embedded/networking equipment (some network processors and legacy telecom gear run ARM in BE-8 mode for compatibility with big-endian protocol stacks or legacy code), the vast majority of ARM devices you’ll ever touch — Android phones, iPads, Raspberry Pis, ARM-based Chromebooks, AWS Graviton servers — run little-endian.

Instructions Sensitive to Endianness

Endianness only affects how multi-byte memory accesses are interpreted — single-byte loads/stores (LDRB/STRB in ARM assembly) are unaffected. It matters for:

Practical Implications and Examples

Networking

Network protocols like TCP/IP define network byte order as big-endian. An ARM device (running little-endian, as almost all do) must byte-swap multi-byte fields — IP addresses, port numbers — when constructing or parsing packets. This is why C code universally uses functions like htons() (host-to-network-short) and ntohl() (network-to-host-long) rather than assuming a byte order. These functions are effectively no-ops on big-endian systems and perform an actual byte swap on little-endian systems like standard ARM Linux/Android builds.

#include <arpa/inet.h>

uint16_t port = 8080;
uint16_t network_order_port = htons(port); // byte-swaps on little-endian ARM

File Formats

Some binary file formats (like older .bmp variants, Java .class files, and certain audio/network capture formats) specify big-endian fields. Code that parses these on ARM must explicitly byte-swap, typically via __builtin_bswap32() (GCC/Clang intrinsic) or ARM’s dedicated REV instruction, which reverses byte order in a register in a single cycle.

; ARM assembly: reverse byte order of a 32-bit register
REV r1, r0   ; r1 = byte-swapped r0

Cross-Compilation and Debugging

When cross-compiling for ARM targets (e.g., building Android NDK code, or embedded Linux firmware) on an x86 development machine, both are little-endian by default, so raw memory dumps and struct layouts usually “just work” without manual byte-swapping — a major convenience that’s part of why little-endian ARM became the mobile/embedded standard.

Real-World Use in Legacy and Networking Equipment

Historically, some networking hardware (routers, switches) using ARM or MIPS cores ran in big-endian mode to match legacy network protocol stacks and existing big-endian codebases inherited from earlier PowerPC- or MIPS-based designs. Modern networking gear has largely converged on little-endian ARM as well, but you may still encounter BE-8 configurations in specialized telecom or industrial control firmware.

Comparing Endianness Across Architectures

ArchitectureDefault EndiannessNotes
x86 / x86-64Little-endianFixed, no big-endian mode
ARM (ARMv7, AArch32)Configurable (BE-8/LE)Little-endian used almost universally in practice
ARM (AArch64, ARMv8+)Configurable (BE-8/LE)Little-endian default on virtually all consumer devices
PowerPCConfigurableOften big-endian historically, though PowerPC64 supports LE
MIPSConfigurableBoth variants (MIPSEB/MIPSEL) used historically
SPARCBig-endianFixed
RISC-VConfigurable (spec allows both)Little-endian is the common default

Troubleshooting Endianness Issues

Best Practices

  1. Never assume endianness in code meant to be portable — use explicit serialization functions (htons/ntohl, or a well-tested serialization library) rather than raw pointer casts.
  2. Use fixed-width, explicitly-ordered formats (like Protocol Buffers, MessagePack, or well-specified binary formats) for data interchange to sidestep endianness ambiguity entirely.
  3. Leverage compiler intrinsics (__builtin_bswap16/32/64 in GCC/Clang) rather than hand-rolled byte-swapping loops — they compile down to a single efficient instruction (like ARM’s REV) instead of multiple shifts and masks.
  4. Document assumed byte order in any custom binary protocol or file format your project defines.
  5. Test on both simulated endian modes if you’re building embedded or networking software that might run on a big-endian ARM configuration, since bugs here are notoriously easy to miss in day-to-day little-endian development.

Summary

Endianness is the convention that decides byte ordering for multi-byte values in memory, and ARM is unusual in that it architecturally supports both big-endian and little-endian modes — a legacy of its BE-32 and modern BE-8 implementations. In practice, nearly every ARM device you interact with today, from smartphones to Raspberry Pis to cloud ARM servers, runs little-endian, largely for compatibility with the dominant little-endian software ecosystem built around x86. Still, understanding ARM’s bi-endian capability matters for networking code, binary file parsing, and specialized embedded/telecom systems where big-endian configurations persist.

FAQs

Q: Is ARM big-endian or little-endian? ARM supports both, but essentially all consumer and mobile ARM devices (Android, iOS, Raspberry Pi, cloud ARM servers) run in little-endian mode.

Q: What’s the difference between BE-32 and BE-8? BE-32 is an older, word-invariant big-endian scheme used up to ARMv5; BE-8 is the modern, byte-invariant scheme used from ARMv6 onward and is the only big-endian mode available on current ARM cores.

Q: Does endianness affect single-byte data? No — a single byte has no internal ordering, so byte-level reads/writes (LDRB/STRB) are unaffected by endianness settings.

Q: Why is “network byte order” big-endian if most devices are little-endian? It’s a historical convention from early Internet protocol design (RFC 1700) that predates the dominance of little-endian hardware; it remains standardized for backward compatibility, so little-endian systems must convert accordingly.

Q: Can an ARM CPU switch endianness at runtime? Older AArch32 cores technically supported the SETEND instruction for a runtime switch (now deprecated), but in practice, endianness on real systems is fixed at boot/configuration time by firmware and the OS, not toggled dynamically by applications.

References

Exit mobile version