[전체 챕터 요약]
Chap3 에서는 두개의 기계어에 대해서 다룸 Intel IA32, x86-64(IA32의 64bit 확장판. AMD에 의해 최초로 개발되었음)
Chap3에 Procedures 부분. 읽어볼만 할듯(Stack frame에 관한 내용). Buffer overflow vulnerabilities
Chap6에서는 디스크 같은 입출력 장치에 대해 더 살펴봄 Memory Hierarchy
Chap6 에서 DRAM같은 메모리 기술이 어떻게 작동하는지, 어떻게 메인메모리로 결합이 되는지 설명해줌
Chap6 에서 캐쉬 메모리에 대해서 더 다루고 어떻게 얘를 활용하는지도 알려줌
process 추상화는 저수준의 하드웨어와 운영체제 소프트웨어 사이에 긴밀한 협력
이 필요한데 이게 어떻게 작동하는지 Chap8에서 배우게 됨. 어플리케이션이 어떻게 프로세스를 생성하고 제어하는지 또한도
Chap9. Virtual Memory(Process가 가지고 있는 가상 메모리 공간. 운영체제에서 제공하는 추상화. 메인 메모리를 너만 쓰고 있어라는 착각을 제공하게 하는)
Virtual memory가 작동하기 위해서는 하드웨어와 운영체제 간에 정교한 상호작용이 필요함(hardward의 모든 주소의 변환). 이러한 작용들을 다룸
Chap12. How to write threaded program
컴퓨터 시스템은 하드웨어와 소프트웨어로 이루어져 있고 application prgoram을 돌리기 위해 서로 협업을 함. 특정 부분의 구현은 시간에 따라 달라질 수 있으나 전체적으로 기반하는 개념은 바뀌지 않는다.
간단한 Hello World 프로그램으로 살펴보는 전반적인 흐름1. 소스 코드 작성2. 컴파일(Chap7 linking)컴파일 시스템이 동작하는 방식에 대해 이해하면 좋은점3. shell에서 해당 executable object file을 실행 ( processor가 메모리에 저장된 instruction을 읽고 이해한다 )Hardware Organization of a SystemRunning the hello Program캐쉬는 중요하다메모리 계층도운영체제는 하드웨어를 관리함Processes (Chap 8)Threads (Chap12 에서 concurrency program 작성법 배움)Virtual Memory (Chap 9)Files ( Chap 10 )네트워크를 이용한 다른 시스템과의 통신Important ThemesConcurrency and ParallelismThread-Level ConcurrencyInstruction -Level ParallelismSingle-Instruction, Multiple-Data(SIMD) ParallelismThe Importance of Abstractions in Computer Systems
간단한 Hello World 프로그램으로 살펴보는 전반적인 흐름
1. 소스 코드 작성
#include <stdio.h> int main(){ printf("hello, world\n"); }
- 프로그래머가 작성하는 코드는 텍스트 파일이지만 결국 byte의 집합임(ASCII 코드를 통해 각각의 문자가 integer 값으로 매핑되고 해당 integer값이 byte로 저장)
- 텍스트 파일이 아닌 모든 다른 파일들은 binary files
- 시스템의 모든 정보들(disk files, 메모리에 저장되어 있는 프로그램, 메모리에 저장되어 있는 유저 정보, network에 의해 전송되는 데이터)은 bit의 덩어리로 표현된다. 다른 데이터 오브젝트들과 구분되게 만드는 점은 우리가 그것을 보는 맥락에 따라 다른 것임
2. 컴파일(Chap7 linking)
- 우리가 작성한 코드를 시스템에서 돌리기 위해서는 해당 코드를 저수준의 기계어 instruction sequence로 번역을 해야 함
- 이 기계어 instruction의 sequence는 그 후 패키징이 되게 되는데 이를 executable object program(=executable object files) 라고 하고 binary disk file로 저장됨
gcc -o hello hello.c
컴파일 시스템이 동작하는 방식에 대해 이해하면 좋은점
- 프로그램의 성능을 최적화 할 수 있음. 컴파일러가 어떻게 해당 코드를 기계어로 번역하는지를 이해하면 더 좋은 성능이 어떤 코드인지를 알 수 있음
- switch 가 if else보다 나은지
- while loop 가 for loop 보다 효율적인지
- link-time error를 이해할 수 있다 ( Chap 7 )
- linker가 reference를 찾을 수 없다고 할 때 그게 무슨 의미인지
- static variable과 global variable의 차이
- static library ↔ dynamic lib 의 차이
- 보안 구멍을 피할 수 있다
- buffer overflow vulnerabilites는 계속해서 존재해 왔다.
- secure programming의 첫 단계는 데이터와 제어정보가 프로그램 스택에 쌓이는 것의 결과에 대해 이해하는 것임 (Chap 3)
3. shell에서 해당 executable object file을 실행 ( processor가 메모리에 저장된 instruction을 읽고 이해한다 )
unix> ./hello hello, world unix>
- executable file을 Unix 에서 실행시키려면 shell이라는 어플리케이션 프로그램에 위와 같이 입력
- shell이 해당 executable file을 load하고 실행시키게 됨
- hello program을 실행시켰을 때 어떤 일이 일어나는지 알기 위해서는 Hardware Organization 을 이해해야 함
Hardware Organization of a System

Buses
- 정보의 바이트를 컴포넌트 사이에 옮겨다닐 수 있게 하는 통로
- 보통 버스는 고정된 사이즈의 바이트(words)를 전달하도록 디자인 되어 있음
- word는 보통 4바이트임
I/O Devices
- I/O 장치는 시스템이 외부세계와 연결할 수 있는 통로임
- 예제에서는 4개의 I/O 장치가 존재함
- 키보드
- 마우스
- 모니터
- 디스크 드라이브(data나 프로그램의 장기간 저장소)
- 예제의 hello 프로그램 또한 처음에는 디스크 드라이브에 상주하고 있음
- 각각의 입출력 장치는 I/O 버스에 controller나 adapter를 통해서 연결이 됨
- 둘의 차이는 packaging의 한 종류인 것임
- 둘의 목적은 결국 I/O 버스와 입출력 장치 간에 데이터를 전달하는 것
Main Memory
- 프로그램과 데이터(프로세서가 프로그램을 실행할 시 조작하는 데이터)를 보유하는 임시 저장 장치
- 물리적으로, 메인메모리는 DRAM(Dynamic Random Access Memory)의 집합으로 구성되어 있음
- 논리적으로, 메모리는 byte의 선형 배열로 조직되어 있고 각각은 고유한 주소(0부터 시작하는)를 가지고 있음
- 프로그램을 구성하는 기계어 instruction들 또한 byte로 구성되어 있음
Processor(=Central Processing Unit(cpu))
- 메인메모리에 저장되어 있는 기계어 instruction들을 이해하고 실행시키는 엔진임
- 코어에는 program counter(PC)라고 불리는 word-sized 저장소(or register)가 존재함
- 어떠한 시점에도 PC는 메인 메모리에 존재하는 기계어 instruction의 주소를 가리킴(혹은 포함함)
- 시스템에 파워가 공급되는 순간부터 꺼지는 순간까지 계속해서 processor는 반복적으로 PC 가 가리키는 기계어 instruction을 실행하고 다음 instruction을 가리키도록 업데이트함
- 메모리의 instruction(PC가 가리키는)을 읽고
- instruction의 bit를 이해하고 & 수행
- PC 의 값을 다음 실행 주소로 업데이트
- register file : word 사이즈의 register의 집합으로 구성된 작은 저장 장치
Running the hello Program
- shell에 ./hello를 입력 → shell 프로그램은 각각의 단어를 읽어서 register로 옮기고 이를 메모리에 저장함
- enter를 입력 → shell이 실행가능한 hello 파일을 로드하여 코드와 데이터를 디스크로부터 메인메모리로 옮김
- 데이터는 출력될 “hello, world\n” 를 포함함
- direct memory access라는 기법을 사용하여 data는 디스크로부터 메인메모리로 바로 전달됨. 프로세서를 거칠 필요 없이
- 메인메모리로 코드와 데이터가 옮겨지고 난 다음에는 프로세서가 기계어 지시들을 하나씩 실행시킴
- 여기에서 메인 메모리에 존재하는 “hello, world\n” 를 복사하여 레지스터 파일로 옮기고 거기서 디스플레이 장치로 다시 옮기게 됨
여기서 보면 정보가 이리 저리 옮겨 다니면서(메인메모리, processor, I/O device 사이에서) 시간을 소모하는 부분이 꽤나 많음 → cache가 도입됨
캐쉬는 중요하다
- 위의 사례에서 보면 hello 프로그램을 디스크에 저장되어 있던 것을 메인 메모리로 옮기고 또 메모리에서 processor로 옮기는 작업들이 꽤나 많은 부분을 차지함
- 그래서 이러한 복사 작업을 가능한 한 빨리 만드는 것이 시스템 디자이너의 목표였음
- 또한 프로세서는 register file(word-sized register의 집합으로 이루어져 있음)에서 데이터를 읽을 때 메인 메모리에서 읽는 것보다 100배는 빠름
- 반도체 기술이 발전함에 따라 프로세서가 더 빠르게 실행되도록 하는 것이 메인 메모리를 빠르게 하는 것보다 더 값이 싸짐 → 이것이 processor-memory gap
- processor-memory gap을 다루기 위해 시스템 디자이너들은 더 작고 더 빠른 cache memory라는 저장 장치를 만듦( 프로세서가 빠른 기간 내에 사용할 것이라고 생각되는 정보들을 모아두는 임시 저장 공간 )
⇒ 위의 2가지 이유들 때문에 cache 메모리가 도입됨

- processor 칩에 있는 L1 캐쉬는 수만 바이트를 저장할 수 있고 register file 만큼이나 빠르게 접근이 가능함
- L2 cache는 수십만~수백만 바이트 저장가능하고 processor와 특별한 bus를 이용하여 연결되어 있음
- L1, L2 cache는 static random access memory(SRAM)으로 구현되어 있음
- 캐시에 숨어있는 아이디어는 locality를 이용한 매우 크면서 매우 빠른 효과를 동시에 얻을 수 있는 메모리라는 것임
- locality : 프로그램이 데이터와 코드에 접근할 때 주변의 범위에 대해서 접근하는 경향
메모리 계층도

- 메모리 계층구조의 주요한 아이디어는 어느 한 레벨의 저장소가 그다음 레벨 저장소의 캐쉬역할을 한다는 점임. L0(register)는 L1의 캐쉬, L1은 L2에 대한 캐시…
운영체제는 하드웨어를 관리함
- 쉘이 hello 프로그램을 로드하고 실행할 때, hello 프로그램이 메시지를 출력할 때 프로그램은 키보드, 디스플레이, 디스크, 메인 메모리에 직접적으로 접근하지 않음. 대신 운영체제에서 제공되는 서비스에 이를 맡김
- 운영체제를 어플리케이션 프로그램과 하드웨어 사이의 소프트웨어라고 생각할 수 있음
- 어플리케이션에서 하드웨어를 조작하고자 하는 모든 시도들은 다 운영체제를 통해서 실행됨


운영체제의 주요 목적
- 어플리케이션의 하드웨어에 대한 잘못된 사용을 보호하기 위함
- 복잡하고 되게 다른 저수준의 하드웨어 기기들을 간단하고 균일한 메커니즘으로 작동시키기 위하여
- 운영체제는 근본적인 추상화(Processes, Virtual Memory, Files)를 통해서 위의 2가지 목적을 달성함
- files are abstractions for I/O device
- virtual memory is an abstraction for both the main memory & disk I/O device
- processes는 processor, main memory와 입출력 장치에 대한 추상화
Processes (Chap 8)
- 앞에서 실행했던 hello 프로그램 같은 경우, 운영체제는 해당 프로그램이 시스템에서 실행 중인 유일한 프로그램이라는 일종의 illusion을 제공함 ⇒ 이를 process라는 개념으로 제공함
- processor, main memory, I/O 장치 들에 대한 독점적인 사용을 하고 있다고 생각하도록
- 프로세서는 프로그램의 instruction만을 실행하고 있고, 프로그램의 코드와 데이터가 시스템 메모리에 유일하게 올라가 있다고 생각되도록
- 프로세스는 실행중인 프로그램에 대한 운영체제의 추상화임
- 다수의 프로세스는 하나의 시스템에서 concurrent하게 돌아갈 수 있는데 각각의 프로세스는 하드웨어에 대한 독점적인 사용을 하고있는 것 처럼 보이게 함
- Concurrently : 하나의 CPU가 다수의 프로세스를 동시적으로 실행하는 것인데, 이를 위해서는 프로세스 간에 전환이 필요하고 이를 context switching이라고 함
- Context : 운영체제는 프로세스를 실행시키기 위해 필요한 모든 상태정보를 가지고 있는데 이를 context 라고 함
- PC(Program counter)
- register file
- contents of main memory
- 어떠한 시점에도 하나의 프로세서는 하나의 프로세스의 코드만을 실행할 수 있음
- Context switching: 운영체제가 현재 프로세스에서 새로운 프로세스로 전환하려고 할 때, 현재 프로세스의 context를 저장하고 새로운 프로세스의 context를 회복하는 과정을 말함. 새로운 프로세스는 그 이전에 중단되었던 그 지점부터 실행함
- shell process에 hello를 실행하라고 입력했을 때, system call이 호출되면서 운영 체제에 제어권이 넘어감
- 운영 체제가 shell의 context를 저장하고 새로운 hello 프로세스와 그 컨텍스트를 만들고 제어권을 그 hello 프로세스에게 넘겨줌
- hello 프로그램이 종료되면 운영체제는 shell 프로세스의 context를 회복하고 제어권을 다시 그쪽으로 넘겨줌(다음 커맨드 라인 입력을 기다리는 shell)

Threads (Chap12 에서 concurrency program 작성법 배움)
- 현대의 시스템에서 프로세스는 다수의 실행 유닛을 가질 수 있는데 이를 Thread라고 함
- 각각의 Thread는 프로세스의 context에서 수행되고 같은 code와 global data를 공유함
- Thread는 점차 더 중요해지고 있음. 그 이유는 network server에서의 concurrency에서 multiple thread사이에 정보 공유가 multiple process사이의 정보 공유보다 쉽기 때문임
Virtual Memory (Chap 9)
- Virtual Memory는 프로세스 마다 메인 메모리에 대해 독점적인 사용을 하고 있다고 생각하게 만드는 추상화임
- 각각의 프로세스는 메인 메모리에 대해 다 같은 균일한 view를 가지게 되는데 이를 virtual address space라고 함 → 독점적으로 사용하고 있다고 생각하게 만듬
- virtual memory가 동작하기 위해서는 하드웨어와 운영체제 사이에 정교한 interaction이 필요함
- Program code and data
- Code는 모든 프로세스에 대해서 똑같은 고정주소에서 시작함
- 그리고 global 변수들에 해당하는 data들이 그 뒤를 따라옴
- code와 data는 executable object file로 부터 바로 초기화 됨
- Heap
- code and data 영역은 프로세스가 시작될 때 사이즈가 고정되는데 반해, run-time heap 영역은 런타임에 동적으로 바뀌게 됨 (C에서는 malloc 과 free를 통해 바뀜)
- Shared Libraries
- 주소 공간의 중간 즈음에 shared library를 위한 코드와 데이터들이 위치하고 있음
- 예를 들어 C standard library와 math library 같은 라이브러리가 존재함
- Stack(Chap3)
- user의 virtual address space의 top에 위치함
- 함수를 호출할 때 컴파일러가 사용하는 주소 공간임
- 힙과 마찬가지로 user stack은 프로그램 실행 중에 동적으로 확장됨
- 함수를 호출할 때 마다 stack은 자라나게 되고, 함수로부터 return할 때 줄어듬
- Kernal virtual memory
- kernel은 운영체제의 일부분으로 메모리에 항상 상주하고 있음
- 모든 프로세스에 공통적인 운영체제의 코드와 데이터가 있음
- Virtual address space의 가장 윗부분은 kernel을 위한 점유공간임
- 어플리케이션 프로그램은 이 공간을 읽거나 작성할 수 없고 kernel code의 함수를 호출할 수도 없음

Files ( Chap 10 )
- byte의 연속임. 그 이상도 그 이하도 아니다
- 모든 입출력 장치(disk, 키보드, 디스플레이, 네트워크)는 모두 file로 모델링 됨
- 시스템의 모든 input과 output은 Unix I/O라는 시스템 콜을 이용하여 file을 읽고 쓰는 방식으로 수행됨
- 간단하고 우아한 파일이라는 개념으로 인해 어플리케이션은 일관적인 interface를 통해 다양한 입출력 장치에 대해 동작할 수 있음
네트워크를 이용한 다른 시스템과의 통신
- 네트워크 또한도 그냥 또 다른 I/O 장치라고 생각할 수 있음
Important Themes
Concurrency and Parallelism
Thread-Level Concurrency
- 스레드를 이용하면, 하나의 프로세스안에서도 여러 개의 제어 흐름을 가져갈 수 있다
Instruction -Level Parallelism
- 현대 프로세서들은 한번에 여러 개의 instruction을 처리할 수 있고 이를 instruction-level parallelism이라 함
Single-Instruction, Multiple-Data(SIMD) Parallelism
- 많은 현대 프로세서들은 한번의 instruction으로 여러 operation을 병렬적으로 수행하도록 할 수 있음 → single-instruction, multiple-data
The Importance of Abstractions in Computer Systems
- computer science에서 추상화는 가장 중요한 컨셉 중 하나임
- 예를 들어, 좋은 코딩 면모 중 하나는 함수를 위한 간단한 API를 구성하는 것. 사용자가 그 안을 다 알 필요없이 사용할 수 있도록