OS 개발일지

[OS개발] 2일차 - 어셈블러랑 말문이 트였다.

RaiKuma 2015. 10. 29. 01:01

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 블록을 보면 사용하는 모습을 볼 수 있다.


지금까지 이해한 부팅 프로세스를 적어보면,

  1. 전원 ON
  2. 디스크의 첫 섹터 읽어감
  3. 마지막 두 바이트가 55 AA임을 확인
  4. 첫 섹터를 메모리에 로드 (ORG 명령어로 인해 0x7c00에 로드 된다)
  5. 로드된 코드를 첫 줄 부터 실행 - 이하 코드 내용↓
  6. 엔트리 블록 실행(레지스터 초기화)
  7. putloop 블록 실행(문자 출력)
  8. 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와 램사이의 통신같은 하드웨어적 내용도 있었다.(궁금하면 직접 읽어보시라) 오늘은 부팅의 과정이 이해가 되면서 머리가 뻥 뚫린 기분이다. 이제 기분 좋게 잠들 수 있겠지...