여러 바이트짜리 수를 메모리에 적을 때 인텔 CPU는 가장 아랫자리 바이트를 가장 낮은 주소에 둔다. 1234를 칸마다 한 덩이씩 “34, 12” 순서로 적는 셈이다. 레지스터로 통째로 읽으면 CPU가 알아서 원래 순서로 돌려놓으므로 평소에는 신경 쓸 일이 없다. 하지만 메모리를 한 바이트씩 들여다보거나 큰 값의 일부만 꺼낼 때는 뒤집힌 순서를 직접 따져야 한다.
예시로 보기
메모리 한 칸은 1바이트다. 4바이트짜리 수 12345678h는 네 칸에 나눠 담아야 한다. 어느 바이트를 첫 칸에 둘까? 정해 두지 않으면 쓴 쪽과 읽는 쪽이 서로 다른 수를 보게 된다.
val1 DWORD 12345678h
주소 0000 0001 0002 0003
바이트 78 56 34 12
아랫자리 ───────────► 윗자리
가장 아랫자리 바이트 78h가 가장 낮은 주소 0000에 간다. 종이에 쓰는 순서(12 34 56 78)와 반대다. 뒤집히는 단위는 바이트다. 16진수 두 자리가 한 덩이로 움직이고, 78이 87이 되지는 않는다.
정의
1바이트보다 큰 자료형은 바이트를 거꾸로 저장한다. 가장 아랫자리 바이트(least significant byte)가 첫 번째, 곧 가장 낮은 주소에 온다. 인텔이 정수를 메모리에 저장하는 방식이다.
기호로 쓰면, \(n\)바이트 값 \(v\)를 주소 \(A\)에 저장할 때 주소 \(A + k\)에 들어가는 바이트 \(b_k\)는 다음과 같다. \(k\)는 0부터 \(n - 1\)까지의 칸 번호다1.
\[b_k = \left\lfloor \frac{v}{256^k} \right\rfloor \bmod 256, \qquad v = \sum_{k=0}^{n-1} b_k \cdot 256^k\]왼쪽 식은 “\(v\)를 256으로 \(k\)번 나눈 몫의 마지막 바이트”다. 오른쪽 식은 읽을 때 하는 일로, 주소가 \(k\)만큼 높은 바이트에 자릿값 \(256^k\)을 곱해 더한다. 12345678h라면 \(78\text{h} + 56\text{h} \cdot 256 + 34\text{h} \cdot 256^2 + 12\text{h} \cdot 256^3\)이다.
메모리에서 레지스터로 정수를 읽으면 바이트가 자동으로 다시 뒤집혀 제자리에 들어간다. mov eax,val1 뒤의 EAX는 12345678h다.
예제
뒤집히는 것과 그대로인 것.1
| 정의 | 메모리(낮은 주소부터) | 무엇이 뒤집혔나 |
|---|---|---|
w WORD 1234h |
34 12 |
워드 안의 두 바이트 |
arr WORD 1,2 |
01 00 02 00 |
원소 안의 바이트만. 원소의 순서는 그대로다 |
s BYTE "ABCD" |
41 42 43 44 |
없다. 1바이트짜리는 뒤집을 것이 없다 |
x DWORD 41424344h |
44 43 42 41 |
더블워드 안의 네 바이트 |
마지막 두 줄은 종이에 쓴 모양이 같아 보여도 메모리 배치는 정반대다.
활용
- 디버거의 메모리 창은 낮은 주소부터 바이트를 보여 준다.
78 56 34 12가 보이면 더블워드 12345678h다. - 큰 값의 일부만 꺼낼 때 순서를 따진다.
val1의 주소에서 2바이트를 읽으면 윗자리 1234h가 아니라 아랫자리 5678h가 나온다: OFFSET과 PTR 연산자. - 윗자리 바이트를 낮은 주소에 두는 방식도 있다(빅 엔디언). 순서가 다른 기계끼리 바이트를 주고받을 때는 한쪽이 뒤집어야 한다1.
연결
- 선수: 데이터 정의
- 자릿값을 곱해 더하면 수가 된다는 원리(여기서는 256진법): 진법과 자릿수
- 배열 원소의 가운데 주소를 읽으면 생기는 일: 피연산자의 종류
- 연습: PTR과 리틀 엔디언 예제 사다리
확인 문제
C1 v DWORD 0A1B2C3Dh가 주소 0000부터 놓인다. 주소 0000~0003의 바이트를 순서대로 쓰라.
답: 3D 2C 1B 0A.
이유: 가장 아랫자리 바이트 3Dh가 가장 낮은 주소에 간다. 16진수 한 자리씩 뒤집어 D3 C2 B1 A0으로 쓰면 틀린다. 바이트 안의 두 자리는 그대로다.
C2 a WORD 1000h,2000h의 메모리는 (가) 00 10 00 20 (나) 20 00 10 00 (다) 10 00 20 00 가운데 무엇인가? 나머지는 왜 아닌가?
답: (가).
이유: 원소는 적은 순서대로 놓이고, 각 원소 안에서만 아랫자리 바이트가 앞에 온다. (나)는 배열 전체를 뒤집었다. 원소의 순서는 바뀌지 않는다. (다)는 아무것도 뒤집지 않은 빅 엔디언 배치다.
C3 메모리에 낮은 주소부터 EF CD AB 89가 있다. 이 네 바이트를 더블워드 하나로 읽은 값과, 워드 둘로 읽은 값을 쓰라.
답: 더블워드 89ABCDEFh. 워드로는 앞의 것이 CDEFh, 뒤의 것이 89ABh.
이유: 높은 주소의 바이트가 윗자리가 된다. 같은 바이트라도 몇 바이트씩 묶어 읽느냐에 따라 값이 달라진다.