yon11b

[SK 쉴더스 루키즈] EMU 8086 실습(신호등, 계산기) 본문

보안/SK 쉴더스 루키즈

[SK 쉴더스 루키즈] EMU 8086 실습(신호등, 계산기)

yon11b 2026. 5. 30. 03:52
반응형

EMU8086이란?

16비트 x86 환경

8086 CPU 에뮬레이터 + 어셈블리 개발 도구

8086 CPU를 가상으로 흉내 내서 어셈블리 코드를 실행해볼 수 있다.

 

구분 16비트 (8086 ) 32비트 (80386+)
범용 레지스터 AX, BX, CX, DX EAX, EBX, ECX, EDX
포인터 레지스터 SP, BP, SI, DI ESP, EBP, ESI, EDI
주소 크기 16비트 32비트
최대 메모리 1MB 4GB
실행 모드 Real Mode Protected Mode
시스템 호출 INT 21h Windows API, SYSENTER 등
어셈 문법 상대적으로 단순 확장된 명령어 다수

 

EMU8086: DOS(16비트) 인터럽트 호출 방식 사용

반면에, 32비트 Windows에서는 보통

CALL MessageBoxA
CALL CreateFileA
CALL ExitProcess

처럼 Windows API를 호출한다.

 

INT 21h 방식 (DOS 인터럽트 호출 방식)

DOS 운영체제에게 기능을 요청하는 방식

MOV AH, 기능번호
INT 21h

 

예제

 

입력: DOS야, 키보드 입력 1글자 받아줘.

MOV AH, 01h
INT 21h

 

출력: DOS야, DL에 있는 문자 출력해줘.

MOV DL, 'A'
MOV AH, 02h
INT 21h

 

신호등 예제

 

; controlling external device with 8086 microprocessor.
; realistic test for c:\emu8086\devices\Traffic_Lights.exe

#start=Traffic_Lights.exe#

name "traffic"

; 모든 신호등을 빨간불로 설정
mov ax, all_red
out 4, ax     ; AX 값을 IO포트 4번으로 보내는 명령어
              ; AX에 들어있는 신호등 상태값을 외부 장치로 출력
              

mov si, offset situation  ; si에 situation의 주소를 넣는다.
                          ; si는 현재 출력할 신호등 패턴을 가리키는 포인터 역할


next:
mov ax, [si]
out 4, ax

; 5초 대기 명령어
mov     cx, 4Ch    ; 004C4B40h = 5,000,000
mov     dx, 4B40h  ; 5초를 나타내려면 두 개의 레지스터에 나눠서 표현해야 함.
mov     ah, 86h
int     15h


; 반복문
add si, 2 ; next situation
cmp si, sit_end  ; 마지막까지 갔는지 비교
jb  next         ; 작으면 위(next)로 점프 / 같으면 밑으로 ㄱㄱ  
mov si, offset situation ;  situation 시작 주소로 si 포인터를 되돌림
jmp next                 ; 다시 처음부터 반복


;                        FEDC_BA98_7654_3210
situation        dw      0000_0011_0000_1100b
s1               dw      0000_0110_1001_1010b
s2               dw      0000_1000_0110_0001b
s3               dw      0000_1000_0110_0001b
s4               dw      0000_0100_1101_0011b
sit_end = $


all_red          equ     0000_0010_0100_1001b

 

신호등 색깔은 이런식으로 나타낸다.

 

구분 의미
INT 어떤 서비스를 호출할지 결정
AH 그 서비스 안에서 어떤 기능을 사용할지 결정

 

BIOS 인터럽트 기능
int 10h 화면 출력
int 13h 디스크 읽기/쓰기
int 15h 시스템 서비스(대기 등)
int 16h 키보드 입력

 

코드 의미
AH=86h 지정 시간만큼 대기
AH=88h 메모리 크기 조회
AH=C0h 시스템 정보 조회

 

흐름 해석

 

situation  반복문 돌릴 때 상황이다.

 

ADD SI, 02h

SI레지스터에 0025 저장

 

mov ax, [si]

si를 주소로 하는 값을 ax에 저장한다.

=>  그래서 메모리에서 0025주소를 찾아가봤더니 06 9A 라는 값이 있었다. (이 값을 ax에 저장)

 

out 4, ax

ax에 들어있는 값을 IO포트 4번으로 출력해라

이 값을 바이너리로 변환하면, s1의 situation (0000 0100 1001 1010)이 나온다.

 

시간 나타내는 부분 해석

원래 BIOS는 시간을

CX:DX

두 개의 레지스터를 붙여서 받는다.

그래서

mov cx, 4Ch
mov dx, 4B40h

를 하면

CX = 004C
DX = 4B40

이 되고,

BIOS는 이를

004C4B40h

라는 하나의 숫자로 본다.

 

 

계산기 만들기

목표: 한 자리 숫자 두 개의 덧셈·뺄셈을 수행하는 콘솔 계산기 작성
➢설명
▶사용자로부터 한 자리 숫자 두 개를 입력받는다.
▶연산자를 입력받아 덧셈(+) 또는 뺄셈(-) 중 하나를 선택한다.
▶입력값은 ASCII 코드이므로 '0'(30h) 을 빼서 실제 숫자로 변환
▶결과는 다시 '0' 을 더해 ASCII로 변환 후 출력

 

; You may customize this and other start-up templates; 
; The location of this template is c:\emu8086\inc\0_com_template.txt

org 100h       

; add your code here
; 첫번째 숫자 입력
MOV ah, 01h
INT 21h             ; 입력결과가 AL에 들어감
MOV bl, al

; 두번째 숫자 입력
MOV ah, 01h
INT 21h
MOV bh, al

; 연산자 입력
MOV ah, 01h
INT 21h
MOV ch, al


; calculate
SUB bl, 30h
SUB bh, 30h

; + 이면 add_cal 함수로 ㄱㄱ / 아니면 sub_cal로 ㄱㄱ
CMP ch, 2bh
JE add_cal
JNZ sub_cal

add_cal:
    ADD bl, bh
    JMP END
    
sub_cal:
    SUB bl, bh
    JMP END

END:    
    ADD bl, 30h  ; 출력할 때는 다시 30h 더해서.
    MOV dl, bl
    MOV ah, 02h
    INT 21h

ret

 

실행 결과

 

5 - 3 = 2 / 5+ 3 = 8

 

5 - 3 = 2 했을 때 상황이다.

BL에 0x32. 즉, 2가 들어있다.

CH에는 0x2D. 즉, - 이 들어있다.

좀 더 깔끔한 GPT 코드

더보기
org 100h

; 첫번째 숫자 입력
MOV ah, 01h
INT 21h
MOV bl, al

; 두번째 숫자 입력
MOV ah, 01h
INT 21h
MOV bh, al

; 연산자 입력
MOV ah, 01h
INT 21h
MOV ch, al

; 문자 숫자 -> 실제 숫자
SUB bl, 30h
SUB bh, 30h

; 연산자 비교
CMP ch, '+'
JE add_cal

CMP ch, '-'
JE sub_cal

JMP END

add_cal:
    ADD bl, bh
    JMP PRINT

sub_cal:
    SUB bl, bh
    JMP PRINT

PRINT:
    ADD bl, 30h
    MOV dl, bl
    MOV ah, 02h
    INT 21h

END:
ret
728x90