728x90

CPU가 명령어를 가져와 실행하는 과정

  1. 명령어 인출
  2. 명령어 실행
  3. 다음 명령어 인출

명령어를 가져오는 기준 : Program Counter (PC)

  • PC는 CPU내부의 레지스터 중 하나로, 프로그램이 메모리에 저장된 여러 명령어들 중 어디부터 실행해야 할지를 알려주는 '위치 표시기'라고 할 수 있음
  • PC는 현재 실행 중이거나 다음에 실행할 명령어가 메모리의 어느 위치에 있는지를 가리킴
  • CPU가 명령어를 인출한 후, PC는 다음 명령어의 주소를 가리키도록 자동으로 증가함
  • 프로그램이 조건에 따라 다른 명령어로 이동해야 할 때(예: if 문, for 문에서의 점프), PC의 값을 변경하여 새로운 위치로 이동하게 함

최초의 PC 레지스터 값은 어떻게 설정될까?

  1. 컴파일 과정
    • 코드가 작성된 후, 컴파일러는 이 코드를 기계 명령어(바이너리 코드)로 변환하여 실행 파일을 생성함
    • 이 실행 파일에는 프로그램의 명령어와 데이터를 포함하고 있으며, 디스크에 저장됨
  2. 프로그램 실행 요청
    • 사용자가 프로그램을 실행하면, 운영 체제가 이 요청을 처리함
  3. 프로그램의 메모리 로드
    • 운영 체제는 실행 파일을 디스크에서 읽어 들여, 메모리(RAM)의 특정 위치에 로드함
    • 이 과정에서 프로그램의 코드와 데이터가 메모리에 배치됨
    • 특히, 프로그램의 시작 지점(엔트리 포인트)이 메모리의 특정 주소에 할당됨
  4. 프로그램 카운터(PC) 설정
    • 운영 체제는 프로그램을 메모리에 로드한 후, 프로그램의 엔트리 포인트 주소(즉, 첫 번째 명령어가 위치한 주소)를 PC 레지스터에 설정함
    • 이 엔트리 포인트 주소는 실행 파일의 헤더에 정의되어 있음
  5. 프로그램 실행 시작
    • PC 레지스터가 프로그램의 첫 번째 명령어를 가리키게 되면, CPU는 이 명령어를 인출(fetch)하여 실행(decode & execute)함
    • 이후, PC는 자동으로 다음 명령어의 주소를 가리키도록 업데이트되며, 프로그램이 순차적으로 실행됨
728x90

'Computer Science' 카테고리의 다른 글

멀티태스킹과 프로세스 관리  (0) 2024.08.14
메모리 단편화  (0) 2024.08.14
운영체제의 역할과 필요성  (0) 2024.08.08
정적 라이브러리와 동적 라이브러리  (3) 2024.07.24
링커의 심벌해석 대상  (3) 2024.07.24
728x90

멀티태스킹과 프로세스 관리는 현대 컴퓨터 시스템의 중요한 요소로, 여러 프로그램이 동시에 실행되면서도 각각의 프로그램이 원활하게 작동할 수 있도록 관리하는 역할을 수행함

이 글에서는 멀티태스킹의 개념과 이를 가능하게 하는 프로세스 관리의 기초 원리를 정리함

1. 멀티태스킹의 개념

멀티태스킹은 컴퓨터 시스템이 여러 작업(프로그램)을 동시에 처리하는 것처럼 보이게 만드는 기술임

실제로는 단일 CPU 코어에서 한 번에 하나의 작업만 처리할 수 있지만, 운영체제는 빠른 속도로 작업을 전환하여 사용자가 여러 프로그램이 동시에 실행되는 것처럼 느끼도록 함

1.1 시분할 시스템과 멀티태스킹

시분할 시스템은 CPU 시간을 여러 작업 간에 나누어 사용하게 하는 방식으로, 멀티태스킹의 기본 원리임

운영체제는 각 작업에 일정한 시간 간격을 할당하고, 이 시간이 지나면 다른 작업으로 전환함

이 과정을 매우 빠르게 반복하여 사용자는 여러 작업이 동시에 실행되는 것처럼 느끼게 됨

 

프로그램 A를 먼저 실행했다가 잠시 중지하고 프로그램 B의 실행으로 넘어갔다가 중지하고 다시 프로그램 A를 실행

이 과정에서는 프로그램 A를 어디까지 실행했고, 어떤 데이터를 사용하고 있었는지 등의 문맥(Context)을 기반으로 전환함

1.2 문맥 전환(Context Switching)

문맥 전환은 CPU가 하나의 프로세스에서 다른 프로세스로 전환할 때 발생하는 과정임

이 과정에서 운영체제는 현재 프로세스의 상태(레지스터 값, 프로그램 카운터 등)를 저장하고, 다음에 실행할 프로세스의 상태를 복원함

문맥 전환은 멀티태스킹의 핵심 기술로, 이를 통해 여러 프로세스가 공존할 수 있음

2. 프로세스 관리의 중요성

프로세스 관리는 멀티태스킹 시스템에서 각 프로그램(프로세스)의 실행을 효과적으로 제어하고 조정하는 역할을 수행함

운영체제는 프로세스의 생성, 실행, 일시 중지, 종료 등을 관리하며, 이를 통해 시스템 자원의 효율적인 사용을 보장함

2.1 프로세스의 구조

프로세스는 프로그램이 메모리에 적재되어 실행 중인 상태를 의미하며, 다음과 같은 구조로 이루어짐

  • 코드 영역: 실행할 기계 명령어가 저장된 영역으로, 프로세스의 실제 작업을 수행
  • 데이터 영역: 전역 변수와 같은 데이터가 저장되는 영역
  • 힙 영역: 동적 메모리 할당을 위해 사용되는 영역
  • 스택 영역: 함수 호출 시 매개변수, 반환 주소, 지역 변수가 저장되는 영역

2.2 프로세스 생성과 종료

프로세스는 프로그램이 실행될 때 운영체제에 의해 생성됨

프로세스 생성 과정은 다음과 같음

  1. 프로세스 식별자(PID) 할당: 운영체제는 각 프로세스에 고유한 식별자를 할당함
  2. 메모리 할당: 코드, 데이터, 힙, 스택 영역이 메모리에 할당됨
  3. 실행 준비: 운영체제는 프로세스를 준비 큐에 배치하여 CPU 할당을 대기하게 함

프로세스가 종료되면 운영체제는 해당 프로세스의 메모리를 해제하고, 프로세스 관련 자원을 반환함

2.3 프로세스 스케줄링

프로세스 스케줄링은 CPU 자원을 여러 프로세스에 할당하는 과정임

스케줄링 알고리즘은 프로세스의 우선순위, 실행 시간, 입출력 대기 시간 등을 고려하여 CPU 시간을 효율적으로 분배함

  • 선점형 스케줄링: 높은 우선순위를 가진 프로세스가 CPU를 차지할 수 있도록 낮은 우선순위의 프로세스를 중지시킴
  • 비선점형 스케줄링: 현재 실행 중인 프로세스가 완료될 때까지 다른 프로세스가 CPU를 차지하지 않음

스케줄링 알고리즘의 선택은 시스템의 응답 속도, 처리량, 공정성 등에 영향을 미침

3. 멀티태스킹의 도전 과제

멀티태스킹은 강력한 기능을 제공하지만, 동시에 몇 가지 도전 과제를 동반함

3.1 상호 배제와 동기화

여러 프로세스가 동시에 실행될 때, 특정 자원(예: 파일, 메모리)을 동시에 사용하려고 하면 충돌이 발생할 수 있음

이를 방지하기 위해 운영체제는 상호 배제(Mutual Exclusion) 메커니즘과 동기화(Synchronization) 기법을 사용함

  • 뮤텍스(Mutex): 한 번에 하나의 프로세스만 자원에 접근할 수 있도록 보장함
  • 세마포어(Semaphore): 자원 접근을 카운팅하여 여러 프로세스가 제한된 자원에 접근할 수 있도록 조정함

3.2 데드락(교착 상태)

데드락은 두 개 이상의 프로세스가 서로의 자원을 기다리며 무한 대기 상태에 빠지는 현상

운영체제는 데드락을 예방, 탐지, 회복하기 위한 다양한 기법을 제공함

4. 결론

멀티태스킹과 프로세스 관리는 현대 운영체제의 핵심적인 기능으로, 여러 프로그램이 동시에 실행될 수 있도록 자원 관리를 효율적으로 수행함

문맥 전환, 프로세스 스케줄링, 상호 배제와 같은 기술을 통해 시스템의 안정성과 성능을 유지하며, 사용자에게 원활한 컴퓨팅 환경을 제공함

운영체제의 이러한 기능들은 복잡한 시스템 자원을 관리하고, 여러 작업이 원활하게 수행될 수 있도록 지원함으로써 현대 컴퓨터 시스템의 근간을 이루고 있음

728x90

'Computer Science' 카테고리의 다른 글

CPU 명령어 인출과 실행 과정  (1) 2024.08.21
메모리 단편화  (0) 2024.08.14
운영체제의 역할과 필요성  (0) 2024.08.08
정적 라이브러리와 동적 라이브러리  (3) 2024.07.24
링커의 심벌해석 대상  (3) 2024.07.24
728x90

메모리 단편화는 메모리를 효율적으로 사용하지 못해 발생하는 현상으로, 내부 단편화와 외부 단편화로 나뉨

내부 단편화 (Internal Fragmentation)

내부 단편화는 메모리 할당 단위의 고정 크기로 인해 할당된 메모리 블록 내에서 남는 공간이 생기는 현상

예를 들어, 운영체제가 8KB 크기의 고정된 메모리 블록을 할당한다고 가정할 때, 어떤 프로그램이 6KB의 메모리가 필요하면 2KB의 메모리가 남게 됨

이 2KB의 공간은 다른 용도로 사용할 수 없으며, 결과적으로 메모리 공간이 낭비됨

이처럼 할당된 메모리 블록 내에서 남는 공간을 내부 단편화라 함

내부 단편화 해결 방법

 

  • 가변 크기 블록 할당 (Variable-sized Partitioning)
    • 고정된 크기의 메모리 블록 대신 가변 크기의 블록을 사용하여 필요한 만큼의 메모리를 할당
    • 프로그램이 실제로 필요한 메모리 양에 맞춰 메모리를 할당할 수 있어 내부 단편화를 줄일 수 있음
  • 슬랩 할당자 (Slab Allocator)
    • 운영체제에서 특정 크기의 메모리 블록을 자주 사용하는 경우, 이러한 블록을 미리 준비해두는 방식으로 내부 단편화를 줄임
    • 슬랩 할당자는 주로 커널에서 사용되며, 효율적인 메모리 사용을 보장함

 

외부 단편화 (External Fragmentation)

외부 단편화는 할당 가능한 메모리 공간이 비연속적으로 존재하여 총 여유 공간이 충분함에도 메모리를 할당하지 못하는 현상

다양한 크기의 메모리 블록이 할당되고 해제되면서, 메모리 공간에는 다양한 크기의 빈 블록이 흩어져 남게 됨

이로 인해, 충분한 전체 메모리 공간이 존재하더라도 연속된 메모리 블록이 없어 새로운 프로그램을 위해 메모리를 할당할 수 없는 상황이 발생할 수 있음

이러한 비연속적인 빈 공간을 외부 단편화라 함

외부 단편화 해결 방법

  • 메모리 압축 (Memory Compaction)
    • 외부 단편화를 줄이기 위해, 메모리의 사용 중인 블록을 하나로 모아 연속된 빈 공간을 확보하는 방법
    • 메모리 이동이 필요하기 때문에 비용이 발생할 수 있지만, 큰 연속된 메모리 블록을 할당해야 할 때 유용함
  • 가상 메모리 (Virtual Memory)
    • 가상 메모리 기법을 사용하면 프로그램은 연속적인 메모리 공간에 접근하는 것처럼 보이지만, 실제로는 비연속적인 물리적 메모리 위치를 사용할 수 있음
    • 이로 인해 외부 단편화 문제를 어느 정도 완화할 수 있음
  • 최적 적합 할당 (Best Fit Allocation)
    • 메모리 할당 시, 사용할 수 있는 빈 공간 중에서 가장 작은 빈 블록에 메모리를 할당하여 외부 단편화를 줄이려는 방법
    • 이는 남은 작은 빈 공간을 최소화하는 데 도움이 됨
728x90
728x90

운영체제는 컴퓨터 시스템에서 핵심적인 역할을 담당하는 소프트웨어로, 사용자가 하드웨어와 소프트웨어를 효율적으로 사용할 수 있도록 다양한 기능을 제공함

1. 운영체제의 역할

1.1 프로세스 관리

운영체제는 여러 프로그램이 동시에 실행되는 멀티태스킹 환경을 지원함

프로세스 관리의 핵심은 다음과 같음

  • 프로세스 생성 및 종료: 프로그램이 실행되면 운영체제가 새로운 프로세스를 생성하고, 프로그램 종료 시 이를 제거함
  • 프로세스 스케줄링: CPU 시간을 효율적으로 분배하여 여러 프로세스가 마치 동시에 실행되는 것처럼 보이게 함
    이는 CPU 스케줄링 알고리즘을 통해 이루어짐
  • 문맥 전환: 프로세스 간 전환 시 필요한 상황 정보를 저장하고 복원하여 프로그램의 상태를 유지함

1.2 메모리 관리

메모리는 모든 프로그램 실행에 필수적인 자원으로, 운영체제는 메모리의 효율적 사용을 보장함

  • 메모리 할당 및 해제: 프로그램이 필요로 하는 메모리 공간을 할당하고, 필요가 없어지면 해제함
  • 가상 메모리 관리: 물리적 메모리의 크기를 초과하는 프로그램 실행을 가능하게 하며, 페이지 교체 알고리즘을 통해 효율적인 메모리 사용을 보장함

1.3 파일 시스템 관리

운영체제는 파일의 저장, 검색, 보호 등과 관련된 다양한 기능을 제공함

  • 파일 저장 및 검색: 파일을 디스크에 저장하고 검색할 수 있는 인터페이스를 제공함
  • 파일 권한 관리: 사용자 및 그룹에 따라 파일 접근 권한을 설정하고 관리함

1.4 하드웨어 및 장치 관리

운영체제는 하드웨어와 소프트웨어 간의 매개 역할을 하여 하드웨어 자원의 효율적 사용을 보장함.

  • 장치 드라이버: 운영체제가 하드웨어 장치와 소통할 수 있도록 지원하는 소프트웨어로, 모든 프로그램이 특정 하드웨어와 직접 상호작용하지 않도록 추상화 계층을 제공함
  • 입출력 관리: 다양한 입출력 장치(프린터, 디스크 등)의 효율적 사용과 관리

1.5 사용자 인터페이스 제공

운영체제는 사용자와 시스템 간의 상호작용을 지원하는 다양한 인터페이스를 제공함

  • 그래픽 사용자 인터페이스(GUI): 사용자가 아이콘과 메뉴를 통해 컴퓨터를 쉽게 사용할 수 있도록 지원함
  • 명령어 인터페이스(CLI): 명령어 입력을 통해 컴퓨터와 상호작용할 수 있는 환경을 제공함

2. 운영체제의 필요성

2.1 자원 관리의 효율성

운영체제가 없다면 사용자가 직접 메모리 할당, CPU 스케줄링 등을 처리해야 하며, 이는 매우 복잡하고 비효율적일 수 있음

운영체제는 이러한 자원 관리를 자동으로 수행하여 시스템의 효율성을 극대화함

2.2 프로그램 실행의 용이성

운영체제는 프로그램 실행을 간단하게 만들어 줌

프로그래머는 프로그램을 작성하고 컴파일한 후 운영체제에 의해 자동으로 메모리에 적재되고 실행됨

이를 통해 개발자는 복잡한 하드웨어 관리에서 벗어나 프로그램 개발에 집중할 수 있음

2.3 하드웨어 추상화

운영체제는 하드웨어와 소프트웨어 간의 추상화 계층을 제공하여, 프로그래머가 특정 하드웨어에 대한 지식 없이도 프로그램을 개발할 수 있게 함

이는 하드웨어의 다양성을 프로그램에 반영하지 않고도 동일한 소프트웨어가 여러 시스템에서 실행될 수 있도록 지원함

2.4 보안 및 안정성

운영체제는 프로그램 간의 상호작용과 데이터 공유를 관리하여 시스템의 보안을 유지함

또한, 프로세스 격리 및 사용자 권한 관리를 통해 시스템의 안정성을 보장함

2.5 사용자 경험 향상

운영체제는 사용자에게 친숙한 환경을 제공함으로써, 컴퓨터 사용 경험을 향상함

GUI를 통해 사용자는 복잡한 명령어 입력 없이도 쉽게 컴퓨터를 사용할 수 있음

3. 결론

운영체제는 현대 컴퓨터 시스템에서 필수적인 구성 요소로, 하드웨어와 소프트웨어 간의 매개 역할을 수행하고 시스템 자원을 효율적으로 관리함으로써 사용자와 프로그래머에게 다양한 편의를 제공함

운영체제의 이러한 기능들은 컴퓨터 시스템의 효율성과 안정성을 유지하는 데 핵심적임

운영체제가 없다면 프로그래머와 사용자는 시스템 자원 관리를 직접 해야 하므로 컴퓨터 사용이 매우 비효율적이 되고, 오류 발생 가능성도 높아짐

운영체제의 중요성과 필요성을 이해하는 것은 컴퓨터 시스템의 전반적인 작동 원리를 이해하는 데 필수적임

728x90

'Computer Science' 카테고리의 다른 글

멀티태스킹과 프로세스 관리  (0) 2024.08.14
메모리 단편화  (0) 2024.08.14
정적 라이브러리와 동적 라이브러리  (3) 2024.07.24
링커의 심벌해석 대상  (3) 2024.07.24
지역 심벌과 전역 심벌  (0) 2024.07.24
728x90

소프트웨어 개발에서 라이브러리는 코드의 재사용성을 높이고, 개발 시간을 단축하는 데 중요한 역할을 함

라이브러리는 크게 정적 라이브러리와 동적 라이브러리로 구분됨

이번 글에서는 정적 라이브러리와 동적 라이브러리의 개념과 차이점, 그리고 라이브러리 생성 및 링크 과정에 대해 정리함

정적 라이브러리(Static Library)란?

정적 라이브러리는 링크 타임에 프로그램에 결합되며, 코드가 실행 파일에 포함되는 라이브러리

 

특징

  • 확장자: .a (Unix 계열), .lib (Windows)
  • 링크 시점: 컴파일 후 링크 타임에 실행 파일에 결합됨
  • 파일 크기: 모든 필요한 라이브러리 코드가 포함되어 실행 파일 크기가 커질 수 있음
  • 독립성: 실행 파일에 라이브러리의 모든 코드가 포함되므로, 실행 시 별도의 라이브러리가 필요하지 않음
  • 업데이트: 라이브러리를 업데이트하려면 실행 파일을 다시 컴파일하고 링크해야 함

로드 방식

  • 링크 타임에 포함: 정적 라이브러리는 프로그램이 링크될 때 실행 파일에 포함됨
    이는 라이브러리의 코드가 실행 파일에 직접 결합되어 독립적인 실행 파일이 생성됨을 의미함
    결과적으로, 실행 시 별도의 라이브러리 파일이 필요하지 않음

동적 라이브러리(Dynamic Library)

동적 라이브러리는 코드가 실행파일에 포함되지 않으며, 일반적으로 실행 시간에 로드되는 라이브러리

 

특징

  • 확장자: .so (Unix 계열), .dll (Windows)
  • 링크 시점: 실행 시간에 라이브러리가 로드됨
  • 파일 크기: 라이브러리 코드가 포함되지 않기 때문에 실행 파일 크기가 정적라이브러리에 비해 작음
  • 공유성: 여러 프로그램이 하나의 라이브러리를 공유하여 메모리 사용량을 줄일 수 있음
  • 업데이트: 라이브러리를 업데이트해도 실행 파일을 다시 컴파일할 필요가 없음

로드 방식

  • 런타임 로드: 일반적으로 프로그램이 실행되는 동안 동적 라이브러리가 로드됨
    이 방식은 라이브러리 파일이 실행 파일과 별도로 유지되며, 필요할 때마다 로드
  • 프리로드: 일부 시스템에서는 프로그램이 실행될 때 특정 동적 라이브러리를 미리 로드할 수 있음
    이를 통해 실행 시간 동안 필요한 라이브러리가 즉시 사용 가능함
    환경 변수(LD_PRELOAD 등)를 사용하여 특정 라이브러리를 미리 로드할 수 있음

라이브러리 생성 과정

라이브러리를 생성하는 과정은 여러 객체 파일을 하나의 라이브러리 파일로 묶는 것을 포함
정적 라이브러리와 동적 라이브러리 생성 과정은 다소 다름

정적 라이브러리 생성

  1. 소스 코드 컴파일
    • 소스 코드를 컴파일하여 객체 파일을 생성함
    • gcc -c libmath.c -o libmath.o
  2. 정적 라이브러리 생성
    • 여러 객체 파일을 하나의 정적 라이브러리 파일로 묶음
    • ar rcs libmath.a libmath.o

동적 라이브러리 생성

  1. 소스 코드 컴파일
    • 동적 라이브러리를 생성할 때는 위치 독립 코드(Position Independent Code)를 생성해야 함
    • gcc -fPIC -c libmath.c -o libmath.o
  2. 동적 라이브러리 생성
    • 객체 파일을 동적 라이브러리로 묶음
    • gcc -shared -o libmath.so libmath.o

라이브러리 링크 과정

생성된 라이브러리를 사용하여 실행 파일을 만드는 과정은 링크 단계에서 이루어짐

 

정적 라이브러리 링크

정적 라이브러리를 포함하여 실행 파일을 생성함
정적 라이브러리의 모든 코드가 실행 파일에 포함

  • gcc -o myprogram myprogram.c -L. -lmath

동적 라이브러리 링크

동적 라이브러리를 포함하여 실행 파일을 생성함
실행 파일에는 동적 라이브러리를 참조하는 코드만 포함되고, 라이브러리는 실행 시 로드됨

  • gcc -o myprogram myprogram.c -L. -lmath

동적 라이브러리 로드 설정

동적 라이브러리를 실행 파일이 실행되는 동안 찾을 수 있도록 환경 변수를 설정

  • export LD_LIBRARY_PATH=.

결론

정적 라이브러리와 동적 라이브러리는 각각의 장단점을 가지고 있으며, 특정 상황에 따라 적절히 선택하여 사용해야 함

라이브러리 생성과 링크는 소프트웨어 개발의 서로 다른 단계이지만, 실행 파일을 만들기 위해 모두 필요함

생성된 라이브러리를 링크 과정에서 사용하여 최종 실행 파일을 만드는 것이 이 두 과정의 주요 역할임

개발 환경과 배포 방식에 따라 적합한 라이브러리 방식을 선택하여 효율적인 소프트웨어 개발을 할 수 있음

728x90

'Computer Science' 카테고리의 다른 글

메모리 단편화  (0) 2024.08.14
운영체제의 역할과 필요성  (0) 2024.08.08
링커의 심벌해석 대상  (3) 2024.07.24
지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
728x90

링커의 심벌 해석 대상은 주로 전역 심벌과 외부 심벌임. 링커는 여러 개의 객체 파일을 결합하여 실행 가능한 프로그램을 생성하는 과정에서 심벌 해석을 수행함

이 과정에서 링커는 각 객체 파일에 포함된 심벌을 분석하고 올바른 메모리 주소를 할당하여 참조를 해결함

링커의 심벌 해석 대상

  1. 전역 심벌(Global Symbols)
    • 정의된 전역 변수와 함수: 각 객체 파일에서 정의된 전역 변수와 함수는 링커에 의해 심벌 테이블에 추가되고, 프로그램 전체에서 참조될 수 있도록 메모리 주소가 할당됨
    • 예시: int g_a = 1; 와 같은 전역 변수나 int func_a(int x, int y); 와 같은 함수 정의
  2. 외부 심벌(External Symbols)
    • 다른 객체 파일에서 정의된 변수와 함수: 한 객체 파일에서 선언되었지만 정의되지 않은 변수나 함수는 외부 심벌로 간주되며, 링커가 다른 객체 파일에서 해당 심벌의 정의를 찾아 연결함
    • 예시: extern int g_e; 와 같은 외부 변수 선언이나 다른 객체 파일에서 정의된 함수 참조

심벌 해석 과정

링커의 심벌 해석 과정은 다음과 같은 단계를 포함함

  1. 심벌 수집(Symbol Collection)
    • 각 객체 파일의 심벌 테이블을 수집하고, 전역 심벌과 외부 심벌을 추출함
  2. 심벌 해석(Symbol Resolution)
    • 전역 심벌과 외부 심벌을 매칭하여 참조를 해결함. 예를 들어, 한 객체 파일에서 extern으로 선언된 심벌을 다른 객체 파일에서 정의된 심벌과 연결함
    • 정의되지 않은 외부 심벌이 발견되면 링커 오류가 발생함
  3. 심벌
    • 에 실제 메모리 주소를 할당함. 이를 통해 각 객체 파일에서 참조된 심벌이 올바른 메모리 위치를 가리키도록 함
  4. 재배치(Relocation)
    • 심벌 해석과 주소 할당 후, 각 객체 파일의 코드와 데이터를 재배치하여 올바른 메모리 위치로 이동함

예시 코드에서의 링커 심벌 해석 대상

int g_a = 1;               // 전역 변수
extern int g_e;           // 외부 변수
int func_a(int x, int y); // 함수 참조

// 함수 구현
int func_b()
{
    int m = g_a + 2;
    return func_a(m + g_e);
}

 

이 예제 코드에서 링커의 심벌 해석 대상은 다음과 같음

  • 전역 변수 g_a: 객체 파일에서 정의된 전역 변수로, 링커는 이 변수를 참조하는 모든 곳에 대해 올바른 메모리 주소를 할당함
  • 외부 변수 g_e: 다른 객체 파일에서 정의된 변수로, 링커는 이 변수를 참조하는 모든 곳에서 정의된 실제 심벌과 연결함
  • 함수 func_a: 다른 객체 파일에서 정의된 함수로, 링커는 이 함수를 참조하는 모든 곳에서 정의된 실제 심벌과 연결함
  • 함수 func_b: 객체 파일에서 정의된 함수로, 링커는 이 함수의 코드와 데이터를 올바른 메모리 위치로 재배치함

이러한 과정을 통해 링커는 프로그램을 실행 가능한 상태로 만들며, 모든 심벌 참조가 올바르게 해결되도록 보장함

728x90

'Computer Science' 카테고리의 다른 글

운영체제의 역할과 필요성  (0) 2024.08.08
정적 라이브러리와 동적 라이브러리  (3) 2024.07.24
지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
728x90

프로그래밍에서 변수와 함수는 프로그램의 여러 부분에서 데이터를 저장하고 작업을 수행하는 중요한 역할을 함

이들 변수와 함수는 심벌(symbol)로 표현되며, 그 범위(scope)에 따라 지역 심벌(Local Symbol)과 전역 심벌(Global Symbol)로 구분됨

지역 심벌(Local Symbol)

지역 심벌은 특정 블록이나 함수 내에서 정의되고 사용되는 식별자를 말함

이러한 심벌은 정의된 블록이 종료되면 더 이상 유효하지 않으며, 해당 블록 내에서만 접근할 수 있음

 

특징

  • 정의 위치: 함수나 블록 내부
  • 유효 범위: 정의된 블록 내에서만 유효
  • 메모리 할당: 스택(stack)에 할당되며, 블록이 실행될 때 할당되고 블록이 종료되면 해제됨

전역 심벌(Global Symbol)

전역 심벌은 프로그램 전체에서 접근 가능한 식별자를 말함

이들 심벌은 파일 범위 또는 프로그램 전체 범위에서 정의되며, 모든 함수에서 접근할 수 있음

 

특징

  • 정의 위치: 함수 외부, 보통 파일의 상단에 위치
  • 유효 범위: 프로그램 전체
  • 메모리 할당: 데이터 세그먼트(data segment)에 할당되며, 프로그램이 시작될 때 할당되고 종료될 때 해제됨

예시 코드로 보는 지역 심벌과 전역 심벌

int g_a = 1;               // 전역 변수
extern int g_e;           // 외부 변수
int func_a(int x, int y); // 함수 참조

// 함수 구현
int func_b()
{
    int m = g_a + 2;
    return func_a(m + g_e);
}

이 예제 코드에서 지역 심벌과 전역 심벌을 나눠서 설명하면 다음과 같음

 

전역 심벌

  • g_a
    • 정의: int g_a = 1;
    • 설명: 프로그램 전체에서 접근 가능한 전역 변수
  • g_e
    • 정의: extern int g_e;
    • 설명: 외부 파일에서 정의된 변수로, 링크 단계에서 실제 주소가 결정됨
  • func_a
    • 정의: int func_a(int x, int y);
    • 설명: 함수 프로토타입 선언으로, 실제 구현은 다른 곳에 있어야 함
  • func_b
    • 정의: int func_b() {...}
    • 설명: 프로그램 전체에서 접근 가능한 함수 정의

지역 심벌

  • m
    • 정의: int m = g_a + 2;
    • 설명: func_b 함수 내에서 정의된 지역 변수로, 이 함수 내에서만 유효함
      함수가 호출될 때 스택에 할당되고, 함수가 종료되면 해제됨

결론

지역 심벌과 전역 심벌은 각각의 범위 내에서 서로 다르게 관리되고 사용됨
지역 심벌은 함수나 블록 내에서만 유효하며 스택에 할당되고, 전역 심벌은 프로그램 전체에서 접근 가능하며 데이터 세그먼트에 할당됨
이러한 차이점을 이해함으로써 더 효과적으로 변수를 관리하고 프로그램을 작성할 수 있음

프로그래밍을 할 때, 변수와 함수의 범위를 명확히 이해하고 사용하는 것이 중요함
이를 통해 코드의 가독성과 유지보수성을 높일 수 있음

728x90

'Computer Science' 카테고리의 다른 글

정적 라이브러리와 동적 라이브러리  (3) 2024.07.24
링커의 심벌해석 대상  (3) 2024.07.24
링커란?  (0) 2024.07.17
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
Brute force(브루트 포스)란?  (0) 2024.07.09
728x90

링커란?

링커(linker)는 컴파일러가 만들어낸 하나 이상의 목적 파일을 가져와 이를 단일 실행 프로그램으로 병합하는 프로그램

링커는 소프트웨어 개발 과정에서 필수적인 도구임

컴파일러가 소스 코드를 번역하여 오브젝트 파일을 생성하는 것만으로는 프로그램이 실행될 수 없음

링커는 심벌 해결, 재배치, 라이브러리 포함 등의 작업을 통해 여러 오브젝트 파일을 결합하여 실행 가능한 프로그램을 생성함

따라서 링커의 역할과 동작 원리를 이해하는 것은 효율적인 소프트웨어 개발을 위해 매우 중요함

컴파일 언어의 동작 과정

  1. 소스 코드 작성: 개발자가 소스 코드를 작성
  2. 컴파일 단계: 소스 코드를 오브젝트 파일로 변환함. 각 오브젝트 파일은 독립적으로 존재하며, 단독으로는 실행되지 않음
  3. 링킹 단계: 여러 오브젝트 파일을 결합하여 하나의 실행 파일을 생성

링커의 주요 역할

  1. 심벌 해결(Symbol Resolution)
    • 각 오브젝트 파일에는 함수나 변수가 정의되고 참조됨
    • 링커는 이러한 심벌들을 확인하고 올바른 메모리 주소를 할당함
    • 예를 들어 함수 A가 다른 오브젝트 파일에 정의된 함수 B를 호출할 때, 링커는 함수 B의 실제 메모리 위치를 찾아 함수 A가 올바르게 이를 참조할 수 있도록 함
  2. 재배치(Relocation)
    • 오브젝트 파일에서 코드와 데이터는 고정된 메모리 주소를 가지지 않음
    • 링커는 이들을 적절한 메모리 위치로 이동시키고, 프로그램의 각 부분이 올바르게 동작하도록 재배치함
    • 이는 메모리 주소가 충돌하지 않고 프로그램이 올바르게 실행되도록 보장함
  3. 라이브러리 포함(Library Inclusion)
    • 프로그램이 사용하는 라이브러리를 포함하여 최종 실행 파일을 만듦
    • 예를 들어, 표준 C 라이브러리나 사용자 정의 라이브러리가 프로그램에 필요할 경우, 링커는 해당 라이브러리의 오브젝트 파일들을 결합하여 실행 파일에 포함시킴

링킹 과정

  1. 오브젝트 파일 로드: 컴파일러가 생성한 오브젝트 파일들을 메모리에 로드
  2. 심벌 테이블 생성: 각 오브젝트 파일에 포함된 심벌 정보를 바탕으로 심벌 테이블을 생성
  3. 심벌 해결: 심볼 테이블을 참조하여 각 심벌의 정의와 참조를 해결
  4. 재배치 수행: 각 심볼의 메모리 주소를 계산하고, 코드와 데이터를 적절한 위치로 이동
  5. 라이브러리 결합: 필요한 라이브러리를 오브젝트 파일과 결합하여 최종 실행 파일을 생성

링커의 종류

  • ld: 유닉스 계열 운영체제에서 널리 사용되는 링커
  • gold: GNU 프로젝트에서 개발한 빠른 링커로, ld의 대안으로 사용됨
  • MSVC Linker: 마이크로소프트 비주얼 스튜디오에서 제공하는 링커로, Windows 환경에서 주로 사용됨

 

728x90

'Computer Science' 카테고리의 다른 글

링커의 심벌해석 대상  (3) 2024.07.24
지역 심벌과 전역 심벌  (0) 2024.07.24
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
Brute force(브루트 포스)란?  (0) 2024.07.09
스택(stack)과 힙(Heap)  (0) 2024.03.27
728x90

인터프리터와 컴파일러는 프로그램 소스를 인간이 이해할 수 있는 형태에서 컴퓨터가 실행할 수 있는 형태로 변환하기 위해 필요함

이들은 코드의 정확성을 검증하고, 최적화된 실행을 가능하게 하여 소프트웨어 개발과 실행 효율성을 높임

컴파일러와 인터프리터 언어의 등장 배경

컴퓨터 언어는 컴퓨터 하드웨어가 이해하고 실행할 수 있는 명령어를 작성하기 위해 등장했음

초기 컴퓨터는 기계어(machine language)로 프로그램을 작성했는데, 이는 매우 복잡하고 오류가 발생하기 쉬웠음

이를 개선하기 위해 어셈블리어(assembly language)가 등장했으며, 이는 기계어에 대한 인간의 이해를 돕기 위해 기호(symbols)와 명령어(opcodes)를 사용했음

 

1950년대에 들어서면서 고급 언어(high-level language)가 개발되기 시작했고, 컴파일러(compiler)를 사용하여 이러한 고급 언어를 기계어로 변환함으로써 프로그래밍의 효율성과 생산성이 크게 향상되었음

컴파일러는 소스 코드를 한 번에 모두 번역하여 실행 파일을 생성함으로써 실행 속도가 빠르다는 장점이 있음

 

한편, 1960년대에는 인터프리터(interpreter) 언어가 등장함

인터프리터 언어는 소스 코드를 한 줄씩 읽고 즉시 실행하는 방식으로 동작함

이러한 방식은 디버깅과 테스트 과정에서 유용하며, 프로그램의 즉각적인 피드백을 제공함

그러나 실행 속도 면에서는 컴파일러 언어에 비해 느릴 수 있음

 

결국, 컴파일러와 인터프리터 언어는 각기 다른 용도와 장점을 가지고 발전해왔으며, 현대에는 많은 언어들이 컴파일러와 인터프리터 방식을 혼합하여 사용하고 있음

예를 들어, Java는 바이트코드(bytecode)로 컴파일된 후, JVM(Java Virtual Machine)에서 인터프리터 방식으로 실행됨으로써 두 방식의 장점을 모두 활용함

특징 비교

특징 컴파일 언어 인터프리터 언어
실행 방식 전체 소스 코드를 한 번에 번역하여 실행 파일 생성 한 줄씩 번역하여 실행
실행 주체 운영체제와 CPU 파이썬 가상 기계(Python Virtual Machine, PVM)
속도 상대적으로 빠름 상대적으로 느림
에러 발견 모든 에러가 컴파일 과정에서 한 번에 발견됨 모든 에러를 한 번에 찾을 수는 없음
한 줄씩 실행시킬 수 있어 에러를 발견한 즉시 수정 및 테스트 가능
배포 기계어 실행 파일 배포 소스 코드 그대로 배포
예시 C, C++, Go 파이썬, 자바스크립트

동작 순서

컴파일러 (Go)

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}
  1. 소스 코드 작성
  2. 어휘 분석
    컴파일러는 소스 코드를 읽고, 이를 작은 단위(토큰)로 나눔
    예를 들어, package, main, import, "fmt", func, main, (), {, fmt.Println, ("Hello, World!"), } 등이 토큰이 됨.
  3. 구문 분석
    토큰들을 문법적으로 분석하여 프로그램 구조를 이해함
    예를 들어, func main() { ... }는 함수 정의라는 것을 이해함.
  4. 중간 코드 생성
    소스 코드를 중간 코드 형태로 변환함
    이 중간 코드는 최적화를 위해 사용됨
  5. 컴파일 에러 처리
    어휘 분석, 구문 분석, 중간 코드 생성 단계에서 발생하는 오류는 오류 메시지를 출력하고 컴파일을 중단함
    예를 들어, 문법 오류, 타입 오류, 선언되지 않은 변수 사용 등이 있음
    문법 오류 발생 시 "./main.go:3:2: undefined: fmt"와 같은 메시지를 출력함
  6. 최적화
    중간 코드를 최적화하여 실행 속도를 높임
    불필요한 부분을 제거하거나 더 효율적인 방식으로 변환함
  7. 기계어 생성
    최적화된 중간 코드를 기계어로 변환함
    기계어는 컴퓨터가 직접 이해하고 실행할 수 있는 코드임
  8. 실행 파일 생성
    최종적으로 기계어로 변환된 코드를 실행 파일로 만듦
  9. 실행 파일 실행
    운영 체제가 이 파일을 로드하고, CPU가 기계어 명령을 직접 실행함
  10. 런타임 에러 처리
    프로그램 실행 중에 발생하는 오류는 운영 체제에 의해 감지되고 보고됨
    예를 들어, 메모리 접근 오류, 논리적 오류 등이 있음

인터프리터 (Python)

print("Hello, World!")
  1. 소스 코드 작성
  2. 어휘 분석
    파이썬 인터프리터는 소스 코드를 읽고, 이를 작은 단위(토큰)로 나눔
    예를 들어, print와 "Hello, World!"가 토큰이 됨
  3. 구문 분석
    토큰들을 문법적으로 분석하여 프로그램 구조를 이해함
    예를 들어, print("Hello, World!")는 함수 호출이라는 것을 이해함
  4. 바이트코드 생성
    구문 분석이 끝난 후, 소스 코드를 바이트코드라는 중간 형태로 변환함
    바이트코드는 소스 코드보다 간단하고 최적화된 형태임
    이 단계에서 파이썬 인터프리터는 .pyc 파일을 생성할 수 있음
  5. 바이트코드 실행
    파이썬 가상 기계(Python Virtual Machine, PVM)는 바이트코드를 읽고, 이를 실행함
    print("Hello, World!") 줄을 바이트코드로 변환하면, PVM은 이 명령어를 해석하고 화면에 "Hello, World!"를 출력함
  6. 에러 처리
    실행 도중 에러가 발생하면 인터프리터는 그 즉시 에러를 보고하고, 해당 줄 이후의 코드는 실행하지 않음

인터프리터 언어에서 가상 기계를 사용하는 이유

  • 이식성
    • 가상 기계는 특정 하드웨어나 운영 체제에 종속되지 않아 바이트코드가 여러 플랫폼에서 동일하게 실행될 수 있음
    • 참고 : 컴파일언어는 특정 하드웨어나 운영체제에 종속됨
      하드웨어에 종속되는 예시 → x86 아키텍처용으로 컴파일된 C 프로그램은 ARM 아키텍처의 컴퓨터에서 실행되지 않음
      운영체제에 종속되는 예시 → 리눅스용으로 컴파일된 C 프로그램은 윈도우 운영 체제에서 실행되지 않음
  • 성능 향상
    • 바이트코드는 소스 코드보다 더 간단하고 최적화된 형태임
    • 가상 기계는 바이트코드를 실행하기 위해 설계된 최적화된 환경을 제공함
    • Just-In-Time (JIT) 컴파일러와 같은 기술을 사용하여 바이트코드를 실행 중에 네이티브 기계어로 변환하고, 이를 캐싱하여 반복 실행 시 성능을 향상시킴
  • 보안 및 안정성
    • 가상 기계는 프로그램의 실행을 제어하고 격리된 환경에서 실행할 수 있어 보안성을 높임
    • 가상 기계는 메모리 관리, 예외 처리, 접근 제어 등의 기능을 제공하여 안정성을 보장함
  • 동적 기능 지원
    • 가상 기계는 동적 타이핑, 동적 코드 실행 등의 기능을 지원할 수 있음
    • 이는 인터프리터 언어의 유연성을 극대화하는 데 도움이 됨

인터프리터 언어가 컴파일 언어보다 실행속도가 느린 이유

  • 실시간 해석
    • 해석 비용
      인터프리터는 프로그램의 각 명령어를 실시간으로 해석함
      소스 코드를 읽고, 해석하고, 실행하는 과정을 반복하기 때문에 추가적인 시간이 소요됨
      반면, 컴파일러는 이 과정을 미리 수행하여 기계어로 번역된 실행 파일을 생성함
    • 반복 작업
      인터프리터는 반복적으로 코드를 해석해야 함
      예를 들어, 루프 안에 있는 코드를 여러 번 실행할 때마다 같은 코드를 반복적으로 해석하고 실행해야 함.
  • 최적화 부족
    • 최적화 수준
      컴파일러는 중간 코드 생성 및 최적화 단계를 통해 프로그램을 더 효율적으로 실행할 수 있도록 최적화함
      반면, 인터프리터는 즉시 실행을 목표로 하기 때문에 최적화 과정이 상대적으로 부족함
  • 바이트코드 및 가상 기계
    • 추가 계층
      일부 인터프리터는 소스 코드를 바이트코드로 변환한 후 이를 가상 기계에서 실행함
      이 경우, 바이트코드를 해석하고 실행하는 추가 계층이 필요하기 때문에 실행 속도가 느려짐
      예를 들어, 파이썬은 소스 코드를 바이트코드로 변환한 후 파이썬 가상 기계(PVM)에서 이를 실행함
  • 동적 타입 검사
    • 타입 검사
      인터프리터는 프로그램 실행 중에 변수의 타입을 검사해야 함
      이 동적 타입 검사는 추가적인 계산 작업을 요구하며, 실행 속도를 저하시키는 요인 중 하나임
      예를 들어, 파이썬과 같은 동적 타이핑 언어에서는 변수의 타입을 실행 중에 결정하고 검사함

 

 

 

 

 

728x90

'Computer Science' 카테고리의 다른 글

지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
Brute force(브루트 포스)란?  (0) 2024.07.09
스택(stack)과 힙(Heap)  (0) 2024.03.27
명령형 프로그래밍 vs 선언형 프로그래밍  (0) 2024.03.02
728x90

Brute force(브루트 포스)란 컴퓨터 과학과 암호학에서 사용되는 용어로, 가능한 모든 경우의 수를 하나씩 대입해가며 해답을 찾는 방법을 의미

이 방법은 주로 암호 해독이나 비밀번호 크래킹 등의 분야에서 사용되며, 무차별 대입 공격이라고도 함

 

브루트 포스 공격은 특정 알고리즘이나 시스템의 취약점을 이용하지 않고 단순히 모든 가능한 조합을 시도함으로써 목표를 달성하는 방식임

쉽게 예를 들면 비밀번호를 찾기 위해 모든 가능한 문자 조합을 하나씩 시도하여 맞추는 경우가 있음

 

브루트 포스의 장점은 시스템이나 알고리즘의 구조에 대한 깊은 이해가 필요 없고, 모든 경우의 수를 시도하기 때문에 성공 확률이 높다는 것임

반면, 단점으로는 매우 많은 시간과 자원이 소모된다는 점이 있음

 

현대의 많은 시스템에서는 이러한 브루트 포스 공격을 방어하기 위해 비밀번호의 길이를 길게 하거나, 복잡한 암호화 알고리즘을 사용함

728x90

'Computer Science' 카테고리의 다른 글

지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
스택(stack)과 힙(Heap)  (0) 2024.03.27
명령형 프로그래밍 vs 선언형 프로그래밍  (0) 2024.03.02

+ Recent posts