Endianness: Why Your Hex Dump Looks Backwards

Computers store everything as bytes (8 bits each, each holding a value from 0 to 255). Small numbers fit in one byte. Bigger numbers (like 1000, or a memory address) need several bytes lined up side by side in memory. The question this article answers: when a number takes multiple bytes, which byte goes first?

Two natural answers exist, and both are in use today.

Big-endian stores the most-significant byte first, the way humans write numbers. The value 0x12345678 would live in memory as 12 34 56 78. Network protocols (TCP/IP headers), older Unix-style systems, and a few non-Intel CPUs use this.

Little-endian does the opposite: least-significant byte first. The same 0x12345678 lives in memory as 78 56 34 12 (reversed compared to how you wrote it). Every x86, x86_64, RISC-V, and (by default) ARM machine you've ever touched uses little-endian. This is the immediate reason hex dumps in your debugger look "backwards".

Neither order is "right". Both work fine internally. The names come from a 1980 paper called "On Holy Wars and a Plea for Peace", which riffed on Jonathan Swift's Gulliver's Travels: two factions of Lilliputians went to war over which end of a soft-boiled egg to crack first. CPU designers in the 1970s picked sides independently, no one ever standardized, and now we live with both. The practical impact today: you have to know which one applies any time you read raw bytes as numbers, send binary data over a network, or write an exploit payload.

Five short sections walk through what this actually looks like: why hex dumps appear reversed, why exploit payloads write addresses LSB-first, why file formats have those distinctive "magic number" bytes at the start, and the real engineering reason little-endian won on consumer CPUs.

1. Same Value, Two Byte Orders

A 32-bit integer is conceptually one number, but in RAM it lives across four byte-sized addresses. Little-endian stores the least-significant byte first; big-endian stores the most-significant byte first. Modern x86, x86_64, and ARM (in its usual mode) are all little-endian.

2. The Same Bytes, Four Valid Readings

You've opened a chunk of memory in your debugger. The same 8 bytes can be interpreted as a string, as a string of small integers, or as larger integers, and the "larger integer" interpretation flips depending on the machine's endianness. This is the #1 source of "why does my disassembler show a different value than my hex dump" confusion.

3. The Return-Address Trick (Exploit Payloads)

If you've read the buffer overflow walk-through (or written your first exploit), this is the mistake that catches everyone: when you overwrite a return address, you write the bytes backwards, because that's what the CPU will read back. This section connects "little-endian" to "why does my Python payload look reversed".

4. File Format Magic Numbers

Almost every binary file format starts with a short fixed byte sequence called a "magic number" that identifies it. They're usually picked so the bytes look like recognizable ASCII (so you can spot them in a hex dump), but if you ever see them quoted as integers (in source code, in docs), endianness flips the value.

5. Why x86 Chose Little-Endian (the Useful "Why")

The "which way is more natural" debate is usually settled with "big-endian matches how humans write numbers, so it's more natural". That's not wrong, but there's a real engineering reason little-endian won on consumer CPUs: it makes type widening free.