---
# System prepended metadata

title: SO Lista 0

---

# SO Lista 0

![](https://i.imgur.com/ScWqdcK.png)
---
![](https://i.imgur.com/uVYvN3R.png)

:::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
![](https://i.imgur.com/VeWthf1.png)
* ### 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.
    ![](https://i.imgur.com/PeIzKjo.png)

    Są podzielone na cztery klasy:
    ![](https://i.imgur.com/eQlRCph.png)

    * ### 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.
        ![](https://i.imgur.com/NHQjmUq.png)

        **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
        ![](https://i.imgur.com/20Gg9G9.png)
        
        **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
        ![](https://i.imgur.com/PWSg0qL.png)
        
        **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
        ![](https://i.imgur.com/QAHbWqK.png)

        **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
![](https://i.imgur.com/HgSAIct.png)

* ### Obsługa przerwań
    ![](https://i.imgur.com/AEnC1Mw.png)
    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ń`**.
    ![](https://i.imgur.com/nE3bTjq.png)

    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
![](https://i.imgur.com/lwP70Lj.png)
* [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. 

---
![](https://i.imgur.com/oAmYYhr.png)

Struktura pliku relokowalnego w formacje ELF:
![](https://i.imgur.com/NVeSVNi.png)

:::spoiler
![](https://i.imgur.com/EOKTl0T.png)
![](https://i.imgur.com/0o7itvL.png)
:::

### 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
![](https://i.imgur.com/8i1FE4p.png)
![](https://i.imgur.com/2pDYIrt.png)

![](https://i.imgur.com/txez6uc.png)
:::

### Segmenty
Program (segment) header:
![](https://i.imgur.com/4PkHYJU.png)
:::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:
![](https://i.imgur.com/JEJ9UXp.png)
:::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:

![](https://i.imgur.com/foobbjl.png)

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


## Zadanie 4
![](https://i.imgur.com/JkbSvZp.png)

:::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
![](https://i.imgur.com/qBGrC6b.png)
`<<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
![](https://i.imgur.com/yMoSDKJ.png)


## Zadanie 7
![](https://i.imgur.com/0sZ7gEH.png)

* **`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
![](https://i.imgur.com/SFnaXMn.png)


### 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