[OS개발] 2일차 - 어셈블러랑 말문이 트였다.
2일차
뭔가 어렴풋이 느낌만 왔던 1일차. 2일차는 본격적으로 어셈블리어를 익히고 Makefile을 쓰는 법을 배웠다.
# 일단 어셈블리어. 확실히 기계어에 가까운 만큼 CPU를 다루는 언어이기에 CPU의 저장 공간인 레지스터에 대해 알아야 하겠더라. 아직까진 16bit 기준이기에언제 32bit간다냐 EAX 같은 레지스터가 아닌 다음의 14가지 16bit 레지스터가 소개 되었다.
AX (accumulator) : 누적 연산기
CX (counter) : 카운터
DX (data) : 데이터
BX (base) : 기초, 기점
※ 위의 4 레지스터는 AL (AX LOW), AH (AX HIGH)등으로 나누어 8bit로 쓰는 것이 가능하다.
SP (stack pointer) : 스택용 포인터
BP (base pointer) : 베이스용 포인터
SI (source index) : 읽기 인덱스
DI (destination index) :쓰기 인덱스
ES (extra segment) : 덤 세그먼트(영역)
CS (code segment) : 코드 세그먼트
SS (stack segment) : 스택 세그먼트
DS (data segment) : 데이터 세그먼트
FS : 덤 세그먼트 No.2
GS : 덤 세그먼트 No.3
그리고 아래는 새로운 어셈코우드-
; hello-os ; TAB=4 ORG 0x7c00 ; 이 프로그램이 어디에 Read되는가 ; 이하는 표준적인 FAT12 포맷 플로피 디스크를 위한 기술 JMP entry DB 0x90 DB "HELLOIPL" ; boot sector의 이름을 자유롭게 써도 좋다(8바이트) DW 512 ; 1섹터 크기(512로 해야 함) DB 1 ; 클러스터 크기(1섹터로 해야 함) DW 1 ; FAT가 어디에서 시작될까(보통은 1 섹터째부터) DB 2 ; FAT 개수(2로 해야 함) DW 224 ; 루트 디렉토리 영역의 크기(보통은 224엔트리로 한다) DW 2880 ; 드라이브 크기(2880섹터로 해야 함) DB 0xf0 ; 미디어 타입(0xf0로 해야 함) DW 9 ; FAT영역 길이(9섹터로 해야 함) DW 18 ; 1트럭에 몇개의 섹터가 있을까(18로 해야 함) DW 2 ; 헤드의 수(2로 하지 않으면 갈 수 없다) DD 0 ; 파티션을 사용하지 않기 때문에 여기는 반드시 0 DD 2880 ; 드라이브 크기를 한번 더 write DB 0,0,0x29 ; 잘 모르지만 이 값으로 해 두면 좋은 것 같다 DD 0xffffffff ; 아마, 볼륨 시리얼 번호 DB "HELLO-OS " ; 디스크 이름(11바이트) DB "FAT12 " ; 포맷 이름(8바이트) RESB 18 ; 우선 18바이트를 비어 둔다 ; 프로그램 본체 entry: MOV AX, 0 ; 레지스터 초기화 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX MOV SI,msg putloop: MOV AL,[SI] ADD SI, 1 ; SI에 1을 더한다 CMP AL,0 JE fin MOV AH, 0x0e ; 한 글자 표시 function MOV BX, 15 ; 칼라 코드 INT 0x10 ; 비디오 BIOS 호출 JMP putloop fin: HLT ; 무엇인가 있을 때까지 CPU를 정지시킨다 JMP fin ; Endless Loop msg: DB 0x0a, 0x0a ; 개행을 2개 DB "hello, os!" DB 0x0a ; 개행 DB 0 RESB 0x7dfe-$ ; 0x7dfe까지를 0x00로 채우는 명령 DB 0x55, 0xaa
그리고 위 코드에 쓰인 새로운 명령어들
<이름 :> : 레이블, 메모리의 특정 주소를 가리킴
[] : 안의 값에 해당하는 메모리 주소안의 값
ORG(origin) : 로드할 메모리 주소 지정
JMP(jump) : 지정한 지점으로 점프, 주로 레이블과 같이 사용
MOV(move) : 대입문, 사용법은 [MOV 목적지, 소스]
ADD(add) : 덧셈, 목적지에 소스를 더한다
CMP(compare) : 비교, 둘을 비교한다
JE(jump if equal) : CMP에서 비교한 결과가 일치면 점프
HLT(halt) : 별 다른 일이 없음면 CPU를 쉬게 한다
INT(interupt) : BIOS의 기본 명령어들을 출력하는 명령어. 특정조건을 만족시키고 사용하면 다양한 기능을 실행할 수 있는 듯 하다. 필자가 작성했다는 메뉴얼이 사라진지라 검색으로 사본을 구해서 사용하였다...
재밌었던 파트는 INT 명령어. 문자하나를 출력하는 데 필요한 조건이
- AH = 0x0e;
- AL = 캐릭터 코드;
- BH = 컬러 코드;
- 리턴값: 없음
- 주: 힙, 백스페이스, CR, LP는 제어 코드로 인식된다.
이러하다. 위 코드의 putloop 블록을 보면 사용하는 모습을 볼 수 있다.
지금까지 이해한 부팅 프로세스를 적어보면,
- 전원 ON
- 디스크의 첫 섹터 읽어감
- 마지막 두 바이트가 55 AA임을 확인
- 첫 섹터를 메모리에 로드 (ORG 명령어로 인해 0x7c00에 로드 된다)
- 로드된 코드를 첫 줄 부터 실행 - 이하 코드 내용↓
- 엔트리 블록 실행(레지스터 초기화)
- putloop 블록 실행(문자 출력)
- fin 블록 실행(무한 대기)
처음엔 어셈블러의 기능이 파악되지 않아서 많이 헷갈렸었다...ㅠ
# 그리고 Makefile의 등장!
확실히 다수의 bat파일 대신 Makefile로 파일을 관리하니 매우 깔끔해진 폴더...
파일수는 얼마 차이 안나도 빌드 과정은 훨씬 깔끔해졌다!
Makefile의 문법은 다음과 같다.
명령어 : 의존파일1 의존파일2 ...
실행될 명령문
직접 파일을 만드는 명령어는 -r 옵션을 붙이는 듯 하다
# 디폴트 동작 default : ../z_tools/make.exe img # 파일 생성 규칙 ipl.bin : ipl.nas Makefile ../z_tools/nask.exe ipl.nas ipl.bin ipl.lst helloos.img : ipl.bin Makefile ../z_tools/edimg.exe imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img # 커맨드 asm : ../z_tools/make.exe -r ipl.bin img : ../z_tools/make.exe -r helloos.img run : ../z_tools/make.exe img copy helloos.img ..\z_tools\qemu\fdimage0.bin ../z_tools/make.exe -C ../z_tools/qemu install : ../z_tools/make.exe img ../z_tools/imgtol.com w a: helloos.img clean : -del ipl.bin -del ipl.lst src_only : ../z_tools/make.exe clean -del helloos.img
자동으로 갱신된 파일과 누락된 파일까지 관리하니 정말 편한 도구이다.
Make 로 빌드하는 현재 파일 생성과정은 이러하다.포토샵으로 할걸
edimg는 첫 섹터의 bin파일을 가지고 디스크 이미지를 만드는 필자의 프로그램이다.
# 이 밖에도 리틀엔디언이라던가, CPU와 램사이의 통신같은 하드웨어적 내용도 있었다.(궁금하면 직접 읽어보시라) 오늘은 부팅의 과정이 이해가 되면서 머리가 뻥 뚫린 기분이다. 이제 기분 좋게 잠들 수 있겠지...