๐๐ป ์๋์ ์ฝ๋๋ ํ๋ฉด์ ‘X’๋์ ์ Hello miniOS!๋ฅผ ํ๋ฉด์ ์ถ๋ ฅํฉ๋๋ค.
The code below outputs “Hello miniOS!” to the screen instead of “X”.
๐๐ป boot.asm ์ ์ฒด ์ฝ๋ / full code
; BIOS๊ฐ ์ด ์ฝ๋๋ฅผ ๋ฉ๋ชจ๋ฆฌ 0x7C00์ ๋ก๋ํฉ๋๋ค.
; The BIOS loads this code into memory at 0x7C00.
[org 0x7c00]
; 16๋นํธ ๋ฆฌ์ผ ๋ชจ๋๋ก ์คํํฉ๋๋ค.
; Executes in 16-bit real mode.
bits 16
start:
; ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ ์ด๊ธฐํ
; Initialize data segment register
mov ax, 0
mov ds, ax
; ๋ฌธ์์ด์ ์์ ์ฃผ์๋ฅผ SI ๋ ์ง์คํฐ์ ์ ์ฅ
; Store the starting address of the string in the SI register
mov si, msg
; ๋ฌธ์์ด์ ํ ๊ธ์์ฉ ์ฝ์ด์ ์ถ๋ ฅํ๋ ๋ฃจํ
; A loop that reads and prints a string character by character
print_loop:
; SI๊ฐ ๊ฐ๋ฆฌํค๋ ์ฃผ์์์ 1๋ฐ์ดํธ๋ฅผ AL์ ๋ก๋ํ๊ณ SI๋ฅผ 1 ์ฆ๊ฐ์ํด
; Load 1 byte from the address pointed to by SI into AL and increment SI by 1
lodsb
; ๊ฐ์ ธ์จ ๋ฌธ์๊ฐ 0(๋ฌธ์์ด์ ๋)์ธ์ง ํ์ธ
; Check if the retrieved character is 0 (end of string)
cmp al, 0
; 0์ด๋ฉด ๋ฌดํ ๋ฃจํ๋ก ์ด๋ํ์ฌ ์ข
๋ฃ
; If 0, jump to the infinite loop and terminate.
je hang
; BIOS ํ
๋ ํ์ดํ ์ถ๋ ฅ ๊ธฐ๋ฅ ์ ํ
; Select BIOS teletype output function
mov ah, 0x0e
; BIOS ๋น๋์ค ์ธํฐ๋ฝํธ ํธ์ถํ์ฌ AL์ ๋ฌธ์ ์ถ๋ ฅ
; Call BIOS video interrupt to output the character in AL
int 0x10
; ๋ค์ ๊ธ์ ์ถ๋ ฅ์ ์ํด ๋ฃจํ ๋ฐ๋ณต
; Loop to print the next character
jmp print_loop
; ํ์ฌ ์์น($)์์ ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ฉฐ ๋๊ธฐํฉ๋๋ค.
; Waits in an infinite loop at the current location ($).
hang:
jmp $
; ์ถ๋ ฅํ ๋ฌธ์์ด ์ ์ (๋์ 0์ ๋ถ์ฌ ๋ฌธ์์ด์ ๋์ ํ์)
; Define the string to output (append 0 to mark the end of the string)
msg db 'Hello miniOS!', 0
; 512๋ฐ์ดํธ ์ค ๋น ๊ณต๊ฐ์ ๋ชจ๋ 0์ผ๋ก ์ฑ์๋๋ค.
; Fill all remaining space within the 512 bytes with zeros.
times 510 - ($ - $$) db 0
; ์ด ๋์คํฌ๊ฐ ๋ถํ
๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์๋ฆฌ๋ ๋ถํธ ์๊ทธ๋์ฒ ์ ์ฅ
; Store the boot signature indicating that this disk is bootable.
dw 0xaa55
# 1. ์ด์
๋ธ๋ฆฌ์ด ์ฝ๋๋ฅผ ์์ํ ๋ฐ์ด๋๋ฆฌ ํ์ผ(.bin)๋ก ์ปดํ์ผ
# Compile assembly code into a pure binary file (.bin)
nasm -f bin boot.asm -o boot.bin
# 2. QEMU ์๋ฎฌ๋ ์ดํฐ์ ์ด ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋์คํฌ๋ก ๋ฃ์ด ๊ฐ์ ์ปดํจํฐ ๋ถํ
# Put this binary on a disk and boot the virtual machine in the QEMU emulator
qemu-system-x86_64 -drive format=raw,file=boot.bin

๐๐ป ์ฝ๋์ค๋ช / Code description
โ๏ธ ๋ ์ง์คํฐ ax,ds๋ฅผ 0 ์ผ๋ก ์ด๊ธฐํํ๊ธฐ
Initialize registers ax and ds to 0.
mov ax, 0
mov ds, ax
— ๋ ์ง์คํฐ(Register)๋ ๋ณ์์ ๋น์ทํ์ง๋ง, CPU(์ปดํจํฐ์ ๋๋) ๋ด๋ถ์ ์กด์ฌํ๋ ‘์ด๊ณ ์ ๋ฏธ๋ ์ ์ฅ ๊ณต๊ฐ’์
๋๋ค.(RAM์ด ์๋)
A register is similar to a variable, but it is a “high-speed mini-storage space” located inside the CPU (the brain of the computer)โnot in RAM.
— ax์ ds๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
The reasons for initializing ax and ds to zero are as follows.
1) ds์ ์ฐ๋ ๊ธฐ ๊ฐ์ด ๋ค์ด ์์ ์ ์์ด์ 0์ผ๋ก ์ด๊ธฐํ ํฉ๋๋ค. ์ฐ๋ ๊ธฐ ๊ฐ์ด ์์ผ๋ฉด ์๋ชป๋ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.ds may contain garbage values, so it is initialized to zero; if garbage values โโare present, it would point to an invalid address.
2)์ฃผ์ ๊ณ์ฐ๊ณต์
Address calculation formula
์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ(ds)๊ฐ 0์ด๊ธฐ ๋๋ฌธ์ ๋ณ์์ ๋ฐ์ดํฐํฌ๊ธฐ๊ฐ ์ฃผ์์์น๊ฐ ๋ฉ๋๋ค.
Since the segment register (ds) is 0, the data size of the variable becomes the address location.
์ง์ง ์ฃผ์ = (์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ ร 16) + ๋ณ์์ ์์น(์คํ์
)
Actual address = (segment register ร 16) + variable location (offset)
— ์๋์ ๐๋ถ๋ถ์ ๋ณ์,๋ ์ง์คํฐ์ ๋ํ ๊ฐ๋
๋ฐ ์ฉ๋ ์ค๋ช
์
๋๋ค.
The section marked ๐ below explains the concepts and purposes of variables and registers.
๐ ๋ณ์์ ๋ ์ง์คํฐ์ ํต์ฌ ์ฐจ์ด์
Key differences between variables and registers
1)์ด์
๋ธ๋ฌ์์ ๋ ์ง์คํฐ์ ๋ฑ๋กํ๋๊ฑด ๋ณ์๋ฑ๋ก๊ณผ ์ ์ฌํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ์ฐจ์ด์ ์ด ์์ต๋๋ค.
Registering a register in an assembler is similar to declaring a variable, but there are the following differences.
| ๊ตฌ๋ถ (Category) | ๋ณ์ (Variable) | ๋ ์ง์คํฐ (Register) |
|---|---|---|
| ์์น / Location | ์ปดํจํฐ์ ๋ฉ๋ชจ๋ฆฌ(RAM) Computer memory (RAM) | CPU ๋ด๋ถ ํ๋์จ์ด Internal CPU hardware |
| ๊ฐ์ / Quantity | ๋ฉ๋ชจ๋ฆฌ ์ฉ๋์ด ํ์ฉํ๋ ํ ๋ฌดํ๋ Infinite as long as memory capacity allows | CPU ์ค๊ณ ์ ๊ณ ์ ๋จ (์์ญ ๊ฐ ๋ด์ธ) Fixed during CPU design (around a few dozen) |
| ์ด๋ฆ / Name | age, name ๋ฑ ๊ฐ๋ฐ์๊ฐ ๋ง์๋๋ก ์ง์Age, name, etc. are named arbitrarily by the developer | ax, bx, cx, ds ๋ฑ ์ด๋ฏธ ์ ํด์ ธ ์์ax, bx, cx, ds, etc., are already defined. |
| ์๋ / Speed | ๋น ๋ฆ / fast | ์ปดํจํฐ์์ ๊ฐ์ฅ ๋น ๋ฆ (๋ฉ๋ชจ๋ฆฌ๋ณด๋ค ์์ญ ๋ฐฐ) Fastest in the computer (dozens of times faster than memory) |
๐ ๋ ์ง์คํฐ์ ์ข
๋ฅ ๋ฐ ์ฉ๋
Types and Uses of Registers
1-1) ์ผ๋ฐ ๊ณ์ฐ์ฉ ๊ณต๊ฐ(๋ฒ์ฉ ๋ ์ง์คํฐ)
General-purpose calculation space (general-purpose registers)
AX (Accumulator - ๋์ฐ๊ธฐ/์ฐ์ฐ์ฉ)
AX (Accumulator - for accumulation/calculation)
-- ์ํ ์ฐ์ฐ(๋ํ๊ธฐ, ๊ณฑํ๊ธฐ)์ ์ค์ฌ์ด์, ์
์ถ๋ ฅ์ ๋๋ฆฌ์ธ์
๋๋ค.
It is the hub of mathematical operations (addition, multiplication) and the agent for input and output.
-- ์ ์ฝ๋์์ mov ah, 0x0e๋ฅผ ํ ๋ ์ฌ์ฉํ ah, al์ด ๋ฐ๋ก ์ด ax๋ฅผ ๋ฐ์ฉ ์ชผ๊ฐ์ ์ฐ๋ ์ด๋ฆ์
๋๋ค. BIOS ๊ธฐ๋ฅ์ ํธ์ถํ ๋ ๋ฒํธํ ์ญํ ์ ํฉ๋๋ค.
In the code above, the `ah` and `al` used with `mov ah, 0x0e` are the names for the two halves of the `ax` register; they serve as function identifiers when calling BIOS services.
BX (Base - ๊ธฐ์ค ์ฃผ์์ฉ)
BX (Base - for base address)
-- ๋ฉ๋ชจ๋ฆฌ์ ํน์ ์ฃผ์(์์น)๋ฅผ ๊ฐ๋ฆฌํค๋ ๋์นจ๋ฐ ์ญํ ์ ์์ฃผ ํฉ๋๋ค.
It often acts as a compass pointing to a specific memory address (or location).
CX (Counter - ๋ฐ๋ณต ํ์์ฉ)
CX (Counter - for repetition count)
-- or๋ฌธ ๊ฐ์ ๋ฐ๋ณต๋ฌธ(Loop)์ด ๋ช ๋ฒ ๋์๋์ง ์ธ๋ ๊ณ์๊ธฐ์
๋๋ค. ๋ฃจํ ๋ช
๋ น์ด๋ฅผ ์ฐ๋ฉด CPU๊ฐ ์๋์ผ๋ก cx ๊ฐ์ 1์ฉ ๊น์ผ๋ฉด์ 0์ด ๋ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค.
It is a counter that tracks the number of iterations for loops, such as the `loop` instruction. When the `loop` instruction is used, the CPU automatically decrements the `CX` register by 1 in each iteration until it reaches zero.
DX (Data - ๋ฐ์ดํฐ ํ์ฅ์ฉ)
DX (Data - for data expansion)
-- ax๋ง์ผ๋ก ๋ด๊ธฐ ํ๋ ๋๋ฌด ํฐ ์ซ์๋ฅผ ๊ณฑํ๊ฑฐ๋ ๋๋ ๋ ์๋ธ ์ฃผ๋จธ๋๋ก ๋๊ฑฐ๋, ํ๋์จ์ด ์ฅ์น์ ์ํตํ ๋ ์๋๋ค.
It is used to assist with multiplication or division involving numbers too large to fit into the `ax` register aloneโacting as a secondary storageโor when communicating with hardware devices.
1-2) ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์ญ ๊ด๋ฆฌ์ฉ ๊ณต๊ฐ (์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ)
Space for memory area management (segment registers)
DS๋ ์ ๊ตฌ์ญ๋ค๊ณผ ์ข
๋ฅ๊ฐ ์์ ๋ค๋ฅธ ์ธ๊ทธ๋จผํธ(Segment) ๋ ์ง์คํฐ์
๋๋ค. 16๋นํธ ์ปดํจํฐ๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋๋ฌด ๋์ด์, ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ๋ฌ ๊ตฌ์ญ์ผ๋ก ๋๋์ด ๊ด๋ฆฌํฉ๋๋ค.
The DS is a segment register that belongs to a completely different category than the aforementioned areas. Because the memory space in 16-bit computers is so vast, memory is managed by dividing it into multiple sections.
DS (Data Segment) - ๋ฐ์ดํฐ๋ฅผ ์ฐพ๊ธฐ์ํ ์ธ๋ฑ์ค์คํฐ์ปค / Index stickers for locating data
-- "์ง๊ธ๋ถํฐ ์ฌ์ฉํ๋ ๋ณ์๋ ๋ฌธ์์ด ๊ฐ์ ๋ฐ์ดํฐ๋ ๋ชจ๋ ์ด ์ฌ๊ธฐ์์ ์ฐพ์ผ๋ผ"๊ณ ๊ธฐ์ค์ ์ ์ก๋ ์ญํ ์ ํฉ๋๋ค.
It serves as a reference point, indicating, "Look here for any dataโsuch as variables or stringsโthat will be used from this point forward."
-- mov ds, ax๋ก ๋ฐ์ดํฐ ๋๋ค ๊ธฐ์ค์ ์ 0์ผ๋ก ์ก์๊ธฐ ๋๋ฌธ์, CPU๊ฐ msg ๋ฌธ์์ด์ ์ ํํ ์์น๋ฅผ ์ฐพ์๋ผ ์ ์์๋ ๊ฒ์
๋๋ค.
By setting the data segment base address to 0 with the instruction `mov ds, ax`, the CPU was able to locate the exact position of the `msg` string.
CS (Code Segment):
๋ด๊ฐ ์คํํ ์ง์ง ๋ช
๋ น์ด(์ฝ๋)๋ค์ด ๋ชจ์ฌ ์๋ ์ฃผ์์
๋๋ค.
This is the address where the actual commands (code) I am to execute are located.
SS (Stack Segment):
ํจ์๋ฅผ ํธ์ถํ๊ฑฐ๋ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ ์์๋๋ '์คํ'์ด๋ผ๋ ์์ ์ ์ฅ ๊ณต๊ฐ์ ์ฃผ์์
๋๋ค.
It is the address of a temporary storage space called the "stack," used for calling functions or briefly storing temporary data.
โ๏ธ ์ถ๋ ฅํ ๋ฌธ์์ด 'Hello miniOS!', 0์ด ์ ์ฅ๋ ๋ฉ๋ชจ๋ฆฌ์ ์์ ์ฃผ์๋ฅผ SI ๋ ์ง์คํฐ์ ๋ฃ์ต๋๋ค.
Load the starting address of the memory containing the string ‘Hello miniOS!’ and the value 0 into the SI register.
mov si, msg
— msg๋ ์ฝ๋ ์๋ถ๋ถ์์ ์ด๊ธฐํ ํ๋ถ๋ถ์ด ์์ง๋ง ์๋์ ‘msg db ‘Hello miniOS!’, 0’์ด ์ฝ๋๋ฅผ ๋ณด๊ณ si ๋ ์ง์คํฐ์ ์๋์ผ๋ก ์ฃผ์๋ฅผ ๋ฑ๋กํฉ๋๋ค.
Although msg is not explicitly initialized in the upper section of the code, the address is automatically registered in the SI register based on the line msg db 'Hello miniOS!', 0 found further down.
— si ๋ ์ง์คํฐ๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ฐ๋ก ์๋์ lodsb(Load String Byte) ์ฝ๋ ๋๋ฌธ์
๋๋ค.
The reason the SI register is used is because of the lodsb (Load String Byte) instruction immediately following it.
— lodsb(Load String Byte) ๋ช
๋ น์ด๋ CPU ๋ด๋ถ์ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ๋ก ์ฝ์์ด ๋์ด ์์ต๋๋ค.
The lodsb (Load String Byte) instruction is hard-wired within the CPU to operate according to the following conventions:
"lodsb ๋ช
๋ น์ด๊ฐ ์คํ๋๋ฉด, CPU๋ ๋ฌด์กฐ๊ฑด si ๋ ์ง์คํฐ๊ฐ ๊ฐ๋ฆฌํค๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ก ์ฐพ์๊ฐ์ 1๋ฐ์ดํธ๋ฅผ ์ฝ์ด AL ๋ ์ง์คํฐ์ ๋ฃ๋๋ค."
When the `lodsb` instruction is executed, the CPU unconditionally accesses the memory address pointed to by the `SI` register, reads one byte, and loads it into the `AL` register.
— ๊ทธ๋์ lodsb์ si๋ ์ง์คํฐ๋ ๊ฐ์ด ์ฌ์ฉํฉ๋๋ค.
Therefore, the lodsb instruction and the si register are used together.
— ์ด์
๋ธ๋ฌ์์๋ ์ปดํ์ผ๋๊ธฐ์ ์ปดํ์ผ๋ฌ๊ฐ ์ ์ฒด ์ฝ๋๋ฅผ ๋ชจ๋ ์ดํด๋ณด๊ณ ๊ณ์ฐํ ํ ์ปดํ์ผ๋ฉ๋๋ค.
In the case of an assembler, the compiler examines and calculates the entire code before the actual compilation takes place.
โ๏ธ ํ
๋ ํ์ดํ ๋ชจ๋(ํ๊ธ์ ์ถ๋ ฅ ๊ธฐ๋ฅ)
Teletype mode (character-by-character output function)
— ํ๋ฉด์ ํ์๊ธฐ์ฒ๋ผ ์ถ๋ ฅํ๋ผ๋ ๋ช
๋ น์
๋๋ค.
This is a command to output text to the screen like a typewriter.
— ํ
๋ ํ์ดํ ๋ชจ๋๋ฅผ ์ ํํ๋ฉด ์ปค์ ์๋์ด๋ ์๋์ค๋ฐ๊ฟ ๊ธฐ๋ฅ์ ์ง์ํฉ๋๋ค.
Selecting Teletype mode enables automatic cursor movement and automatic line wrapping.
— al ๋ ์ง์คํฐ ๋ด์ ๋ฌธ์ ์ถ๋ ฅ ๊ธฐ๋ฅ์ธ int 0x10์ ๊ฐ์ด ์ฌ์ฉํฉ๋๋ค.
It is used in conjunction with int 0x10, a function for outputting characters via the al register.
mov ah, 0x0e
โ๏ธ ๋ฌดํ๋ฃจํ ์ด์ ๋ฐ๋ณต๋ฌธ์์ msg db ‘Hello miniOS!’, 0์ด ๋ฐ์ดํฐ ๋ถ๋ถ์ ๋ชจ๋ ์ฐธ์กฐํ๊ณ ๋ฌดํ๋ฃจํ๋ก ๋๊ธฐ ํฉ๋๋ค.
In the loop preceding the infinite loop, msg db 'Hello miniOS!', 0 references the entire data section, and the program then waits within the infinite loop.
jmp $
โ๏ธ ๋ฉ๋ชจ๋ฆฌ msg์ Hello miniOS!0 ๊ฐ์ ์
๋ ฅํฉ๋๋ค.
Enter the value “Hello miniOS!0” into the memory location msg.
— 0์ ๋ฌธ์์ด์ ๋์์ ํ์ธํ๊ธฐ ์ํด์ ์
๋๋ค.
It is to verify that 0 marks the end of the string.
— ๋ณ์์ ํ์
์ด ์๋ ์ด์ ๋ ๋ชจ๋ ascii๊ฐ์ผ๋ก ์ ์ฅ๋๊ธฐ ๋๋ฌธ์
๋๋ค.
The reason variables do not have types is that they are all stored as ASCII values.
msg db 'Hello miniOS!', 0
โ๏ธ ์ฌ์ฉํ์ง ์๋ ๋๋จธ์ง ๊ณต๊ฐ์ ๋ชจ๋ 0์ผ๋ก ์ฑ์๋๋ค.
Fill all remaining unused space with zeros.
— times๋ ๋ณ์๊ฐ ์๋๋ผ ๋ฐ๋ณต๋ช
๋ น์ง์์ด ์
๋๋ค.
‘times’ is not a variable; it is a command for repetition.
times 510 - ($ - $$) db 0
โ๏ธ ๋ถํ
๊ฐ๋ฅํจ์ ์ง์ํ๋ ์ฝ๋์
๋๋ค.
This is the code that indicates bootability.
dw 0xaa55
๐ ๊ฒฐ๋ก / conclusion
โ๏ธ16๋นํธ ์ปดํจํฐ์์ ํ๋ฉด์ ๊ธ์๋ฅผ ํ์ํ๊ธฐ ์ํด์๋ msg๋ณ์์ ๋ฌธ์๋ฅผ ์
๋ ฅํด๋๊ณ ํ๊ธ์์ฉ al๋ ์ง์คํฐ์์ ๊ฐ์ ธ์์ ํ๋ฉด์ ์ถ๋ ฅํฉ๋๋ค.
To display characters on the screen of a 16-bit computer, the characters are stored in the msg variable, then retrieved one by one from the AL register and output to the screen.
โ๏ธ al๋ ์ง์คํฐ์์ ํ๊ธ์์ฉ ๋ฌธ์๋ฅผ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ์ ๋ฐ๋ณตํ๊ธฐ ์ํด์ si ๋ ์ง์คํฐ์ lodsb๋ฅผ ์ฌ์ฉํฉ๋๋ค.
To repeatedly fetch characters one by one from the register, the SI register and the lodsb instruction are used.