CPU가 명령어와 데이터를 처리하려면 먼저 메모리에 적재가 되어야 한다.

엔디안은 이때 메모리 워드에서 바이트를 저장하는 순서인 byte order를 결정한다.
엔디안에 대해 얘기하기 전에 먼저 명령어와 메모리의 논리적 구성에 대해 간단히 정리한다.

 

메모리의 속성

1) 워드(word)
워드는 명령어와 데이터를 담을 수 있는 메모리 구성 요소 중 하나이다. 워드는 고정된 개수의 bit라는 메모리 소자로 이루어진다. 컴퓨터마다 워드를 구성하는 비트 수는 다르나, 대부분의 컴퓨터에서 하나의 word는 32bit로 구성되어 있다.

 

2) 주소(address)
메모리는 주소라는 고유의 값을 사용해 명령어나 데이터를 참조한다. 택배 기사가 주소를 보고 배송을 하듯이 메모리에서 특정한 데이터가 저장된 위치를 알아내기 위해 주소를 사용한다.

 

3) 주소 지정 단위(addressable unit)
주소 지정 단위는 데이터를 담는 그릇의 크기에 해당하며 정보의 최소 단위인 주소 해상도(address resolution)를 결정한다.
최소 주소 지정 단위로 비트를 사용하는 아키텍처도 있었으나, 이 경우 주소를 나타내기 위해 많은 비트가 필요할 뿐만 아니라 데이터 정렬에 추가 시간이 필요했다. 따라서 지금은 비트 단위의 주소 해상도를 사용하지 않고 주로 8의 배수 단위로 주소 해상도를 사용한다. 주소의 기본 단위는 cpu가 한번에 인식하여 처리할 수 있는 주소 값의 범위가 된다.

 

어떤 시스템에서 16개의 데이터를 다루어야 한다고 가정해보자.
데이터를 한번에 하나씩 저장하게 된다면 16개의 주소가 필요하다. 비트로 표현한다면 2^4로 4비트의 주소를 사용해야한다.

데이터를 한번에 8개씩 저장한다면 주소는 2개면 충분하다. 이때는 2^1로 1비트의 주소를 사용할 수 있다.

데이터를 저장하는 단위가 커질수록 주소를 위한 비트가 적게 필요하다. 하지만 그만큼 데이터를 작은 단위로 취급하기가 어려워진다. 무작정 단위가 크다고 좋은 것이 아니므로 데이터를 취급하는 단위와 주소의 크기를 적절하게 조정해야 한다.

 

주소 지정 단위로 8비트로 구성된 바이트를 사용하는 것을 바이트 주소라고 한다. 오늘날 대부분의 아키텍처는 바이트 단위로 메모리를 관리하고 있다. 그리고 일관성과 간결성을 위해 명령어와 데이터에 대해 동일한 주소 해상도를 사용한다.

 

정렬된 메모리(aligned memory)

컴퓨터를 구현할 때 실행 속도를 높이기 위해 명령어와 데이터를 강제로 정렬하는 방식이다. 데이터와 명령어는 자신의 길이에 대한 배수의 주소에 위치해야 한다. 2바이트로 구성된 명령어와 데이터는 2의 배수로 시작되는 주소를 갖고, 4바이트로 구성된 명령어와 데이터는 4의 배수로 시작되는 주소를 가져야 한다. 그러면 하나의 데이터가 여러개의 워드에 걸쳐 자리잡을 일이 없기 때문에 메모리 읽기 사이클 수행 횟수를 최소화 할 수 있다.

 

출처 : https://microchipdeveloper.com/32bit:mz-arch-memory-alignment

데이터가 정렬되었을 경우와 그렇지 않을 경우를 그림으로 나타낸 것이다.

좌 : 4의 배수로 시작하는 주소를 사용해 데이터가 정렬되어 있다. 데이터를 적재하기 위해 1개의 메모리 읽기 사이클을 수행한다.
우 : 데이터가 정렬되지 않았을 경우의 예시다. 정렬되지 않은 데이터를 적재하려면 2개의 메모리 읽기 사이클을 수행해야 한다.

 

엔디안 방식

 문화권에 따라 나라마다 글을 읽고 쓰는 방향이 다르다. 왼쪽에서 시작해 오른쪽으로 쓰는 나라가 있고, 오른쪽에서 시작해 왼쪽으로 쓸수도 있다. 컴퓨터 아키텍처에서도 비슷한 일이 일어난다.

엔디안(endian)은 여러개의 연속된 대상을 1차원 공간에 배열하는 방법이다. 쉽게 말하자면 컴퓨터가 메모리에 데이터를 읽고 쓰는 방향을 정의하는 것이다. 32비트 컴퓨터를 예를 들면 워드에 4개의 바이트를 배열하는 방법이다.

 

엔디안 시스템은 주로 빅 엔디안(big-endian)이나 리틀 엔디안(little-endian)을 사용한다. 빅 엔디언의 경우 가장 왼쪽 바이트가, 리틀 엔디언의 경우 가장 오른쪽 바이트가 워드의 주소가 된다.

 

1) 빅 엔디안
상위 바이트를 하위 번지수에 저장한다. 즉, 사람이 숫자를 쓰는 것처럼 왼쪽에서 오른쪽으로 바이트를 배열한다.
이 경우 큰 단위의 바이트가 앞자리에 위치하게 한다. 최대 유효비트(MSB, Most Significant Bit)가 포함된 바이트의 주소가 워드의 주소가 된다.

 

2) 리틀 엔디안
빅 엔디안과 반대로 상위 바이트를 상위 번지수에 저장한다. 방향은 오른쪽에서 왼쪽이 된다. 최소 유효비트(LSB, Least Significant Bit)가 포함된 바이트의 주소가 워드 주소가 된다.

출처 : https://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8

 

16진수 0x12345678을 빅 엔디안과 리틀 엔디안에 따라 정렬하면 아래와 같다.
메모리 주소는 임의로 작성한 것이다.

 

big-endian

메모리 주소 0x1000 0x1001 0x1002 0x1003
16진수 12 34 56 78
2진수 0001 0010 0011 0100 0101 0110 0111 1000

 

little-endian

메모리 주소 0x1000 0x1001 0x1002 0x1003
16진수 78 56 34 12
2진수 0111 1000 0101 0110 0011 0100 0001 0010

 

내가 예전에 자료형에 대한 이해가 부족했을 때는 왜 여기서 87 65 43 21이 아니라 78 56 34 12가 되는건지 잘 이해하지 못했다.

위에서 컴퓨터는 바이트 단위로 메모리를 관리한다는 설명을 했다. 그리고 하나의 16진수를 표현하는데는 4bit가 필요하다.

1byte = 8bit, 하나의 정수 = 4bit 이므로 두자리 단위로 정렬된 결과가 나오게 되는 것이다. 정보의 최소 단위가 8bit 이므로 내부의 순서는 바뀌지 않는다.

 

각각의 장점

  • 빅 엔디언은 사람이 수를 읽고 쓰는 방법과 저장 순서가 같기 때문에 디버깅이 편리해진다는 장점이 있다.
  • 리틀 엔디언은 메모리의 하위 바이트만을 꺼낼 때 편리하다는 장점이 있다. 예를들어 0xff를 32비트 빅 엔디안 환경에서 비트로 표현하면 0000 0000 0000 0000 0000 0000 1111 1111이 된다. 리틀 엔디안에서는 1111 1111 0000 0000 0000 0000 0000 0000이 된다. 앞의 두자리만 떼어내면 바로 값을 얻어낼 수 있기 때문에 별도의 계산이 필요하지 않다. 가산기가 덧셈을 할 땐 LSB부터 올림을 계산하기 때문에 가산기의 설계도 단순해진다.

호환성

프로그램을 다른 아키텍처로 이식할 때 엔디안 시스템에 따라 워드 내부의 비트 혹은 바이트의 순서가 달라진다. 사람은 융통성을 가지고 익숙하지 않더라도 반대되는 방향의 글을 읽어볼 수 있지만, 컴퓨터는 그렇지 않다. 엔디안 시스템이 다른 컴퓨터로 프로그램을 이식할 경우 컴퓨터가 내용을 제대로 읽지 못해 문제가 생길 수 있다. 따라서 이때는 데이터가 호환될 수 있도록 엔디안을 변환하는 과정이 필요하다.

 

참고 자료

 

참고 용어

  • MSB : 비트를 나열했을 때 가장 왼쪽에 있는 비트. 주로 부호를 표시하는데 사용한다.
  • LSB : 비트를 나열했을 때 가장 오른쪽에 있는 비트