근 한달동안 모든 코딩을 어셈블리어로만 하고 있다보니 호출 규약(Calling Convention)을 다시 살펴보고 있습니다. C로 프로그래밍하던 시절에는 호출 규약은 별로 신경쓰지 않았는데, 어셈블리어로 함수를 호출하려니 안 볼수가 없더군요. ㅠㅠ


MINT64 OS를 만들 때 어셈블리어로 코딩했으면서 왠 엄살이냐고 생각하실텐데... 리눅스에서 사용하는 호출 규약(Calling Convention)과 윈도우에서 사용하는 호출 규약은 상당한 차이가 있더라구요. ㅠㅠ 그래서 적응하는데 살짝 힘들었습니다. 사실 적응한다기 보다는 차이를 아는데 시간이 좀 걸렸지요. ㅠㅠ

64비트 리눅스의 호출 규약

리눅스는 64비트 모드에서 파라미터를 전달할 때 윈도우보다 레지스터를 더 많이 사용합니다. 정수 타입의 파라미터를 전달할 때는 순서대로 RDI, RSI, RDX, RCX, R8, R9까지 6개의 레지스터를 사용하고 7개 이상이면 스택을 통해 전달합니다. 실수 타입의 파라미터의 경우는 XMM0 ~ XMM7까지 8개를 순서대로 사용하고 그 이상이면 스택으로 전달하지요. ;)


반환값은 정수일 때 RAX(하위 64비트), RDX(상위 64비트)를 사용하고, 실수일때는 XMM0(하위 128비트), XMM1(상위 128비트)를 사용합니다. 아래는 64비트 멀티코어 OS 원리와 구조의 11.2.2 장에서 추출한 호출 규약 그림입니다. ;)




64비트 윈도우의 호출 규약

반면, 윈도우는 64비트 모드에서 파라미터를 전달할 때 레지스터 4개만 사용합니다. 정수 타입의 경우는 순서대로 RCX, RDX, R8, R9를 사용하고 나머지는 스택으로 전달합니다. 실수의 경우는 XMM0 ~ XMM3까지 4개를 순서대로 사용하며 나머지는 스택으로 전달합니다. 여기까지 보면 파라미터로 사용하는 레지스터의 종류와 개수만 차이가 나는 것 같습니다만.... 실제로 보면 스택을 사용하는 방법도 차이가 있습니다.


리눅스의 경우 파라미터를 전달할 때 스택을 꽉꽉 채워서 사용하는 반면, 윈도우의 경우는 4개의 레지스터가 들어갈 공간만큼을 띄워서 사용합니다. 즉, 파라미터 4개가 RCX, RDX, R8, R9를 통해 전달되지만, 스택에 이 4개를 위한 공간을 할당해놓는 것이죠. 아래 그림을 보시면 좀 더 이해하시기 편할 겁니다. ^^;;;





이 차이 때문에 한참을 헤맸네요. ㅠㅠ 스택에 저 공간을 안 할당해놓으면 파라미터가 잘못 전될되서 보기좋게 함수 호출이 실패를... 쿨럭..;;; 그리고 주의할 점은 비록 파라미터가 4개 미만이더라도 함수 호출 시 저 영역은 무조건 할당해야 한다는 겁니다. 에궁... 진짜 알고나면 별 것 아닌데... 코드를 몇 번이나 갈아 엎었는지 모르겠네요. ㅠㅠ


C로 코딩을 했으면 아예 신경을 안써도 되는 부분인데... 어셈블리어로 코딩하다보니 삽질을 하고 말았군요. ㅎㅎ 윈도우 호출 규약에 대한 보다 자세한 내용이 궁금하시다면 MSDN 사이트를 참고하시기 바랍니다. ^^


그나저나 PE32 파일 포멧을 읽어 메모리에 로딩하여 실행하는 가볍게 어셈블리어로 작성하는 괴수(?)를 어떻게해야 따라잡을 수 있을까요? 아우... 따라가려니 죽을 것만 같네요. ㅠㅠ


그럼 좋은 밤 되세요 ;)

 안녕하십니까 까마굽니다 (__)

 크윽... Add 명령을 조합하다가 도저히 지금의 구조로는 모든 명령에 대해 조합을맞추가기 어렵다는 결론이 났습니다.  MOV 까지는 잘 맞춰졌는데, Add가 되니까 약간씩 핀트가 어긋나서 다른 코드가 선택되는 걸 피할 수 가 없군요.

 으으... 이때까지 Register를 중심으로 Define하고 코드를 개발했었는데, 이게 오산이었습니다. 명령어의 Operand를 중심으로 했어야 하는데, 기존에 define 된걸 가지고 Operand를 맞출려고하니 무리가 있군요. Scanner 정도는 그냥 쓸수있을꺼 같은데, Parser랑 Code Generator는 완전히다시 써야 할듯 합니다.

 사실 생각한건데, Parser랑 Code Generator를 분리할 필요는 없다고 생각되네요. 분리를 하고 나니까 중복으로 검색하는것이 있어서, 하나로 합치는게 옳은거같군요. 일단 좌절입니다.

 아아.. 힘빠져.. ㅡ0ㅠ...다들 좋은하루 되세요 (__)

 안녕하십니까 까마굽니다 (__)
 으으.. 오늘 Machine Code Generator를 만들다가, OpCode까지는 어케 선택을 해줬는데, Mod 및 SIB를 선택하지 못하여 하루종일 보냈슴다. 이제야 필을 받아서 일단 mov reg, reg 형식을 대략 완성하고 output을 냈는데요,다행이도 nasm이랑 output이 같게 나오는걸 보니, 테이블을 틀리게 만든건 아닌거같군요.

 흠, 아직 테이블을 좀더 만들고 테스트해야 하는게 있긴하지만 머, 일단 첫발을내딛었기땜시롱 한자 끄적여 봅니다. 처음에는 모든 경우의 수를 생각하고 Scanner랑 Parser를 만들었는데요, 오늘 딱생각하니 빼먹은것이 있군요.

 으으, 다 포함하려니 소스가 자꾸 복잡해져서리 일단간단하게 완성하고 덧붙이던가 해야 되겠군요.에궁, 징짜 너무 빡시네요.

 그럼 좋은하루 되세요 (__)아래는 테스트 결과
/////////////////////////////////////////////////////////////////////////////
//input file
/////////////////////////////////////////////////////////////////////////////
mov ebx, eax
mov ebx, ecx
mov ebx, edx
mov ebx, esi
mov ebx, edi
mov ecx, eax
mov ecx, ebx
mov ecx, ecx
mov ecx, edx
mov ecx, esi
mov ecx, edi
mov edx, eax
mov edx, ebx
mov edx, ecx
mov edx, edx
mov edx, esi
mov edx, edi
mov esi, eax
mov esi, ebx
mov esi, ecx
mov esi, edx
mov esi, esi
mov esi, edi
mov edi, eax
mov edi, ebx
mov edi, ecx
mov edi, edx
mov edi, esi
mov edi, edi

//////////////////////////////////////////////////////////////////////////////
// 아래는 Kkamagui Simple Asambler Output
//////////////////////////////////////////////////////////////////////////////
Output[89C3]
Output[89CB]
Output[89D3]
Output[89F3]
Output[89FB]
Output[89C1]
Output[89D9]
Output[89C9]
Output[89D1]
Output[89F1]
Output[89F9]
Output[89C2]
Output[89DA]
Output[89CA]
Output[89D2]
Output[89F2]
Output[89FA]
Output[89C6]
Output[89DE]
Output[89CE]
Output[89D6]
Output[89F6]
Output[89FE]
Output[89C7]
Output[89DF]
Output[89CF]
Output[89D7]
Output[89F7]
Output[89FF]

 안녕하십니까 까마굽니다 (__)
 요 이틀째 어셈블러 제작에 매달리고 있는데요, 오늘 오전즈음해서 scanner를테스트한 다음, 그 output을 parser에 넣고 문법을 검사하려다보니, 기본적인 검사를 하더라도, 어셈명령에 따른 operand의 갯수 같은 것이 필요하겠더라구요.

 그리고 머신코드를 생성할 때는 각 operand에 따른 머신 코드의 맵핑 테이블이필요한데, 막상 고민해보니 깔끔한 생각이 안떠오르더군요. 하드코딩을 안할려고 머신코드의 규칙을 살펴봤으나, prefix/MOD/SIB 머 이런것들은 일정한 규칙같은게 있던데, 머신코드는.. ㅡ0ㅡ;;;;;

 그래서 nasm을 참고할려고 들여다 봤더니, 쿠.. 쿨럭...걍.. 테이블이 하드코딩 되어있더군요. ㅠㅇㅠ/~~크윽... 그래서 일단 저도 하드코딩해서 테이블을 만들어 놓고 이제 parser를만들어 테스트를 할려고 생각중입니다.하.. 참나... 이거 무쟈게 빡시군요.기본적으로 제가 쓰는 명령만 구현하는데도, 한참 걸리겠습니다. 그려...일단 오늘도 삽질 @0@/~~

 그럼 좋은하루 되세요 (__)

 안녕하십니까 까마굽니다 (__)
 넹 커널을 릴리즈한지 며칠이 지났는데요, 다행이도 "왜 일케 짯어요??" "정신이 있는 사람이에요??" 이런식의 글이 올라오지 않아서 긴장을 풀고 있습니다. ㅋㅋㅋ사실 잔뜩 요 며칠 쫄아있었기 땜시롱, 워낙 허접한 코드를 릴리즈해놔서 이것 또한걱정이군요.

 ㅡ0ㅡ;;;흠, 당분간 커널 소스는 손을 안대고, 다른걸 쪼금씩 해볼 생각을 하고 있습니다.머, 다음에 손보게 되면, FAT를 좀더 보강하고, 스레드를 구현해 넣고 GUI 함수약간 더 추가하는 정도가 될것 같군요.스레드와 GUI 함수에 대해서는 아직 뚜렷한 방향이 잡히지 않아서 약간 시간이 걸리겠구요, FAT 루틴은 사실 약간 보강이 된 상태인데 추가해야 할 부분이 생겨서그부분에 대한 처리를 미뤄둔 상태입니다.

 음, 글고보니 응용 프로그램용 라이브러리와 응용프로그램 전송하는 방법에 대한언급이 없었네요. 이것도 시간나는대로 릴리즈를... ㅋㅋㅋ아아, 눈탱이가 아프군요... 갑자기 왜이러지...그만 자야겠습니다.

 다들 좋은밤 되세요 (__)

 안녕하십니까 까마굽니다 (__)
 오늘 한번 어셈블러를 끄적거려 볼려고 했었습니다만, 쇼크만 먹었습니다.흠, 전 지금까지 Opcode는 각 명령에 대해서 1:1로 대응되는줄 알고있었기때문에,쉽게 보고 있었는데, 오늘 문서를 보니 같은 mov라도 뒤의 Operand에 따라서 Opcode가 틀리더군요.

 또 뒤에 오는 Operand 타입에 따라서 옵션으로 설정되는 것들이 있고, 으아~~ 어찌나 복잡하던지...하는수 없이, 책을 일단 쬐금 복사한다음 nasm을 이용해서 역어셈해가면서 봤습니다.규칙이 있긴하던데, 머 관건은 머신코드를 작성할때 적절한 Opcode를 선택하기위해서는 Operand의 Type을 알고있어야 한다는 결론에 봉착한것 말고는 별 소득이 없네요.테이블도 몇개를 이용해야 될꺼 같고, 으음 일단 mov 명령을 잘 뜯어본다음 nasm과동일한 output이 나오도록 한번 해봐야 겠습니다.

 그러려고하니 문제가, scanner를 만들어야 하겠는데 머 만드는거야 별 문제가 없지만 중요한건 scanner의 output을 parser가 가지고가서 문법 체크를 하고, 다시 이걸넘겨받아서 머신코드를 만드는 놈이 output을 만들어 내야 하는데, scanner의 output을 어떤식으로 할지가 문제군요.머 일단 Token단위로 자른다 치면, scanner의 output으로는 Token별 String도 있어야 할터인데 어떤식으로 할지 걱정이군요.걍 Queue에 넣어버릴까나, 쩝쩝... 암생각하지말고 String의 크기만큼 동적할당해서걍 스트링 복사한다음 Queue에 넣는 무식한 방법도 생각하고 있습니다.

 오홀홀홀.. 혹시 머 좋은 생각 있으신분 계신가요??있으시면 답글좀...
 그럼 좋은하루 되세요 (__)

 안녕하십니까 까마굽니다 (__)
 요즘 계속 소스를 정리한다고 거의 기능 추가부분은 손을 안대고 있습니다.그래도 계속 무리를 좀 했더니 대충은 끝나 가는군요.사실, 세부적인 정리는 안했고 그냥 인덴트랑 주석을 좀 정리하고, 가장 중요한디버깅 코드들을 삭제하는데 중점을 두었습니다.

 머 사실 몇몇 파일들은 한참 개발중이기 때문에 정리자체가 무의미 하다고 생각되어 무시한것도 있습니다만, 여튼 끝이 보입니다.이제 파일도 몇개 안남았는데( 사실 무쟈게 많더군요... ㅡ0ㅠ.. 죽는줄 알았음 또 소스는 얼마나 긴지.. 꼭 공부 못하는 애들이 코드가 길듯.. ), 정리 되고 나면커널 소스를 올리겠습니다.

 그럼 좋은하루 되세요 (__)
 ps) 홧팅입니다 @0@/~~

+ Recent posts