Control Flow 제어흐름
일반적인 컴퓨터는 프로그램이 시작하면(전원을 공급하는 순간부터) startup 에서 shutdown 으로 순차적으로 진행이 되고 끝난다.
이 과정에서 CPU 는 명령어를 한 번에 한 개씩 수행할 수 있는데(제어이동), 이를 CPU's control flow 라고 한다.
interpret a sequence of instructions, one at a time
Control flow가 바뀌는 요인
지금까지 배웠던 컨트롤 흐름을 바꾸기 위한 두 개의 메커니즘 :
1. jumps and branches 와 같은 분기 명령어
- return address 를 저장해두고, jmp의 주소로 pc 업데이트, 실행 후 저장된 주소로 돌아온다.
2. 함수 call and return 명령어
- 서브루틴을 호출하는 경우
- 정해진 곳으로 PC가 이동하게 된다. 프로그램 상태의 변화에 반응하는 것이다.
"흐름제어가 바뀌었다" 라고 한다.
→ 사용자 모드에서 프로그램의 상태 (state) 를 바꿀 뿐 시스템 모드의 상태를 바꿀 수는 없다.
시스템은 위처럼 명령어로 인한 프로그램 상태변화가 아닌, 프로그램의 실행과는 관계없는 시스템 상태 변화에도 반응할 수 있어야 한다.
시스템 상태 변화가 필요한 경우
1. 시스템 타이머가 만료된 경우
2. 디스크나 네트워크 어댑터에서 데이터를 가져올 경우 ( 시스템 자원 사용)
3. 2와 비슷한 경우로, 데이터가 디스크에 존재할 때
4. page fault
→ 프로그램 사체가 할 수 있는 범위를 넘어선다. 이를 간접적으로 해결하기 위해 예외 상황 발생 시 OS에게 제어권을 넘겨 처리할 수 있다.
예외상황 제어 흐름을 알아보기 이전에 , 듀얼모드의 동작방식을 대략적으로 알아보고자 한다.
User and Kerner Modes
프로세서는 우선순위를 특정짓는 제어 레지스터에 mode bit 를 전달한다.
유저/사용자 모드
- mode bit 가 세팅되지 않았을 대
- 사용자의 접근 영역을 제한적으로 두고, 프로그램 자원에 함부로 접근하지 못하도록 한다.
- 하드웨어 직접 접근 불가능
- 코드 작성, 프로세스 실행 명령 등 실행 가능
커널모드
- full privileges 실행 → 모든 CPU 명령 실행 가능
- 운영체제 코드나 디바이스 드라이버 같은 커널모드 코드가 실행된다.
Rings
x86 CPU는 각기 다른 우선권을 ring 3개로 분류한다. 대부분의 운영체제는 ring 0 과 3만을 사용한다.
ring 0 : OS kernel
ring 1, 2 : device drivers
-----------------------------------
ring 3 : user
Q. 시스템에 듀얼 모드가 필요한 이유는? ( 사용자/커널 모드의 필요성)
사용자 모드와 커널모드로 나뉘는 이 모드는 시스템의 안정성과 보안을 보장하는 데 필수적이다. 듀얼 모드를 통해 프로그램 실행이 하드웨어와 시스템 자원을 직접 제어하지 못하도록 제한하면서, 커널을 시스템 리소스를 안전하게 관리할 수 있다.
1. 명령어의 우선순위 지정
- 커널 모드에서만 사용 가능한 명령어
커널 모드에서는 하드웨어와 시스템 자원을 제어할 수 있는 특수한 명령어가 존재한다
ex) 인터럽트를 (비)활성화하는 명령어, 프로세서 동작 정지 명령어, mode bit 변경, I/O 장치 초기화 명령어
2. 메모리 접근 권한
- 유저모드에서 실행되는 프로그램은 커널 메모리 영역에 접근할 수 없고, 유저 코드가 커널을 수정하지 못하도록 해야 한다. 이는 프로그램이 실수 또는 악의적으로 커널 영역을 변경하거나 손상시키는 것을 방지하는 중요한 보호 장치이다.
- 커널 메모리에 only read/write 만 가능하도록 해야한다.
3. 하드웨어 접근 권한
- 오직 커널모드에서만 하드웨어 장치와 직접적으로 상호작용 할 수 있다. ex)timer interrupt 설정해, 일정 시간이 지나면 현재 실행 중인 프로세스를 중단하고 다른 프로세스가 실행될 수 있도록 강제한다.
4. timer interrupt 및 프로세스 스위칭
- 커널에 의해서만 세팅 가능하다. 시스템에서 실행 중인 프로세스가 주기적으로 전환되도록 swtich 를 강제한다.
Exceptinal Control Flow 예외적인 제어흐름
예외상황 : 어떤 프로세서 상태 변화에 대한 대응으로, 제어흐름을 변화시키는 상황을 말한다.
- 예외적인 제외흐름의 한가지 형태로써, 특정 이벤트에 대한 반응으로 OS 커널로 제어가 전환되는 것(모드 스위칭)을 의미한다.
ex) I/O request completes, page fault
- 유저모드에서 코드가 작동하다가 이벤트가 발생하면, 예외가 발생했으니 커널로 제어권을 넘겨준다.
- 커널 코드로 넘어가 예외처리 핸들러가 작동하게 된다.
이때, 현재 실행중인 명령어 도중 예외처리 핸들러를 호출하는 게 아닌, 현재 명령어를 끝마친 후에 호출한다.
예외처리 핸들러에서 처리를 끝마치면, 예외 상황을 발생시킨 이벤트 종류에 따라 각기 다른 수행이 이뤄진다.
(원래 위치로 돌아오거나 / 다음 명령어로 가거나 / 유저코드는 멈출 수 있다. )
Exception Table
: 예외들을 모아둔 테이블
- 각각의 예외상황 이벤트 종류마다 고유한 nonnegative 예외번호를 가지고 있다. 예외가 발생한 순서대로 번호가 매겨지게 된다.
- k = 예외테이블에 접근하기 위한 인덱스 ( 각 이벤트 핸들러의 시작주소)
- 핸들러 k는 예외상황 k가 발생할 때마다 call된다.
- 각각의 엔트리에는 k에 대한 핸들러 주소가 저장되어 있다.
0 ~ 31 : 인텔 아키텍쳐에서 정의된 예외 → 모든 x86-64 시스템에서 동일하다.
32 ~ 233 : OS 에서 정의된 인터럽트와 트랩에 대응된다.
프로그램이 power on 된 이후, 운영체제는 jump table을 할당하고, 초기화한다.
예외번호는 테이블의 index로 부여되며 이 jump 테이블의 시작주소를 레지스터에 저장해놓는다. 이후 예외가 발생하면 인덱스 k를 통해 접근 가능한 공간에 예외 핸들러 함수코드의 주소를 세팅할 수 있다. 해당 주소로 jump해 핸들러를 실행할 수 있게 되는 것이다.
테이블의 첫주소를 알면 인덱싱(*8byte) 으로 함수를 실행시킬 수 있다.
특정 명령어의 실행으로 발생한 이벤트가 예외 상황을 유발한다.
예외상황 : interrupt(내부) + exception(외부) (이분법적으로 구분되는 것은 아니다)
Trap, Fault, Abort 예외 - 동기방식
: 프로세스의 명령어 실행에서의 이벤트 발생으로 인한 예외상황
1. Intectional exceptions : Trap
- 커널모드로 전환하기 위한 의도적인 exception 이다. 프로세스가 직접 system call을 호출하는 경우 혹은 이외의 방법으로 OS에 특정 명령어 수행을 요청하는 경우에 발생하는 예외이다.
- 시스템 콜이라고 알려진 사용자 프로그램과 커널 사이의 프로시저와 유사한 인터페이스를 제공한다.
시스템 콜 vs 함수 콜
보통의 함수는 사용자 모드에서 돌아가며, 이들이 실행할 수 있는 인스트럭션은 제한적이다. 이들은 호출하는 함수와 동일한 스택을 사용한다. 반면 시스템 콜은 커널 모드에서 돌아가며, 이로 인해 커널 내에서 정의된 스택에 접근하며, 특권을 가진 인스트럭션을 실행할 수 있도록 해준다.
ex) system calls ... (read / write / open / close / kill ...)
- 커널의 예외핸들러로 넘어가 해당 system call 에 맞는 명령어를 찾는다. 필요한 값을 핸들어에서 반환하면서,
I_next 로 이동해 명령어를 순차적으로 수행한다.
2. Unintentional exceptions and recoverable : faults
- 의도적이진 않지만 잠재적으로 에러를 처리할 수 있을 때 일어난다.
- I_cur or abort
- 에러를 정정할 수 있다면 오류를 발생시킨 인스트럭션으로 돌려주어서 거기서부터 재실행한다. 그렇지 않다면, 핸들러는 커널 내부의 abort 루틴으로 리턴해서 오류를 발생시킨 응용프로그램을 종료한다.
ex) page faults( 가상메모리에 없는 데이터를 프로세스가 요청한 경우) , segment faults
page는 가상메모리의 연속적인 블록 개념!
3. Unintentional exceptions and unrecoverable : aborts
- 에러를 처리할 수 없을 때 일어난다.
- 대개 DRAM이나 SRAM이 고장날 때 발생하는 패리티 에러와 하드웨어 같은 복구할 수 없는 치명적인 에러에서 발생한다. 중단핸들러는 절대 응용프로그램으로 제어를 리턴하지 않는다.
- 프로그램을 abort 한다. ( return 없고 중단 리턴으로 넘겨줌)
ex) illegal 명령어, parity error ...
Interrupt 예외 - 비동기
: 프로세스 바깥의 이벤트로 인해 발생하는 예외
- 인터럽트 핀을 통해 수행된다. CPU 는 프로세스 명령어들을 순차적으로 수행하며, 각각의 명령어를 실행시킨 뒤 핀의 상태를 확인한다 . 이때 핀의 상태값이 high라면(전기신호가 들어오고 있다면) 컨트롤 흐름을 kernel로 넘긴다.
- 명령어 수행이 끝나면 핸들러가 I_next 로 이동해 수행하던 프로세스를 이어 진행한다.
ex) Timer interrupt
프로세서는 한 번에 하나의 프로레스만 실행할 수 있지만, 운영체제 시스템에서는 수 ms 마다, 외부 타이머 작동시켜 여러 프로세스를 time sharing 해 실행한다. 만약 타이머가 다 되면 context switching 을 통해 프로세스를 다른 프로세스로 교체해 준다.
ex) I/O interrupt
- Ctrl+c 눌렀을 경우
- 네트워크로부터 패킷을 받을 때
- 디스크로부터 data sector 를 받을 때
Exception example
Fault Example : Page fault
int a [1000];
main() {
a[500] = 13;
}
정상동작 할 것 같지만, 메모리에 올라가지 않고 디스크에만 존재할 수 있다.
DRAM에 없는 데이터를 프로세서가 요청했기 때문에 page fault 가 발생한다.
이때 일단 프로그램을 잠시 멈추고 커널로 가게 된다. 커널은 디스크나 SSD에 있는 값을 DRAM에 옯겨주고, 프로세스가 마지막으로 수행하려던 명령어( I_current)를 다시 수행하라고 전달한다.
결과적으로 그 전까지는 메모리에 없어서 수행하지 못했으나 다시 수행할 때에는 메모리 값을 얻을 수 있게 되어 page fault 예외상황을 해결할 수 있다.
Invalid memory를 참조한다면?
int a[1000];
main() {
a[2000] =13;
}
상황에 따라서 가상 메모리에서 가져오려는 값이 정작 디스크에 없거나, page fault를 해결하지 못해 abort가 일어날 수도 있다. 위의 상황에서는 배열의 범위를 넘어난 곳에 접근하고 있기 때문에 segmenation fault가 발생하고프로그램이 종료된다.
System Calls : Opening file
: 시스템콜은 커널과의 인터페이스이다.
- 어플리케이션이 운영체제와 소통할 수 있도록 한다.
system call의 필요성
- 시스템 자원을 보호하기 위해서
- reliablity 메모리에 접근하는 프로그램이나 버그가 있는 프로그램을 막기 위함
- security
사용자 호출 : opne (filename , options)
system call - open의 고유한 예외번호인 $0x2 를 레지스터 %rax에 저장한다.
trap 발생으로 커널모드로 모드가 변경된다.
인자의 파일이름이나 옵션(수정,생성 등)은 %rdi, %rsi~~ 레지스터에 저장된다.
리턴값은 %rax에 저장되고, syscall은 보통 error가 많고 -1 or 0이면 에러를 의미한다.
'Major S-T-U-D-Y > System Programming' 카테고리의 다른 글
[시스템 프로그래밍] 8 . Process (0) | 2024.12.19 |
---|---|
[시스템 프로그래밍] 7 (4) How to use Static Library 정적 라이브러리 (0) | 2024.11.26 |
[시스템 프로그래밍] 7. (3) 링킹과정 1단계 : 심볼 해석과 재배치 (0) | 2024.11.26 |
[시스템 프로그래밍] 7. (2) Linking 정적/동적 링킹 과정과 (0) | 2024.11.22 |
[시스템 프로그래밍] 7. Linking (1) 분할컴파일과 extern/static modifier (0) | 2024.11.21 |