1. C/C++ 에는 포인터가 있지. 그래서 특정 주소를 원하는 단위로 접근 할 수 있어.


메모리의 내용은 비트 단위인 1 과 0 으로 표현되지만

( 폰 노이만 박사가 2진법 채용이 좋아유~ 해서 다들 응~ 좋구나~ 하고 쓰는거 )


비트 단위로 읽고 쓰는게 너무 노가다니까 최소 접근 단위를 char 로 적용한 경우가 대부분이지

( bit field 표현은 어차피 CPU 내부 명령어 레벨엔 없으니 제외 )

( 편의점에서 담배 한 개피씩 팔면 짜증나겠지? )


그래서 char, short, int, long long 이런식으로 1, 2, 4, 8 바이트 단위로 처리하곤 하잖아?

( 컴파일러 마다 조금씩 다르지만 )


근데 문제가 있어.

메모리에 접근할때 한번에 4바이트를 가져오려면, 그 주소도 4의 배수여야 되고,

2바이트를 접근하려면 주소도 2의 배수여야 한다는게 대부분의 하드웨어 스펙이야.


즉, 다시 말해

0x00000001 주소에서 4 바이트를 읽거나 쓰려고 하면 오류를 낸다는거지.

0x00000000 주소나 0x00000004 등 4의 배수인 경우에만 쓸 수 있다는 이야기.


C/C++ 에서 포인터는 자유도가 뛰어나서 다음과 같은 표현이 가능하지.


char temp[64]; // temp 가 4바이트 단위 주소에 정렬되어 있다고 가정하자. align 지시어는 컴파일러 마다 다르니.

int* a = (int*)( temp + 1 ); // 여기서 temp + 1 은 당연히 unaligned

*a = 3; // 여기서 SIGBUS


이러면 대부분 빌드는 되지만,

막상 실행해보면 우리가 주로 사용하는 인텔 CISC 아키텍쳐인 x86 / x64 를 제외한 다른 시스템에선

SIGBUS fault 를 내고 실행이 중단되기도 해.


그러니 1바이트 보다 큰 단위로 접근할때는 주소를 정렬해서 진행하든지, 아니면 1바이트씩 접근해야 한다는거야.

( 1의 정수배는 모든 정수잖아? 즉 1바이트 단위는 항상 주소가 정렬된 셈인거지 )


그런데 intel architecture 에는 이런 정렬되지 않은 접근을 허용해. ( protection )

그렇다 하더라도 aligned 보단 성능이 느렸어. ( 사실은 aligned 처리를 일일이 CPU 가 대신해 주는거 )


그래서 사람들은 대개 aligned 로 소스코드를 최적화 했지.

한번에 큰 단위로 읽거나 쓰기 위해서 말야.

core / data bus 32비트 architecture 면,

CPU 와 메모리 라는 출발/목적지 사이에서 자동차( data bit )가 달릴수 있는 길이 32차선인 셈인데,

매번 1바이트 단위로 8대씩만 달리게 하면 낭비잖아?

교통량이 많을 때 ( 많은 데이타를 읽고 쓸때 )는 당연히 32차선을 꽉꽉 채우는게 득이지.


그러기 위해서 시작주소가 4로 나눠떨어지지 않는 부분만큼을 1 byte 단위,

4로 정렬될수 있는 마지막 주소 이후 짜투리를 또 1 byte 단위로 읽고 쓰는 식으로 최적화를 한다는거야.


근데 intel 에서 SIMD 를 지원하기 시작하면서 SSE 확장 명령어들이 추가되었고,

이 중에 정렬되지 않은 주소에 접근하는 unaligned 처리를 가속화 해주는 명령도 생겼어.

그래서 기존의 파라다임과는 다른 특이한 상황이 벌어진거야.


그 내용을 알고 있던 ㅅㅅㅅ 란 애가 다른 커뮤니티에 SIGBUS 에 대해 잘 알고 쓰면 상관없다고 말한 것에 대해

kukyakya 가 개소리라고 씹고는,

그걸 또 프갤에 퍼 와서 모욕을 줬지.


그게 이 사건의 발단인거야.

길어져서 다음글로.