update 8.md 9.md
This commit is contained in:
25
notes/8.md
Normal file
25
notes/8.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Linking
|
||||
|
||||
When Calling Functions in Other Files, We Need to Link Them Together. Because Caller do know how to pass data by calling convention, but do know where the callee is located in memory.
|
||||
|
||||
## Why Linker Needed?
|
||||
|
||||
* Modularity
|
||||
* Efficiency
|
||||
* Time: Seperate Compiliation
|
||||
* Space: Libraries
|
||||
|
||||
## What do Linker do?
|
||||
|
||||
1. Symbol Resolution
|
||||
2. Reloacation
|
||||
|
||||
## 3 Types of Object
|
||||
|
||||
1. Relocatable Object File (`*.o`)
|
||||
2. Executable File (`a.out`)
|
||||
3. Shared Object File (`*.so`)
|
||||
|
||||
|
||||
## ELF* Executable and Linkable Format
|
||||
|
||||
203
notes/9.md
Normal file
203
notes/9.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Exception
|
||||
|
||||
An Exception is a **transfer of control** to the OS kernel in response to some event(like div by 0, overflow, ctrl+C). that is change in processor state.
|
||||
|
||||
**Exception Tables**
|
||||
|
||||
Each type of event has an unique exc number `k`: `k` is index into **exception table(interrupt vector table)**
|
||||
|
||||
Handler `k` is called each time exception `k` occurs.
|
||||
|
||||
## Asyncronous exceptions
|
||||
|
||||
It is caused by external events. Handler returns to next instruction.
|
||||
|
||||
for example: Timer interrupt, I/O interrupt.
|
||||
|
||||
## Syncronous exceptions
|
||||
|
||||
It is caused by events that occur as a result of exxecuting an current instruction.
|
||||
|
||||
* Traps
|
||||
* Intentional like procedure calls (e.g. system calls)
|
||||
* Returns to next instruction
|
||||
* Faults
|
||||
* Unintentional but possibly recoverable (e.g. page fault(recoverable), protection fault(not recoverable), floating point exception)
|
||||
* re-executes by kernel or aborts
|
||||
* Aborts
|
||||
* Unintentional and not recoverable (e.g. illegal instruction, parity error, machine check)
|
||||
* Aborts the program
|
||||
|
||||
## System Calls
|
||||
|
||||
Each x86-64 system call has a unique syscall number.
|
||||
|
||||
| Num | Name | Desc |
|
||||
| --- | ------ | --------------- |
|
||||
| 0 | read | read file |
|
||||
| 1 | write | write file |
|
||||
| 2 | open | open file |
|
||||
| 3 | close | close file |
|
||||
| 4 | stat | get file status |
|
||||
| 57 | fork | create process |
|
||||
| 59 | execve | execute program |
|
||||
| 62 | kill | send signal |
|
||||
|
||||
## Fault Example
|
||||
|
||||
### Page Fault
|
||||
```c
|
||||
int a[1000];
|
||||
main() {
|
||||
a[500] = 13;
|
||||
}
|
||||
```
|
||||
In this situation, a page containing `a[500]` is currently on disk, so page fault occurs, CPU cannot find the data in physical RAM. So kernel copy page from disk to memory, and return and re-executes the instruction `movl`
|
||||
|
||||
### Invalid Memory Ref
|
||||
|
||||
```c
|
||||
int a[1000];
|
||||
main() {
|
||||
a[5000] = 13;
|
||||
}
|
||||
```
|
||||
|
||||
In this situation, address `a[5000]` is invalid, so protection fault occurs, kernel terminates the program by sending `SIGSEGV` signal to the user process. Then user process exits with error code `Segmentation Fault`.
|
||||
|
||||
|
||||
## Process
|
||||
|
||||
An instance of a running program.
|
||||
|
||||
Process provides each program with two key abstractions:
|
||||
* Logical control flow
|
||||
* Each program seems to have **exclusive use of the CPU** provided by **context switching** of the kernel
|
||||
* Private address space
|
||||
* Each program seems to have **exclusive use of main memory** provided by **virtual memory** of the kernel
|
||||
|
||||
But in reality, computer runs multiple processes simultaneously by time-sharing CPU and multiplexing memory.
|
||||
|
||||
### Multiprocessing
|
||||
|
||||
Single processor executes multiple processes concurrently. process execution interleaved by time-slicing. Address spaces managed by virtual memory system. And register values for non-executing processes saved in memory.
|
||||
|
||||
Multicore processor share main memory each can execute a separate process. scheduling of processors onto cores done by kernel.
|
||||
|
||||
### Concurrent Processes
|
||||
|
||||
Concurrency is **not at the exact same time**.
|
||||
|
||||
Two processes are **concurrent** if their flows **overlap in time**. Otherwise, they are **sequential**.
|
||||
|
||||
Control flows for concurrent processes are pysically disjoint in time. But user think that they are logically running in parallel.
|
||||
|
||||
* Execution time of instruction may vary because of the Nondeterminism of the System: OS scheduling, Interrupts, Cache miss or Page fault, I/O device delays.
|
||||
|
||||
### Context Switching
|
||||
|
||||
Prcess are managed by a shared chunk of memory-resident OS code called the **kernel**.
|
||||
|
||||
What is important is that the kernel is **not a seprate process**. It is invoked by processes when they need OS services, or when exceptions occur. That is Part of the processor.
|
||||
|
||||
Control flow passes via a context switching.
|
||||
|
||||
## Syscall Error Handling
|
||||
|
||||
On error, Linux sys level function typically returns `-1` and sets the global variable `errno` to indicate the specific error.
|
||||
|
||||
Hard and fast rule:
|
||||
* You must check the return status of every system-level function
|
||||
* Only exception is the handful of functions that return void
|
||||
|
||||
Error reporting functions:
|
||||
```c
|
||||
void unix_error(char *msg) {
|
||||
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
|
||||
exit(0);
|
||||
}
|
||||
```
|
||||
|
||||
Error handling wrappers:
|
||||
```c
|
||||
pid_t Fork(void) {
|
||||
pid_t pid;
|
||||
if ((pid = fork()) < 0) unix_error("Fork error");
|
||||
return pid;
|
||||
}
|
||||
```
|
||||
|
||||
## Creating and Terminating Processes
|
||||
|
||||
* `pid_t getpid(void)` returnes pid of current process
|
||||
* `pid_t getppid(void)` returns pid of parent process
|
||||
|
||||
We can think of a process as being in one of three states:
|
||||
* Running
|
||||
* Executing or waiting to be executed
|
||||
* Stopped
|
||||
* Process execution is suspended and will not be scheduled until futher notice
|
||||
* Terminated
|
||||
* Stopped permanently
|
||||
|
||||
### Terminating Processes
|
||||
|
||||
1. `return` from `main`
|
||||
2. call `exit(status)` function
|
||||
3. Receive a termination signal
|
||||
|
||||
```c
|
||||
void exit(int status);
|
||||
```
|
||||
|
||||
### Creating Process
|
||||
|
||||
Parent process can creates a new running child process by calling `fork()` system call.
|
||||
|
||||
```c
|
||||
int fork(void);
|
||||
```
|
||||
|
||||
it returns `0` to the newly created child, and returns **child's pid** to the parent.
|
||||
Child is almost identical to parent: child get an identical copy of the parent's virtual address space, file descriptors, and process state.
|
||||
But child has its own unique pid.
|
||||
|
||||
```c {cmd=gcc, args=[-O2 -x c $input_file -o 9_1.out]}
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
int main() {
|
||||
pid_t pid;
|
||||
int x = 1;
|
||||
pid = fork();
|
||||
if (pid == 0) { /* Child */
|
||||
printf("child: x=%d\n", ++x);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("parent: x=%d\n", --x);
|
||||
exit(0);
|
||||
}
|
||||
```
|
||||
|
||||
```sh {cmd}
|
||||
while ! [ -r 9_1.out ]; do sleep .1; done; ./9_1.out
|
||||
```
|
||||
|
||||
Concurrent execution of parent and child processes. `fork` duplicates but separates address space.
|
||||
File descriptors are shared between parent and child like `stdout`, `stderr`.
|
||||
|
||||
Modeling fork with Process Graphs
|
||||
* Each vertex represents a process state
|
||||
* Directive Edges represent is ordering of execution.
|
||||
* Edge can be labeled with current value of variables
|
||||
|
||||
Any topological sort of the graph corresponds to a feasible total ordering.
|
||||
|
||||
|
||||
### Reaping Child Processes
|
||||
|
||||
When a child process terminates, it becomes a **zombie** until its parent calls `wait` to read its exit status.
|
||||
|
||||
## execve
|
||||
|
||||
Reference in New Issue
Block a user