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 가 개소리라고 씹고는,
그걸 또 프갤에 퍼 와서 모욕을 줬지.
그게 이 사건의 발단인거야.
길어져서 다음글로.
댓글 0