# SO Lista 0

---

:::spoiler deklaracja podglad
## Deklaracja
| Zadanie | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|-----------|---|---|---|---|---|---|---|---|
| Deklaracja|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:| | :heavy_check_mark:| | :heavy_check_mark:| :heavy_check_mark:|
:::
## Zadanie 1

* ### Wyjątek procesora `exception`
Nagła zmiana kontroli przepływu (zaimplementowana częściowo przez hardware i częściowo przez system operacyjny) w odpowiedzi na jakąś zmianę w stanie procesora.

Są podzielone na cztery klasy:

* ### Przerwanie sprzętowe `hardware interrupt`
Występuje kiedy po skończeniu wykonania aktualnej instrukcji procesor wykryje stan wysoki na pinie przerwania, odczytuje numer wyjątku z magistrali systemowej i wywołuje odpowiedni handler przerwania.

**Przykłady**:
* requesty I/O (np. sygnał z klawiatury)
* przyjście pakietów sieciowych
* dysk sygnalizujący, przeczytanie seri bloków danych
* ### Pułapka (trap)
Wyjątki uzyskane celowo, `syscall'e`, instrukcje wykonane przez program, gdy potrzebujemy dostępu do usług kernela

**Przykłady**:
* fork
* write
* execve
* exit
* breakpointy w debuggerach
* ### Fault
Wyjątki wywołane przez błędy, które `exception handler` może naprawić, próbą ponownego wykonania instrukcji przy której wystąpił błąd

**Przykłady**:
* dzielenie przez 0
* page fault
* ### Abort
Wyjątki wywołane przez nienaprawialne błędy - `handler` przekazuje wtedy kontrolę do `abort'a`, który kończy działanie programu

**Przykłady**:
* `machine check` fatalne błędy hardware'u (np. corrupted bits w DRAM/SRAM)
* `SEGFAULT` próba dostepu do nieistniejacej pamieci albo do takiej do ktorej nie mamy dostepu
## Zadanie 2

* ### Obsługa przerwań

Gdy wysłany zostaje sygnał komunikujący przerwanie, na magistrali systemowej zostaje umieszczony numer przerwania, którego używamy jako indeksu do odczytania **`Procedury obsługi przerwania`** z tablicy skoków (alokowanej i inicjalizowanej podczas bootowania systemu) zwanej jako **`wektor przerwań`**.

Po wykonaniu procedury obsługi przerwania w zależności od rodzaju przerwania handler wraca do następnej instrukcji i program jest wykonywany dalej lub program zostaje zakończony.
* ### Co robi procesor przed pobraniem pierwszej instrukcji procedury obsługi przerwania?
Procesor odkłada na stos adres powrotu (zależnie od klasy wyjątku jest to aktualna lub następna w kolejności instrukcja) oraz kilka dodatkowych stanów procesora, potrzebnych do zrestartowania działania przerwanego programu po powrocie z `handler'a` (np. w systemie x86-64 są to rejestry EFLAGS z aktualnymi condition codes)
Kiedy następuje transfer z `user mode` do `kernel mode` te rzeczy są odkładane na stos kernela, zamiast na stos użytkownika.
* ### Czemu procedura obsługi przerwania powinna być wykonywana w trybie jądra i używać stosu odrębnego od stosu użytkownika?
W trybie jądra mamy kompletny dostęp do zasobów systemowych, które są potrzebne do obsługi przerwania.
Używamy stosu jądra ponieważ w stosie użytkownika wartość wskaźnika stosu może być nieprawidłowa, co może prowadzić do błędu gdy spróbujemy zapisać coś pod podanym adresem.
## Zadanie 3

* [Link do poczytania](https://www.intezer.com/blog/research/executable-linkable-format-101-part1-sections-segments/)
**Pliki relokowalne w formacie ELF składają się z:**
* nagłówka ELF
* segmentów
* sekcji
**Różnica**:
**Segment** - informacje potrzebne podczas runtime. Ma jedną lub więcej sekcji. Znane jako `Program Headery` - organizują strukturę pliku ELF w kawałki przygotowujące plik do załadowania do pamięci.
**Wiemy, gdzie umieścić segment dzięki informacji w nagłówku. Segment ma jedną lub więcej sekcji.**
**Sekcja** - informacje potrzebne podczas linkowania.
---

Struktura pliku relokowalnego w formacje ELF:

:::spoiler


:::
### Nagłówki ELF
Informacje ogólne o pliku
Adres pierwszej instrukcji programu znajduje się w polu
`e_entry`
:::spoiler
```c=
Figure 4-3: ELF Header
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT]; - pierwsze bajty mówią jak interpretować zawartość pliku
Elf32_Half e_type; - typ (realokowalny, so, wykonywalny, itd.)
Elf32_Half e_machine; - wymagana architektura dla pliku
Elf32_Word e_version; - wersja
Elf32_Addr e_entry; - adres wirtualny w którym system startuje proces (domyślnie 0)
Elf32_Off e_phoff; - offset w bajtach tablicy nagłówków (domyślnie 0 jeśli nie ma tablicy nagłówków)
Elf32_Off e_shoff; - jw. section header table
Elf32_Word e_flags; - processor-specific flagi powiązane z plikiem
Elf32_Half e_ehsize; - rozmiar ELF headera w bajtach
Elf32_Half e_phentsize; - rozmiar w bajtach jednej krotki z header table programu
Elf32_Half e_phnum; - ile jest krotek w header table programu
Elf32_Half e_shentsize; - jw. ale z section header
Elf32_Half e_shnum; - jw. ale z section header
Elf32_Half e_shstrndx; - index w section header table dla section name string table (domyślnie SHN_UNDEF)
} Elf32_Ehdr;
typedef struct {
Elf64_Word p_type; - jaki rodzaj segmentu opisuje
Elf64_Word p_flags; - flagi
Elf64_Off p_offset; - offset wzgledem poczatku pliku
Elf64_Addr p_vaddr; - virtual address pierwszego bajtu segmentu
Elf64_Addr p_paddr; - jw. dla fizycznego adresowania
Elf64_Xword p_filesz; - liczba bajtow w obrazie pliku segmentu
Elf64_Xword p_memsz; - jw. tylko w obrazie pamieci segmentu
Elf64_Xword p_align; - alignment segmentow
} Elf64_Phdr;
```
:::
:::spoiler szczegółowe opisy
http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid



:::
### Segmenty
Program (segment) header:

:::spoiler opisy pól
p_type: Segment type.ELF Header
p_flags: Segment attributes.
p_offset: File offset of segment.
p_vaddr: Virtual address of segment.
p_paddr: Physical address of segment.
p_filesz: Size of segment on disk.
p_memsz: Size of segment in memory.
P_align: segment alignment in memory.
There are a wide range of segment types. Some of common types are the following
PT_NULL: unassigned segment (usually first entry of Program Header Table).
PT_LOAD: Loadable segment.
PT_INTERP: Segment holding .interp section.
PT_TLS: Thread Local Storage segment (Common in statically linked binaries).
PT_DYNAMIC: Holding .dynamic section.
:::
Tylko segmenty typem PT_LOAD są załadowane do pamięci, reszta segmentów jest mapowana w obszarze pamięci jednego z segmentów PT_LOAD
### Sekcje
W plikach ELF jest Section Header Table z informacjami o danej sekcji
Section header:

:::spoiler opisy pól
sh_name: index of section name in section header string table.ELF Header
sh_type: section type.
sh_flags: section attributes.
sh_addr: virtual address of section.
sh_offset: section offset in disk.
sh_size: section size.
sh_link: section link index.
sh_Info: Section extra information.
sh_addralign: section alignment.
sh_entsize: size of entries contained in section.
:::
### Najczęściej występujące sekcje:

### Skąd system operacyjny wie gdzie położona jest pierwsza instrukcja programu?
z `ELF Header`
## Zadanie 4

:::spoiler detal o argumentach f main w c
For the command ‘cat foo bar’, argc is 3 and argv has three elements, "cat", "foo" and "bar".
In Unix systems you can define main a third way, using three arguments:
int main (int argc, char *argv[], char *envp[])
The first two arguments are just the same. The third argument envp gives the program’s environment; it is the same as the value of environ. See Environment Variables. POSIX.1 does not allow this three-argument form, so to be portable it is best to write main to take two arguments, and use the value of environ.
:::
:::spoiler ciekawostka
write file desc
fwrite struktura
:::
- przygotowac specjalne rejestry
- przygotowanie stosu
## Zadanie 5

`<<volatile>>` oznacza, że wartość jest ulotna i należy za każdym razem od nowa ją odczytać
**przykłady**:
* działanie na pamięci do której mogą zapisywać różne programy w tym samym czasie (np. zmienne globalne w programach wielowątkowych)
* odczyt z rejestrów z jakichś urządzeń
* odczyt danych z portów
nie moze byc w cachu przez inen rdzene (przyklad wspolb)
## Zadanie 6

## Zadanie 7

* **`opendir`**
* `openat` otwiera plik do deskryptora
* `newfstatat` sprawdza status pliku
* `SYS_318`
* `brk` zmiejsza segment danych [wywołane z opendir_tail]
* **`readdir`**
* `getdents64` pobiera wpisy w katalogu
* **`printf`**
* `newfstatat` sprawdza status pliku
* `write` zapisuje do deskryptora
* **`closedir`**
* `close` zamyka deskryptor
## Zadanie 8

### Zmodyfikowany Program
```c=
#include "apue.h"
#include <unistd.h>
#include "libapue/error.c"
#define BUFFSIZE 4096
// Dodane
#include <fcntl.h> // dla open
int main(int argc, char* argv []) {
int n;
char buf[BUFFSIZE];
int desc = open(argv[1], O_RDONLY); // open zwraca nr deskryptora
while ((n = read(desc, buf, BUFFSIZE)) > 0) {
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
}
if (n < 0)
err_sys("read error");
exit(0);
}
```
https://hackmd.io/zuUgbO9bQUiB2GVHgSjKww?view