소스코드
1. 소스코드 분류
- 고급언어(High-Level Language): 사람이 이해하기 쉬운 문법이다. (C, Java, Python 등)
- 저급언어(Low-Level Language)
- 어셈블리어(Assembly): 기계어를 사람이 읽을 수 있도록 기호화한 언어이다.
- 기계어(Machine Code): 0과 1로 표현된 CPU가 직접 해석할 수 있는 명령어 비트다.
2. 변환(Translation) 방식
- 컴파일 언어(Compiled Language)
- 전체 소스코드를 한 번에 번역하여 실행 파일을 생성한다. (예: C, C++, Go)
- 인터프리터 언어(Interpreted Language)
- 실행 시 한 줄씩 해석하여 실행한다 (예: Python, JavaScript)
- 혼합형: Java: 소스 -> 바이트코드 -> JVM이 실행한다.
3. 컴파일 언어 실행 과정
Source Code -> Compiler -> Object Code(.o/.obj) Object Code + Libraries -> Linker -> Executable File(.exe / ELF)
- Compiler: 고급언어 -> 저급언어(기계어에 가까운 형태) 변환
- Linker: 여러 오브젝트 파일과 라이브러리를 연결하여 실행 가능한 하나의 파일 생성
- Executable File: OS가 로드 후 CPU가 실행
4. 추가 설명
- Object Code는 CPU 아키텍처에 맞는 기계어지만, 단일 파일로 실행되려면 링킹이 필요하다.
- 어셈블리어 <---> 기계어는 1:1 매핑 관계라서 어셈블러/디스어셈블러로 상호 변환이 가능하다.
소스코드가 실행파일로 변환되는 과정
Source Code (C, Java, Python...) -> Compile / Assemble Object Code (Machine Instructions) ->
Link Executable File (.exe / ELF) -> Load (by OS Loader) Main Memory (Instructions + Data) ->
Fetch / Decode / Execute (by CPU)
OS Loader와 메모리 배치
실행 파일이 OS에 의해 실행되면 Loader가 다음 작업을 진행한다.
- 코드 영역(Text Segment): 기계어 명령어를 저장 (CPU가 여기서 Fetch)
- 데이터 영역(Data Segment): 전역 변수, 상수
- 힙(Heap): 동적 메모리 할당
- 스택(Stack): 함수 호출 시 지역 변수, 리턴 주소 저장
이때 CPU는 메모리 주소(Instruction Pointer)를 통해 명령어를 한 줄씩 가져온다.
CPU 레지스터 관점: 실행 사이클, 명령어 사이클(Instruction Cycle)을 반복한다.
- Fetch (명령어 가져오기)
- PC (Program Counter): 다음에 실행할 명령어의 메모리 주소 저장
- MAR (Memory Address Register): PC가 가리키는 주소를 메모리에 전달
- MDR (Memory Data Register): 해당 주소에서 읽은 명령어를 저장
- IR (Instruction Register): 현재 실행할 명령어를 보관
- Decode (명령어 해석)
- 명령어를 해석하여 어떤 동작(ADD, MOV, JUMP 등)과 어떤 데이터가 필요한지 판단
- 제어장치(Control Unit)가 ALU나 레지스터에 신호를 보냄
- Execute (명령어 실행)
- ALU (Arithmetic Logic Unit): 덧셈, 뺄셈, 논리연산 수행
- General Purpose Registers (EAX, EBX, R0, R1 등): 중간 계산값 저장
- 메모리 읽기/쓰기, 분기(JUMP) 등 실행
- Write Back (결과 저장)
- 계산 결과를 레지스터나 메모리에 저장
- PC 값을 갱신 -> 다음 명령어로 이동
명령어(Command): Operation code, Operand
[ Operation Code | Operand(s) ]
Operation Code(Opcode): 수행할 동작을 지정하는 부분 (예: ADD, MOV, JUMP 등), CPU가 어떤 연산을 해야 하는지 알려준다.
Operand: 연산에 필요한 데이터나 데이터의 위치(주소)를 지정한다. 레지스터, 메모리 주소, 즉시 값(Immediate Value) 등이 될 수 있다.
오퍼랜드는 사용할 데이터를 직접 명시하기 보다, 데이터가 저장된 위치를 주로 나타낸다. 즉 메모리 주소나 레지스터 이름이 담긴다.
아래는 Operation code와 Operand가 사용될 때의 예시다.
ADD R1, R2, R3
주요 아키텍처(예: x86, ARM, RISC-V)에서 공통적으로 나오는 Opcode 분류 + 대표 예시 정리내용은 아래와 같으며, 분류별 개념을 설명한다. 모든 CPU의 Opcode 집합은 ISA(Instruction Set Architecture)마다 다르다.
1. 데이터 전송 (Data Transfer): 메모리와 레지스터, 레지스터 간 데이터 이동
- MOV: 레지스터 ↔ 메모리/레지스터 간 데이터 이동
- LD / LDR / LOAD: 메모리 → 레지스터 로드
- ST / STR / STORE: 레지스터 → 메모리 저장
- PUSH / POP: 스택에 값 저장/스택에서 값 꺼내기
- LEA: 주소 계산 후 레지스터에 저장
2. 산술 연산 (Arithmetic Operations): 수학적 연산 수행
- ADD: 덧셈
- SUB: 뺄셈
- MUL / IMUL: 곱셈 (정수)
- DIV / IDIV: 나눗셈 (정수)
- INC: 1 증가
- DEC: 1 감소
- NEG: 부호 반전
- ADC / SBB: 캐리·보로와 함께 덧셈/뺄셈
3. 논리 연산 (Logical Operations): 비트 단위 연산
- AND: 비트 AND
- OR: 비트 OR
- XOR: 비트 XOR
- NOT: 비트 반전
- TEST: AND 수행 후 결과 저장 안 하고 플래그만 설정
4. 시프트 / 회전 (Shift / Rotate): 비트를 이동시키는 연산
- SHL / SAL: 왼쪽 시프트
- SHR: 오른쪽 시프트
- SAR: 부호 유지하며 오른쪽 시프트
- ROL / ROR: 비트를 왼쪽/오른쪽 회전
- RCL / RCR: 캐리 플래그 포함 회전
5. 비교 및 분기 (Comparison & Branching): 조건에 따른 실행 흐름 제어
- CMP: 두 값 비교 (결과는 플래그에 반영)
- JMP: 무조건 점프
- JE / JZ: 같으면/0이면 점프
- JNE / JNZ: 다르면/0이 아니면 점프
- JG / JGE / JL / JLE: 부호 있는 비교 후 조건 점프
- JA / JAE / JB / JBE: 부호 없는 비교 후 조건 점프
- CALL: 서브루틴 호출
- RET: 서브루틴 반환
6. 스택/프로시저 제어 (Stack & Procedure Control)
- CALL / RET: 함수 호출 / 반환
- ENTER / LEAVE: 함수 프레임 설정 / 해제
7. 시스템 제어 (System Control)
- HLT: CPU 정지
- NOP: 아무것도 하지 않음
- INT: 소프트웨어 인터럽트
- IRET: 인터럽트에서 복귀
- CLI / STI: 인터럽트 비활성화 / 활성화
8. 부동소수점/멀티미디어 명령 (Optional)
- FADD / FSUB / FMUL / FDIV: 부동소수점 연산
- MOVD / MOVQ: SSE/MMX 레지스터 간 데이터 이동
- ADDPS / MULPS: SIMD 벡터 연산
강민철, 혼자 공부하는 컴퓨터 구조+운영체제. 한빛미디어, 2022
'컴퓨터 구조와 운영체제' 카테고리의 다른 글
3. ALU, 제어장치, 레지스터 (2) | 2025.08.16 |
---|---|
1. 컴퓨터 구조의 큰그림 (4) | 2025.08.07 |