# **Linux OS Project 2**
<br/>
<br/>
<br/>
**第1組 111522015 陳萬鈿 110522156 陳明威**
Goal
---
*Write a program using the system call you wrote in Project 1 to check how memory areas are shared by two processes that execute this program simultaneously.
The memory areas include code segments, data segments, BSS segments, heap segments, libraries, stack segments.*
<br/>
Method
---
**寫一個program test.c,透過使用tmux執行test.c編譯後的執行檔,比對彼此的segment實體位置來確認是否相同。**
<br/>
**Project_1 syscall link :** https://hackmd.io/ISR9bPY8RjuH2r8RijH__A
<br/>
Kernel & Linux version
---
**Kernel 4.4.1 + ubuntu 16.04**
**( GCC 5.4.0 + Tmux 2.1)**
tmux install
```
sudo apt install tmux
```
<br/>
Test code
---
```C=
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define mask 0x00000000ffffffff
char label[100] = {"Stack Lib Heap Bss Data Code "};
int data = 0;
int bss ;
int code(){
return 0;
}
int main(){
int k = 0;
unsigned long arr[8];
unsigned long arr1[8];
unsigned long temp =0;
unsigned long *p2 = &temp;
int index = 0;
int stack = 54088;
int *heap = malloc(sizeof(int));
unsigned long address[6] =
{(unsigned long)&stack,
(unsigned long)&printf,
(unsigned long)heap,
(unsigned long)&bss,
(unsigned long)&data,
(unsigned long)&code};
printf("I'm process pid : %d !!!\n\n" , getpid());
for(int i = 0 ;i < 6;i++){
unsigned long *p1 = &address[i];
long a = syscall(547,p1,p2);
while(1){
printf("%c",label[index]);
index++;
if(label[index] ==' '){index++; break;}};
printf(" vaddr: %#lx\t paddr: %#lx\n",*p1,*p2 );
}
printf("\n\n");
long a = syscall(546 , arr1, arr1);
arr1[7] =0;
printf("virtual address :");
for(int i = 0 ; i < 8 ; i = i +2){
printf("%d : start : %lx end : %lx\n", k ,arr1[i] , arr1[i+1]);
k++;
}
for(int i = 0 ; i < 8 ;i++){
unsigned long *p1 = &arr1[i];
long b = syscall(547,p1,p2);
arr1[i] = temp;
}
k=0;
arr1[7] =0;
printf("\n")
printf("physical address :");
for(int i = 0 ; i < 8 ; i = i +2){
printf("%d : start : %lx end : %lx\n", k ,arr1[i] ,arr1[i+1]);
k++;
}
printf("\n");
sleep(1000);
return 0;
}
```
<br/>
Syscall code
---
```C=
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/current.h>
SYSCALL_DEFINE2(v_to_p,unsigned long* ,vaddr,unsigned long* ,paddr ){
struct mm_struct *mm;
struct vm_area_struct* vma;
unsigned long arr[7];
mm = current->mm;
vma = mm->mmap;
copy_from_user(arr,vaddr,sizeof(unsigned long)*7);
arr[6] = mm->start_stack;
arr[0] = mm->start_code;
arr[1] = mm->end_code;
arr[2] = mm->start_data;
arr[3] = mm->end_data;
arr[4] = mm->start_brk;
arr[5] = mm->brk;
copy_to_user(paddr,arr,sizeof(unsigned long)*7);
return 0;
}
```
compiling
---
**在command line 依序輸入以下指令**
```
gcc -fpie test.c -o main
```
<br/>
Result
---

從mm_struct中抓到的位置分別對應為
0 : code_start/code_end address
1 : data_start/data_end address
2 : heap_start/heap_end address
3 : stack_start address
<br/>
Conclusion
---
<br/>
在上次的專案中找出各個thread的分段位置中有出現**錯誤**,我發現lib segment的virtual address要比heap segment來的高,但是結果卻顯示與code segment的位置非常接近,這是因為lib segment取值是取到printf@plt位置,會導致這個結果的原因是gcc compiler設定上問題,我的compiler預設並沒有開啟pie,因此編譯後的檔案是non-pie,而linux x86_64的二進制文件地址默認在0x400000,這個地址與code segment很近才會有先前的結果。

[PIE-PIC](https://leimao.github.io/blog/PIC-PIE/)
[ASLR](https://leimao.github.io/blog/PIC-PIE/)
[得到錯誤地址的原因](https://stackoverflow.com/questions/28119365/what-are-the-differences-comparing-pie-pic-code-and-executable-on-64-bit-x86-pl )
[PLT](https://www.cnblogs.com/sword03/p/9385660.html)
這次加入了一個新的syscall將上次加分題的功能實做出來,編譯過程與上次相同,從task_struct-> mm_struct中取值,回傳後再透過Project_1 syscall轉換為physical address。
透過以上結果我們可以判斷不同的process執行相同的program,共享的實體位置只有code segment和lib segment共享,其他皆沒有共享。
<br/>
---
## demo 提問
**1.在sleep 時 process 狀態**
透過tmux開兩個process進sleep(),再分割一個下指令: $ps a可看到當中STAT(目前狀態)皆為S+([ps man_page](https://man7.org/linux/man-pages/man1/ps.1.html#PROCESS_STATE_CODES))

**2.sleep時如何關閉 process? ctrl+c在做什麼?kill在做什麼?**
終止正在執行之程式(ctrl+c),按下後Terminal會發送一個[**SIGINT中斷訊號**]給Shell,Shell再把SIGINT轉發給ping process,最後ping process收到就會自己停掉。
暫停正在執行的程式(ctrl+z),發送[**SIGTSTP(暫停訊號)**]給正在跑的process。回復執行下指令:**fg**
[Day23-Signal 訊號(一)]: https://ithelp.ithome.com.tw/articles/10226301
**3.signal?**
是 OS 控制程序執行的媒介,作業系統中 process 間通訊的一種有限制的方式。它是一種異步的通知機制,用來提醒 process 一個事件已經發生。當一個 signal 傳送給一個 process,作業系統中斷了行程正常的控制流程,此時,任何非原子操作都將被中斷。例如用戶要終止某一執行中的應用程式,OS 就要將用戶的這個意圖,利用訊號正確地傳遞到指定的應用程序。這類要求 process 結束的訊號稱為 termination signals。
**SIGTERM**
Termination
SIGTERM 信號是用於導致程序終止的通用信號。 與 SIGKILL 不同,此信號可以被阻止、處理和忽略。
**SIGINT**
Interrupt
User 輸入 INTR character(Ctrl + C)時產生
**SIGQUIT**
和SIGINT類似, 但由QUIT字符(通常是Ctrl-\)來控制. process在收到SIGQUIT退出時會產生core文件, 在這個意義上類似於一個程序錯誤信號。
**SIGKILL**
信號用於立即終止程序。 它不能被處理或忽略,也無法阻止此信號。
**SIGHUP**
Hang-up
hong up,本信號在用戶終端連接(正常或非正常)結束時發出, 通常是在終端的控制進程結束時, 通知同一session內的各個作業, 這時它們與控制終端不再關聯。
**4.mmap system call 在做什麼?**
mmap system call 是linux中可用來將文件映射到虛擬記憶體位置,如此一來不同的process透過對這段記憶體位置的讀寫達到共享的目的,這樣也可以方便操作
文件不需要透過read write函數對文件進行讀寫,當呼叫此函數時會在process的虛擬記憶體位置找到連續的空間,並分配vm_area_struct結構的空間,再將此空間鏈結到原本process的vm_area_struct串列中。
**5.copy on write(COW)?**
如果有多個呼叫者(callers)同時請求相同資源(如記憶體或磁碟上的資料儲存),他們會共同取得相同的指標指向相同的資源,直到某個呼叫者試圖修改資源的內容時,系統才會真正複製一份專用副本(private copy)給該呼叫者,而其他呼叫者所見到的最初的資源仍然保持不變。這過程對其他的呼叫者都是透明的。此作法主要的優點是如果呼叫者沒有修改該資源,就不會有副本(private copy)被建立,因此多個呼叫者只是讀取操作時可以共享同一份資源。
**6.page fault哪些原因?**
沒有實際建立虛擬記憶體與實體記憶體的映射關係,當CPU沒有辦法存取實體記憶體的時候就會發生分頁錯誤(page fault)。
觸發 Page Fault 的原因主要歸類為幾大類:
1.使用共享記憶體的區域,但是還不存在虛擬位址與實體位址的對應,而產生的分頁錯誤,這種錯誤只要在分頁表中建立對應關係就好了。
2.訪問的地址在實體記憶體中不存在,需要從硬碟或是 swap分割槽讀入才能使用,這種效能影響比較大,因為磁碟讀取的速度真的太慢了。
3.訪問的記憶體位址非法,缺頁錯誤會進而引發 SIGSEGN 訊號結束程序,這種分頁錯誤會導致行程直接關閉。