혼공컴운_CH3_명령어

Today Jeeho Learned·2025년 10월 15일

📘 소스 코드와 명령어

핵심 문장: 컴퓨터는 명령어를 처리하는 기계
사람이 작성한 소스 코드는 실행 전에 저급언어(기계가 이해하는 형식) 로 변환되어야 합니다.


1) 고급 언어와 저급 언어

Q. 컴퓨터는 C/C++/Java/Python 같은 언어를 직접 이해할까?

  • 고급언어(High-Level Language): 사람이 읽고 쓰기 쉽게 설계된 언어
    예) C, C++, Java, Python, Rust, Go
  • 저급언어(Low-Level Language): 컴퓨터가 직접 이해·실행할 수 있는 언어
    • 기계어(Machine Code): 0과 1의 이진 비트로 표현된 명령어
    • 어셈블리어(Assembly Language): 기계어를 기호/약어로 사람이 읽기 좋게 표시한 언어
      어셈블러(Assembler) 로 기계어로 변환
구분설명예시
기계어CPU가 직접 해석·실행하는 이진 코드10110000 00000101
어셈블리어기계어의 기호화 표현(조금 더 읽기 쉬움)MOV AL, 5

왜 저급언어를 알아야 하나?

  • 성능/메모리/타이밍 제약 상황에서 정확한 제어가 필요
  • 디버깅(레지스터/스택/덤프 분석), 임베디드, 드라이버 등 저수준 개발
  • 컴파일러가 생성하는 코드의 원리/한계 이해 → 더 나은 고급 코드 작성

2) 고급언어가 실행 파일이 되기까지

일반적인 빌드 파이프라인(언어/툴체인에 따라 일부 상이):

  1. 전처리(Preprocess): 매크로/#include 처리(C/C++)
  2. 컴파일(Compile): 고급언어 → 중간표현(IR) → 어셈블리
  3. 어셈블(Assemble): 어셈블리 → 오브젝트 파일(.o/.obj)
  4. 링크(Link): 여러 오브젝트 + 라이브러리 → 실행 파일/라이브러리
  5. 로딩(Load): OS 로더가 메모리에 적재, 진입점(entry) 호출

언어별 구현:

  • C/C++/Rust/Go: 정적/동적 링크를 거쳐 네이티브 기계어 실행
  • Java/Kotlin/Scala: 바이트코드(.class) 생성 → JVM이 실행(JIT으로 기계어 변환)
  • Python/JavaScript: 인터프리터 중심이나, 내부적으로 바이트코드/JIT 혼용

3) 컴파일 언어와 인터프리터 언어

고급 언어는 어떻게 저급 언어로 변환되나?

compile/interpret

✅ 컴파일 언어 (Compiled)

  • 컴파일러가 소스 전체를 저급 형식으로 변환 후 실행
  • 예) C, C++, Rust, Go
  • 장점: 실행 속도 빠름, 배포 용이
  • 단점: 수정 시 재컴파일 필요

✅ 인터프리터 언어 (Interpreted)

  • 인터프리터한 줄씩(또는 바이트코드 단위) 읽고 바로 실행
  • 예) Python, Ruby, 일부 JS 런타임
  • 장점: 즉시 실행/디버깅 용이
  • 단점: 상대적으로 느릴 수 있음

⚠️ 실전에서는 혼합 모델이 일반적:
JS(V8), Java(JIT), Python(PyPy)처럼 인터프리트 + JIT를 함께 사용


4) 명령어의 구조 — 연산 코드와 오퍼랜드

기계어/어셈블리어의 각 명령어는 보통 연산코드(Opcode) + 오퍼랜드(Operand) 로 구성됩니다.

📌 개념 잡기

연산자오퍼랜드
a - b-a, b
x * 2*x, 2
score >= 60>=score, 60
num++++num
  • 연산코드(Opcode): 무엇을 할지(이동/산술/논리/분기 등)
  • 오퍼랜드(Operand): 무엇을 대상으로(값/레지스터/메모리 주소 등)
mov eax, 0      ; 연산코드: mov  | 오퍼랜드: eax, 0
pop rbp         ; 연산코드: pop  | 오퍼랜드: rbp
ret             ; 연산코드: ret  | 오퍼랜드: (없음)
오퍼랜드 수형태예시설명
0개0-주소ret피연산자 없음(내부 스택/PC 이용)
1개1-주소pop rbp하나의 대상만 사용
2개2-주소mov eax, edxedxeax 복사(x86 전형)
3개3-주소add x3, x1, x2RISC 계열 전형(결과 레지스터 분리)

5) 연산 코드(Opcode) 유형과 플래그

  • 데이터 전송: mov, push, pop, load/store

  • 산술/논리: add, sub, mul, and, or, xor, shl, shr

  • 비교/분기: cmp, test, jmp, je/jne/jl/jg… (플래그 기반 조건 분기)

  • 제어 흐름: call, ret, syscall/svc

  • 입출력 제어: in, out(x86), 메모리 매핑 I/O(일반적)

플래그(상태) 레지스터: 연산 결과에 따라 ZF(Zero), CF(Carry), SF(Sign), OF(Overflow) 등이 설정되고, 이후 조건 분기에서 사용됩니다.

6) 주소 지정 방식 (Addressing Modes)

Q. 오퍼랜드 필드에 그냥 데이터/주소를 넣으면 되지 않나?
A. 명령어 길이 제한, 코드 밀도, 배열/구조체/포인터 접근의 유연성을 위해 다양한 모드가 필요합니다.

구분예시설명/용도
즉시(Immediate)MOV AX, 5값이 명령어 안에 직접 포함. 빠르지만 값은 고정
직접(Direct)MOV AL, [0x1234]상수 주소의 메모리에 바로 접근
간접(Indirect)MOV AL, [BX]레지스터가 주소를 보관 → 그 주소의 메모리에 접근
레지스터(Register)MOV AX, BX레지스터 간 전송(가장 빠름, 메모리 미접근)
레지스터 간접(Register Indirect)MOV AX, [SI]인덱스 레지스터가 가리키는 주소 접근
변위(Indexed/Displacement)MOV AL, [BX+05]기준 주소 + 오프셋(배열 인덱싱)
베이스+인덱스(Base+Index)MOV AL, [BX+SI]구조체/2차원 배열 등 복합 주소
스케일드 인덱스(Scaled Index)MOV EAX, [RBX+RCX*4]기준 + 인덱스×크기 (원소 크기 반영)
상대(PC-Relative)JMP label현재 PC + 오프셋(분기/함수 호출에 보편)
profile
기록해야 (살아)남는다 !

0개의 댓글