x86 어셈블리 언어 프로그래밍 핵심 가이드

컴퓨터 하드웨어와 기본 구조

컴퓨터는 중앙처리장치(CPU), 메모리, 버스 시스템으로 구성됩니다. 모든 명령어와 데이터는 메모리나 저장장치에 이진수 형태로 저장됩니다. 8086 프로세서는 20비트 주소버스를 통해 1MB(2^20)의 메모리 공간에 접근할 수 있습니다.

저장장치 주소 체계

메모리는 일련의 저장 단위로 구성되며, 각 단위는 고유한 물리적 주소를 가집니다. 주소버스의 폭은 접근 가능한 메모리 범위를 결정하며, 데이터버스는 CPU와 메모리 간 데이터 전송 속도를 결정합니다.

레지스터 체계

8086 CPU는 14개의 레지스터를 제공합니다. 범용 레지스터인 AX, BX, CX, DX는 각각 16비트이며, 상위 8비트와 하위 8비트로 분할 사용할 수 있습니다.

; 레지스터 사용 예제
mov 누산기, 0x1234  ; AX 레지스터에 즉시값 저장
mov 기준, 누산기     ; BX 레지스터에 AX 값 복사
add 누산기, 기준     ; AX = AX + BX

세그먼트 레지스터

CS(코드세그먼트), DS(데이터세그먼트), SS(스택세그먼트), ES(추가세그먼트)는 메모리 세그먼트의 기준 주소를 저장합니다. 물리적 주소는 '세그먼트주소 × 16 + 오프셋' 공식으로 계산됩니다.

기본 명령어 집합

데이터 전송 명령어

; MOV 명령어 활용
mov 기준, 0x1000      ; BX에 세그먼트 주소 로드
mov 세그먼트레지스터, 기준 ; DS에 세그먼트 주소 설정
mov 누산기, [0]       ; DS:0 주소의 데이터를 AX로 로드
mov [0], 데이터레지스터 ; DX 값을 DS:0 주소에 저장

산술 연산 명령어

; ADD 명령어 활용
add 누산기, 0x10      ; AX에 16 추가
add 기준, 누산기      ; BX = BX + AX

메모리 접근 기법

직접 주소 지정 방식

대괄호 표기법을 사용하여 메모리 주소를 지정합니다. [오프셋] 형태로 사용하며, 세그먼트 주소는 DS 레지스터가 기본적으로 제공합니다.

레지스터 간접 주소 지정

; BX를 주소 포인터로 사용
mov 기준, 0x0200      ; 오프셋 주소 설정
mov 누산기, [기준]    ; DS:BX 주소의 데이터 로드

변위 주소 지정 방식

; 상대 주소 계산
mov 누산기, [기준+0x10]   ; BX+16 오프셋 주소 접근
mov 누산기, [기준+시작인덱스+0x20] ; 복합 변위 주소

스택 메커니즘

8086 CPU는 PUSH와 POP 명령어를 통해 스택 구조를 지원합니다. SS:SP 레지스터 쌍이 스택 최상위 주소를 가리킵니다.

; 스택 초기화 및 사용
mov 기준, 0x1000
mov 스택세그먼트, 기준
mov 스택포인터, 0x0020  ; 스택 탑 설정

push 누산기            ; AX 값을 스택에 푸시
pop 데이터레지스터      ; 스택에서 DX로 팝

디버그 도구 활용

기본 명령어

  • R: 레지스터 내용 조회 및 수정
  • D: 메모리 덤프 (예: D 0x1000:0)
  • E: 메모리 직접 수정 (예: E 0x1000:0 0x12 0x34)
  • U: 기계어를 어셈블리어로 디스어셈블
  • A: 어셈블리어로 메모리에 명령어 작성
  • T: 단일 명령어 실행
  • G: 지정 주소까지 실행
  • P: 프로시저 스킵 실행

어셈블리 프로그램 구조

세그먼트 정의

코드영역 segment
    assume cs:코드영역, ds:데이터영역, ss:스택영역
    
시작점:
    ; 데이터 세그먼트 초기화
    mov 누산기, 데이터영역
    mov 데이터세그먼트, 누산기
    
    ; 주 프로그램 로직
    mov 카운터, 5
루프레이블:
    ; 반복 처리 코드
    loop 루프레이블
    
    ; 프로그램 종료
    mov 누산기, 0x4C00
    int 0x21
코드영역 ends
end 시작점

가명(pseudo) 지시어

  • db: 바이트 단위 데이터 정의
  • dw: 워드(2바이트) 단위 데이터 정의
  • dd: 더블워드(4바이트) 데이터 정의
  • dup: 데이터 반복 정의 (예: db 5 dup(0))

루프 제어 구조

LOOP 명령어는 CX 레지스터와 결합하여 반복문을 구현합니다. CX 값이 0이 될 때까지 지정된 레이블로 점프합니다.

; 1부터 10까지 합계 계산
mov 누산기, 0
mov 카운터, 10
mov 기준, 1

합계루프:
    add 누산기, 기준
    inc 기준
    loop 합계루프
; 결과: AX = 55

고급 주소 지정 모드

SI/DI 변址 레지스터 활용

; 문자열 복사 예제
mov 원본인덱스, 0          ; SI
mov 목적인덱스, 16         ; DI
mov 카운터, 8

복사루프:
    mov 누산기, [기준+원본인덱스]
    mov [기준+목적인덱스], 누산기
    add 원본인덱스, 2
    add 목적인덱스, 2
    loop 복사루프

기저-변址 복합 주소

; 복합 주소 계산
mov 누산기, [기준+원본인덱스+0x10] ; BX+SI+상수

산술 연산 고급 명령어

곱셈과 나눗셈

; MUL 명령어 (무기호 곱셈)
mov 알레지스터, 100
mov 블레지스터, 50
mul 블레지스터          ; AX = AL × BL

; DIV 명령어 (무기호 나눗셈)
mov 누산기, 1000
mov 블레지스터, 10
div 블레지스터          ; AL = AX ÷ BL(몫), AH = 나머지

ADC/SBB 명령어

여러 정밀도 연산을 위한 명령어로, 이전 연산의 캐리/빌로우 플래그를 포함합니다.

; 32비트 덧셈
mov 누산기, 0x1234
mov 데이터레지스터, 0x5678
add 기준, 0x9ABC
adc 누산기, 0x0DEF      ; 상위 워드에 캐리 포함

플래그 레지스터와 조건부 실행

주요 플래그 비트

  • ZF: 연산 결과가 0이면 설정
  • CF: 캐리/빌로우 발생 시 설정 (무기호 연산)
  • OF: 오버플로우 발생 시 설정 (기호 연산)
  • SF: 연산 결과 부호 비트
  • PF: 결과의 짝수 패리티
  • DF: 문자열 방향 제어

조건부 점프 명령어

; JZ/JNZ (Zero Flag)
cmp 누산기, 0
je  같을때실행      ; ZF=1 시 점프

; JC/JNC (Carry Flag)
cmp 기준, 0xFFFF
jb  작을때실행      ; CF=1 시 점프 (아래)

서브루틴 설계

CALL/RET 메커니즘

; 서브루틴 호출 예제
main:
    mov 매개변수, 5
    call 팩토리얼계산
    ; 결과는 누산기에 반환
    
팩토리얼계산:
    push 기준          ; 레지스터 보존
    mov 기준, 매개변수
    mov 카운터, 기준
    dec 카운터
    mov 누산기, 기준
    
계산루프:
    mul 카운터
    loop 계산루프
    
    pop 기준           ; 레지스터 복원
    ret                ; 호출 지점으로 복귀

매개변수 전달 방식

  1. 레지스터 방식: 값을 레지스터에 직접 로드
  2. 메모리 방식: 데이터 영역에 매개변수 배치
  3. 스택 방식: PUSH로 스택에 전달

문자열 및 화면 처리

문자 변환 테이블

; 16진수를 ASCII로 변환
변환테이블 db '0123456789ABCDEF'

mov 기준, 변환테이블
mov 알레지스터, 0x0A        ; 변환할 값
mov 원본인덱스, 알레지스터
mov 누산기, [기준+원본인덱스] ; 'A' 문자 획득

비디오 메모리 조작

텍스트 모드에서 0xB800:0000 주소가 화면 버퍼입니다. 문자와 속성 바이트를交替로 작성합니다.

; 화면 중앙에 문자 출력
mov 누산기, 0xB800
mov 엑스트라세그먼트, 누산기
mov 목적인덱스, (80*12 + 40) * 2  ; 화면 중앙 오프셋

mov 알레지스터, 'A'
mov 엑스트라세그먼트:[목적인덱스], 알레지스터
mov 알레지스터, 0x07              ; 흰색 속성
mov 엑스트라세그먼트:[목적인덱스+1], 알레지스터

인터럽트 처리

BIOS/DOS 인터럽트

; 프로그램 종료
mov 누산기, 0x4C00
int 0x21              ; DOS 21h 인터럽트

; 화면 클리어 (BIOS)
mov 누산기, 0x0600    ; 스크롤 윈도우 기능
mov 카운터, 0x07      ; 속성
mov 데이터레지스터, 0x184F ; 화면 크기
int 0x10              ; BIOS 10h 인터럽트

고급 기법

시프트 연산

; 논리 시프트
mov 알레지스터, 0b10010000
shr 알레지스터, 1     ; 0b01001000, CF=0

; 회전 시프트
mov 알레지스터, 0b10010001
ror 알레지스터, 1     ; 0b11001000, CF=1

구조화된 프로그래밍

코드, 데이터, 스택을 분리된 세그먼트로 정의하여 모듈화된 프로그램을 작성합니다.

데이터영역 segment
    배열 dw 1, 2, 3, 4, 5
    결과 dd 0
데이터영역 ends

스택영역 segment stack
    db 64 dup(0)
스택영역 ends

코드영역 segment
    assume cs:코드영역, ds:데이터영역, ss:스택영역
    
시작점:
    ; 초기화 및 메인 로직
    mov 누산기, 0x4C00
    int 0x21
코드영역 ends
end 시작점

최적화 및 디버깅 팁

  1. 레지스터 할당을 효율적으로 계획하여 메모리 접근 최소화
  2. 루프에서 불필요한 명령어 제거
  3. 플래그를 활용한 조건부 실행으로 분기 예측 개선
  4. Debug의 T/P/G 명령어로 단계별 실행 및 브레이크포인트 설정
  5. INT 3 소프트 브레이크포인트 활용

어셈블리 언어는 하드웨어에 직접 접근하는 강력한 도구이며, 레지스터와 메모리를 직접 제어함으로써 최고의 성능을 추구할 수 있습니다. 위 가이드를 통해 기본 개념부터 고급 기법까지 단계적으로 학습할 수 있습니다.

태그: 어셈블리 x86 레지스터 메모리주소 디버그

9월 25일 18:03에 게시됨