dumpcode() 함수에대해알게된구타는대견하게도실습을하기로마음먹습니다. 구타는먼저 4 바이트짜리정수형변수를하나만든후, 그것을 memory dump 를해보기로했습니다. #include dumpcode.h int main() { int test = 10; dumpcode( 98
소스코드를완성한구타는컴파일을시도합니다../11/ex1.c #include dumpcode.h int main() { int test = 10; } dumpcode(&test, 4); [ 컴파일결과 ] $ cd 11 $ gcc -o ex1 ex1.c ex1.c: In function `main : ex1.c:7: warning: passing arg 1 of `dumpcode from incompatible pointer type $ 99
./11/ex2.c #include dumpcode.h int main() { int test = 10; } dumpcode((unsigned char *)&test, 4); [ 컴파일결과 ] $ gcc -o ex2 ex2.c $ 100
dumpcode() 는잘작동했지만, 구타는무언가이상한점을발견합니다. $./ex2 0xbffffb44 0a 00 00 00... $ 101
이처럼메모리에저장된값을 dump 해보면, 그순서가반대로나타나는재미있는특징을볼수있습니다. 이를컴퓨터용어로 Little Endian 이라고부르는데요, 이중 Endian 이라는단어는영어사전을찾아봐도나오질않습니다. 그이유는이 Little Endian 이라는말이 걸리버여행기 라는다들잘알고계실소설에서처음만들어졌기때문인데요, 그이야기가재미있기때문에소개를해드리려고합니다. 걸리버여행기 란, 항해술과의술을공부한주인공이선박의선원들을돌보는외과의사로취업한후, 항해도중겪게되는황당한사건들에대한이야기를담고있는모험소설입니다. 이소설은 1726 년조나단스위프트란영국작가에의해쓰여졌는데요, 가상의이야기에빗대어인간의추악한모습들을비유적으로풍자하며오늘날까지도세계적인명작에꼽히고있습니다. 소설의주인공은항해중사고로인해 소인국나라, 거인국나라, 하늘의섬 등에표류하게되는데요, Little Endian, 그리고그에대립되는 Big Endian 이라는용어는이들중 소인국나라 편에등장합니다. 거대한폭풍우에휩쓸려난파된선박에서탈출한주인공은, 끝내외딴섬에도착해정신을잃게됩니다. 그리고다음날정신을차렸을땐이미온몸이밧줄로꽁꽁묶인상태였습니다. 102
주인공은밧줄에서벗어나려고발버둥을쳐보지만, 수많은소인국군인들의화살공격에기가죽어순순히복종을하게됩니다. 이후주인공은발에쇠사슬이묶인채노예와같은생활을하게되는데요, 친절함과너그러움으로점차소인국사람들로부터신뢰를얻어자유의몸이된후, 이웃국가와의전쟁을승리로이끌기도하며, 급기야두국가를화해모드로이끌고, 결국엔그섬을빠져나와고향으로돌아간다는훈훈한이야기를담고있습니다. Little Endian 과 Big Endian 이야기는위에언급된두국가인릴리퍼트와블레프수크가도대체무엇때문에사이가안좋아졌는지에대해듣게되는부분에서등장하는데요, 그사연은이렇습니다. 약 36 개월전, 릴리퍼트제국은지금과마찬가지로식사때달걀을즐겨먹었습니다. 그리고이들은달걀을먹을때, 끝부분이넓직한부분을위로향하게한다음껍질을깨먹었다고합니다. 그런데어느날역사적인사건이발생하는데, 바로황제의세자가이넓직한부분부터달걀을깨어먹다가그만껍질에손을베어버린것입니다. 화가난황제는앞으로달걀을먹을때넓직한부분이아닌, 뾰족한부분부터깨어먹어라, 그렇지않는자는사형에처한다라는새로운법률을공포하게됩니다. 103
버퍼 오버플로우-왕기초편 11.리틀엔디안과 빅엔디안 104
버퍼 오버플로우-왕기초편 11.리틀엔디안과 빅엔디안 105
하지만이에반대하는무리가생겨나기시작했고, 여러번의반란끝에국가는두개의당파로갈라지게됩니다. 그리고뾰족한끝부분, 즉작은부분에서부터깨어먹는것을주장하는무리를 Little Endian, 반대로넓직한끝부분에서부터깨어먹어야한다고주장하는이들은 Big Endian 이라고부르게된것입니다. Big Endian 당파는이웃국가인블레프수크의도움을받거나망명을가면서급기야두국가간의전쟁으로발전합니다. 이처럼소인국국가들은작은몸짓답게참으로사소한것을가지고싸움을하고있는데요, 이는마찬가지로사소한것들로전쟁을하고살인을하는우리인간들을풍자한것이라고합니다. ( 당시영국과프랑스의종교전쟁을빗댄것이라는해석이있습니다.) 이제다시컴퓨터분야로넘어옵시다. 이 Little Endian 과 Big Endian 이란용어는 Danny Cohen 이라는사람의논문중 Memory Order 라는섹션에서처음인용됩니다. 이논문에선 CPU 가메모리에데이터를저장할때어느순서로저장하는가에대해설명하는데, 이때왼쪽에서오른쪽순서로저장하는것을 Big Endian, 그리고오른쪽에서왼쪽으로저장하는것을 Little Endian 이라고비유한것이시초가되어지금까지도사용되어지고있는것입니다. 이처럼메모리에값을저장하는두방법엔서로장단점이있는데요, 먼저높은쪽의값을먼저저장하는 Big Endian 을봅시다. 106
Big Endian 은두개의숫자를비교할때더욱빠르게연산할수있습니다. 만약첫바이트에서한쪽이더크다면나머지바이트들은더이상비교를할필요가없기때문입니다. 그리고 Big Endian 은우리가사용하는방식에친근하다는장점도있습니다. 다음으로 Little Endian 입니다. Little Endian 은이수가짝수인지홀수인지를검사할때빠르다는장점이있습니다. 첫바이트하나만보면짝수인지홀수인지를금방알수있기때문입니다. 그리고연산과정에서자릿수증가가생겼을때 Big Endian 방식보다더빠르다고합니다. 그리고또하나, 이 Little Endian 방식은포인터 (pointer) 의값참조시유리합니다. 예를들어, char *x 라는포인터변수가하나있고, 이 x 가가리키는메모리주소의값이 0x12345678 라고가정해봅시다. 이때, y = *x 와같이포인터변수가가리키는값을참조하고자할경우, 포인터의시작주소에서 1 바이트 (char 형 ) 만가져오면자연스럽게가장낮은바이트인 0x78 가참조되게됩니다. 왜냐면 Little Endian 의특성에따라메모리에저장된데이터값은 0x78 0x56 0x34 0x12 가되기때문입니다. 이와같은바이트저장순서를 Byte Ordering 이라고부르는데요, 만약서로다른 Byte Ordering 을사용하는두 PC 가네트워크통신을하면서데이터를주고받는다면이 Byte Ordering 을통일화시켜주는작업이필요할것입니다. 107
현재 TCP/IP 표준은 Big Endian 이며, 그래서대부분의프로그래밍언어가 Byte Ordering 을 Big Endian 타입으로바꿔주는 htons() 와 htonl() 함수를제공하고있기도합니다. CPU 개발업체에따라 Big Endian 과 Little Endian 이구분되는데요, 다음과같습니다. Little Endian 과 Bin Endian 사이엔서로만의장점이있기도하고, 기술적인관점을떠나생각해봐도어느것이더좋다고선뜻말할수는없습니다. 예를들어한글이나영어는왼쪽에서오른쪽으로글자를쓰지만, 히브리어, 아랍어, 이집트상형문자등은오른쪽에서왼쪽으로글자를씁니다. 이를가지고누가옳다라고말할수없는것과같기때문입니다. 여튼메모리분석을정확하게하기위해선, 이 Big Endian 과 Little Endian 을잘알고있어야합니다. 108