[CS:APP]컴퓨터 시스템

IKNOW·2024년 6월 9일

컴퓨터 시스템은 하드웨어와 시스템 소프트 웨어로 구성된다.

이 둘은 서로 협력하여 응용 소프트웨어를 실행한다.

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

정보는 비트와 컨텍스트로 이루어진다.

hello 프로그램은 hello.c라는 파일에 저장된다.

소스 파일은 0 또는 1로 이루어진 비트의 시퀀스이며, 바이트라는 8비트 단위로 구성된다.

대부분의 컴퓨터 시스템은 텍스트 문자를 ASCII표준을 사용하여 표시한다.

hello.c 처럼 오직 ASCII 문자로만 이루어진 파일을 텍스트 파일이라고 부르며,
다른 모든 파일은 바이너리 파일이라고 한다.

프로그램은 다른 프로그램에 의해 다른 형태로 번역된다.

hello 프로그램은 인간이 읽고 이해할 수 있으므로 고급 C프로그램으로 일생을 시작한다.

컴퓨터 시스템에서 hello.c를 실행시키려면 각 문장을 다른 프로그램들에 의해
저급 기계어 인스트럭션(machine language instruction)들로 번역되어야 한다.

이 인스트럭션들은 실행가능 목적 프로그램(executable program)이라는 형태로 합쳐져서 바이너리 파일로 저장된다.

compiler는 UNIX 시스템에서 다음과 같이 소스 파일에서 오브젝트 파일로 번역할 수 있다.

linux > gcc -o hello hello.c

GCC 컴파일러 드라이버는 hello.c 소스파일을 읽어서 hello 실행파일로 번역한다.

번역은 4단계를 거치는데 이 4단계를 컴파일 시스템이라고 한다.

flowchart LR

	pp["Pre-processor(cpp)"]
	comp["Compiler(cc1)"]
	assem["Assembler(as)"]
	linker["Linker(ld)"]
	
	start[" "] --hello.c--> pp
	pp --hello.i--> comp
	comp --"hello.s"--> assem
	assem --"hello.o"--> linker
	linker --"hello"--> endee[" "]
  • 전처리 단계: CPP (전처리기) C프로그램을 #문자로 시작하는 directive에 따라 수정한다.
    그 결과로 .i로 끝나는 새로운 C 프로그램이 생성된다.
  • 컴파일 단계: cc1 컴파일러는 텍스트 파일 hello.i를 hello.s로 번역하고 이 파일에는 어셈블리어 프로그램이 저장된다.
main:
	subq $8, %rsp
	movl $.LCO, $edi
	call puts
	movl $0, $eax
	addq $8, %rsp
	ret

어셈블리어는 여러 상위수준 언어의 컴파일러들을 위한 공통의 출력언어를 제공하기 때문에 유용하다.

  • 어셈블리 단계: as 어셈블러가 hello.s를 기계어 인스트럭션으로 번역하고 이들을 재배치 가능 목적 프로그램의 형태로 묶어서 hello.o라는 목적파일에 저장한다.
  • 링크단계: hello 프로그램은 C컴파일러에서 제공하는 표준 C 라이브러리에 들어있는 printf함수를 호출한다.
    printf함수는 이미 printf.o에 들어있으며, hello.o파일과 결합되어야 한다. ld 링커 프로그램이 이 작업을 수행한다. 그 결과로 hello 파일은 실행파일로 메모리에 적재되어 실행될 수 있다.

프로세서는 메모리에 저장된 인스트럭션을 읽고 해석한다.

linux> ./hello
hello, world
linux>

쉘은 커맨드라인 인터프리터로 프롬프트를 출력하고 명령어 라인을 입력받는다.

명령어 라인이 내장 쉘 명령어가 아니면 쉘은 실행 파일의 이름이라고 판단하고 해당 파일을 실행한다.

hello 프로그램이 실행될 때 전형적인 시스템에서 하드웨어 조직을 이해할 필요가 있다.

  • Bus: 시스템을 관통하는 배선, 컴포넌트간 바이트 정보를 전송한다. 일반적으로 word라고 하는 고정 크기 바이트 단위로 데이터를 전송한다. 대부분의 컴퓨터는 4바이트, 8바이트 워드 크기를 갖는다.
  • IO: 시스템과 외부 세계를 연결한다.
  • 메인 메모리: 프로세서가 프로그램을 실행하는 동안 데이터와 프로그램을 모두 저장한다. 논리적으로 메모리는 연속적인 바이트의 배열로 0부터 시작하는 고유 주소를 갖고 있다.
  • 프로세서: CPU 또는 프로세서는 메인 메모리에 저장된 인스트럭션을 해동하는 엔진이다. 중심에 워드 크기의 저장장치인 프로그램 카운터(PC)가 있다. PC는 메인 메모리의 기계어 인스트럭션을 가리킨다.

프로세서는 PC가 가리키는 인스트럭션을 반복적으로 실행하고, PC가 다음 인스트럭션의 위치를 가리키도록 업데이트 한다.

이러한 단순한 동작들은 메인 메모리, 레지스터파일, 수식/논리 처리기 주위를 순환한다. 레지스터 파일은 각각 고유의 이름을 갖는 워드 크기의 레지스터 집합으로 구성되어 있다.

  • 적재(Load): 메인 메모리에서 레지스터에 복사한다.
  • 저장(Store): 레지스터에서 메인 메모리로 복사한다.
  • 작업(Operate): 두 레지스터 값을 ALU로 복사하고, 수식 연산을 수행한 뒤, 결과를 레지스터에 저장한다.
  • 점프(Jump): 인스트럭션에서 워드를 추출하고 PC에 복사한다.

Hello 프로그램의 실행

./hello 를 쉘에 입력하면 쉘 프로그램은 각 문자를 레지스터에 읽어 들인후 메모리에 저장한다.

키보드에서 엔터키를 누르면 쉘은 파일 내의 코드와 데이터를 복사하는 인스트럭션을 실행하고 실행파일 hello를 디스크에서 메인 메모리로 로딩한다.

hello 파일의 코드와 데이터가 메모리에 적재되면, 프로세서는 hello 프로그램의 main 루틴의 인스트럭션을 실행한다.

이 인스트럭션 들은 스트링을 메모리에서 레지스터로 복사하고 레지스터에서 디스플레이로 전송하여 화면에 글자가 표시된다.

profile
조금씩,하지만,자주

0개의 댓글