2025-1 컴퓨터구조 (Assembly Language and machine code 2)

JayainHUFS·2025년 4월 23일
post-thumbnail

  • 아래의 포스팅은 한국외국어대학교 컴퓨터공학부 Mohsen Ali Alawami 교수님의 [컴퓨터구조] 강의를 기반으로 작성했습니다.
  • 또한, 상업적 의도는 전무하며, 단순 학습 용도의 교재 자료를 첨부함을 알립니다.

"Mov" instruction (Cont.)


mov Instruction Variants - 접미어에 따른 데이터 크기 지정

mov 명령어는 데이터 크기를 명확히 하기 위해 접미어(suffix)를 가질 수 있음

b: byte (1바이트, 8비트)
w: word (2바이트, 16비트)
l: long (4바이트, 32비트)
q: quadword (8바이트, 64비트)

즉, mov는 상황에 따라 movb, movw, movl, movq로 번역됨.

이는 operand size (피연산자의 크기) 에 따라 결정되며,
CPU가 메모리로부터 가져오거나 쓰는 데이터의 크기를 명시함.

movb $0x01, %al         ; 1바이트 값을 AL 레지스터에 저장
movw $0x1234, %ax       ; 2바이트 값을 AX 레지스터에 저장
movl $0x12345678, %eax  ; 4바이트 값을 EAX 레지스터에 저장
movq $0x123456789ABCDEF0, %rax ; 8바이트 값을 RAX 레지스터에 저장

핵심 개념 정리

접미어명령어 형태의미데이터 크기
bmovbMove Byte8비트 (1 byte)
wmovwMove Word16비트 (2 bytes)
lmovlMove Long32비트 (4 bytes)
qmovqMove Quadword64비트 (8 bytes)

포인트
mov 명령어는 데이터 크기 명시가 중요하며, 이는 CPU의 레지스터 구조와 메모리 접근 방식과 직결됨.

데이터 버스의 폭(예: 64비트 시스템)과도 관련이 있음.


Arithmetic and logical operations in Assembly


Arithmetic and Logic instructions

아래 명령어들은 모두 2개의 피연산자(src, dst) 를 사용하며, 연산 결과는 항상 dst에 저장됨

명령어 형식

op src, dst   ; dst ← dst op src

rc: 레지스터, 메모리, 즉시값 가능
dst: 레지스터 또는 메모리 (단, 둘 다 메모리는 불가)

핵심 개념 정리

InstructionEffectDescription
addD ← D + S더하기
subD ← D - S빼기
imulD ← D × S곱하기
xorD ← D ^ SXOR (비트 반전)
orD ← D | SOR (논리합)
andD ← D & SAND (논리곱)

예시 코드 해설

addq %rcx, (%rax)      ; %rcx + 메모리[%rax] → 메모리[%rax]
subq %rdx, 8(%rax)     ; 메모리[%rax+8] ← 메모리[%rax+8] - %rdx
xorq $16, 8(%rdx)      ; 메모리[%rdx+8] ← 메모리[%rdx+8] ^ 16
andl $12, (%rcx)       ; 메모리[%rcx] ← 메모리[%rcx] & 12

Control Follow and loops


Intro: Control Flow Instructions

셈블리 명령어는 레지스터와 메모리 사이의 값 전송을 수행함
이 명령어들 자체도 메모리에 저장되어 실행됨

핵심 학습 내용
루프(while, for)나 흐름 제어(if-else 등)의 구현 방식 이해
조건 비교 결과는 조건 코드(Condition Codes) 로 저장됨


Unconditional Jump Instruction

jmp 0x404f8       ; Direct jump - 0x404f8 주소로 이동
jmp *%rax         ; Indirect jump - %rax에 저장된 주소로 이동

jmp [target]: 조건 없는 점프 수행

두 가지 형태 존재:
jmp Label: Direct Jump → 고정 주소로 이동
jmp *Operand: Indirect Jump → 레지스터/메모리에 저장된 주소로 이동

구분설명
Direct Jump코드에 하드코딩된 주소로 이동 (jmp 0x404f8)
Indirect Jump주소가 저장된 레지스터나 메모리로 이동 (jmp *%rax)

Conditional Jump Instruction

(1) Conditional Jump 개요

설명
조건문 (if, else, while, for 등)은 조건에 따라 흐름이 달라지는 제어문

어셈블리에서는 조건부 점프 명령어로 구현

cmp 명령어로 두 값을 비교하고, 조건부 점프(je, jne, jg 등)를 통해 흐름 분기

(2) Conditional Jump 명령어 패턴

cmp S1, S2  ; S2 - S1 수행
j[조건] target

예시
je target → equal (ZF = 1)
jne target → not equal (ZF = 0)
jg target → greater
jge target → greater or equal
jl target → less
jle target → less or equal

조건별 명령어 정리

Instruction의미조건 (Set Condition)
jeequal (==)ZF = 1
jnenot equal (!=)ZF = 0
jggreater (>)ZF = 0 and SF = OF
jgegreater or equal (>=)ZF = 1 or SF = OF
jlless (<)SF ≠ OF
jleless or equal (<=)ZF = 1 or SF ≠ OF

(3) Condition Code와 비교 로직

설명
cmp S1, S2는 S2 - S1 연산을 수행하고 결과는 CPU 내부 condition code register에 저장됨
condition code들은 jump 명령어의 판단 기준으로 활용됨

대표적인 flag 종류
ZF (Zero Flag): 연산 결과가 0
CF (Carry Flag): 자리 올림 발생 여부
SF (Sign Flag): 결과가 음수인지
OF (Overflow Flag): 부호가 뒤틀린 오버플로우 발생 여부

조건 플래그

Flag의미설명
ZFZero Flag연산 결과가 0일 때 1로 설정
CFCarry Flag자리 올림(carry) 발생 시 1로 설정
SFSign Flag연산 결과가 음수일 경우 1로 설정
OFOverflow Flag부호 있는 연산에서 오버플로우 발생 시 1로 설정

Common If-Else Construction

(1) 단순 조건 분기 if-else (arg > 3)

c코드

int test(int arg) {
    int num;
    if (arg > 3) {
        num = 10;
    } else {
        num = 0;
    }
    num++;
    return num;
}

어셈블리어

cmp $0x3, %edi        ; arg와 3 비교
jle <else>            ; arg ≤ 3이면 else 블록으로 점프
mov $0xa, %eax        ; num = 10
jmp <end>
<else>:
mov $0x0, %eax        ; num = 0
<end>:
add $0x1, %eax        ; num++
retq

설명
%edi에 arg가 들어있고, %eax가 num을 저장하는 역할.

조건 분기 후 각각의 분기에서 값을 넣고, 마지막에 num++ 수행 후 반환.

(2) 조건 계산이 포함된 if-else (x < y, 절댓값 계산)

c코드

long absdiff(long x, long y) {
    long result;
    if (x < y) {
        result = y - x;
    } else {
        result = x - y;
    }
    return result;
}

어셈블리어

cmp %rsi, %rdi        ; x와 y 비교
jge <else>            ; x ≥ y -> else로 점프
mov %rsi, %rax        ; rax = y
sub %rdi, %rax        ; rax = y - x
retq
<else>:
mov %rdi, %rax        ; rax = x
sub %rsi, %rax        ; rax = x - y
retq

설명
%rdi에 x, %rsi에 y 전달.
cmp와 jge 조합으로 if 조건 처리.
최종 계산 결과는 rax 레지스터에 저장되어 return됨.


Common While and For Loops Construction

(1) while 문

(2) for 문

sum_array:
    mov     $0x0, %eax              ; i = 0
    mov     $0x0, %edx              ; sum = 0
.loop:
    cmp     %esi, %eax              ; if (i >= nelems) → %esi는 nelems
    jge     .end_loop               ; 조건 만족 시 종료

    movslq  %eax, %rcx              ; rcx = (long)i
    add     (%rdi,%rcx,4), %edx     ; sum += arr[i] → %rdi는 arr 주소
    add     $0x1, %eax              ; i++

    jmp     .loop                   ; 다시 루프 시작
.end_loop:
    mov     %edx, %eax              ; return sum
    ret

흐름 설명
(1) 초기화
%eax ← i = 0
%edx ← sum = 0

(2) 루프 조건 검사
cmp %esi, %eax : nelems와 i를 비교 (즉, i - nelems)
jge : i >= nelems이면 .end_loop로 점프

(3) 본문 실행
movslq : i를 64비트로 확장하여 배열 인덱싱 가능하게 함
add : sum += arr[i], 즉 메모리에서 값 읽어와 %edx에 누적
add : i 증가 (i++)

(4) 루프 반복
jmp .loop : 조건 검사로 되돌아감

(5)종료 및 반환
mov %edx, %eax : 결과(sum)를 리턴값으로 이동
ret : 함수 종료


큰일난 것 같다...

profile
"REAL" 밑바닥부터 시작하는 데이터분석

0개의 댓글