系統呼叫原理

2022-09-09 15:00:25 字數 3024 閱讀 2195

以fork()為例

int main()

fork();

fork()是乙個對系統呼叫fork的封裝,可用下列巨集來定義

_syscall0(pit_t, fork);

_syscall0是乙個巨集函式,i386版本定義如下:

#define _syscall0(type, name)       \

type  name(void)                         \

long __res;         \

__asm__ volatile ( "int $0x80"         //__asm__ 為gcc 嵌入彙編**標識關鍵字, volatile 告訴gcc 這段**不做優化;__asm__的第乙個引數為彙編**字串,0x80為中斷號\

: "=a" (__res)   // a表示eax, 這個語句表示用eax輸出返回資料並儲存在__res裡。\

: "0"  (__nr__##name)); //表示__nr_##name為輸入,「0」指示有編譯器選擇和輸出相同的暫存器(eax)來傳遞引數。\

__syscall_return(type, __res); \

對於__syacall0(pid_t, fork)展開為:

pid_t fork(void)

long __res;

__asm__ volatile ("int $0x80"

: "=a" (__res)

: "0" (__nr_fork));

__syscall_return(pid_t, __res);

進一步可讀化:

pid_t fork(void)

long __res;

$eax = __nr_fork   //eax傳遞系統呼叫號, linux系統中fork為2。 linux/include/asm-x86/unistd_32.h   #define __nr_fork   2

int $0x80

__res = $eax

__syacall_return(pid_t, __res);

帶引數的syscall

#define _syscall2(type, name, type1, arg1)  \

type name(type1, arg1)                   \

long  _res;  \

__asm__ volatile ("int $0x80" \

: "=a" (__res)        \

: "0" (__nr_##name), "b" ((long)(arg1))); // b代表ebx暫存器, "b"((long)(arg1))表示先把arg1強轉為long,然後存放在ebx裡作為輸入。可用ebx/ecx/edx/esi/edi/ebp \

__syscall_return(type, __res); \

對應彙編**:

push ebx

eax = __nr_##name

ebx = arg1

int 0x80

__res = eax

pop ebx

系統呼叫需要將堆疊從使用者棧切換到核心棧,返回時需要切換到使用者棧。

「當前棧」是指esp的值所在的棧空間,esp的值位於使用者棧範圍,則程式的當前棧就是使用者棧,反之亦然。此外,暫存器ss的值還應該指向當前棧所在的頁。所以使用者棧--》核心棧 實際就是:

1)儲存當前的esp、ss值

2)將esp、ss的值設為核心棧的相應值。

反過來, 核心棧--》使用者棧則是:

1)恢復原來的esp、ss的值

使用者態的esp、ss儲存在**呢? 在核心棧上。有i386的中斷硬體指令完成。

當0x80中斷發生的時候,cpu除了切換核心態之外,還自動完成:

1)找到當前程序的核心棧(每個程序都有自己的核心棧)

2) 在核心棧中依次壓入使用者態的暫存器ss、esp、eflags、cs、eip。

當核心從系統呼叫中返回的時候,需要用iret指令來回到使用者態。

linux實際不用int $0x80方式,而是用sysenter方式。

cat /proc/self/maps可以看到vdso檔案(virtual dynamic shared library),vdso總是被載入在位址0xffffe000

ffffe000-fffff000 r-xp 00000000 00:00 0  [vdso]

通過$dd if=/proc/self/mem of=linux-gate.dso bs=4096 skip=1048574 count=1

將vdso輸出到linux-gate.dso. dd複製檔案,if--輸入檔案,of--輸出檔案, skip表示從檔案開頭要跳過都少塊, 0xffffe000/4096(0x1000) = 1048574

$objdump -t linux-gate.dso可分析該檔案

ffffe400 .... __kernel_vsyscall

檢視該vsyscall,

objdump -d --start-address=0xffffe400  --stop-address=0xffffe408  linux-gate.dso

push %ecx

push %edx

push %ebp

mov  %esp, %ebp

sysenter

nop人工呼叫系統呼叫

int main()

int ret;

char msg = "hello\n";

__asm__ volatile (

"call *%%esi"

: "=a" (ret)

: "a" (4),    //write 系統呼叫號4通過eax傳入

「s」(0xffffe400),  //通過esi傳入__kernel_vsyscall函式的位址

」b」 ((long)1),  //fd = stdout 

「c」 ((long)msg),

"d" ((long)sizeof(msg)));

return 0;

系統呼叫原理

系統呼叫 系統呼叫是應用程式和作業系統核心的介面,無論程式是直接進行系統呼叫還是通過執行庫,最終還是會到達系統呼叫層面上。之所以要系統呼叫,是因為現在作業系統都將可能產生衝突的系統資源給保護起來,組織應用程式直接訪問。這些系統資源包括檔案 網路 io 各種裝置等。所有的這些操作都必須經由作業系統所規...

Linux系統呼叫原理

rootfs 使用者空間 kernel 核心空間 檔案系統 裝置驅動 網路協議棧 程序管理 記憶體管理 平台 系統呼叫 七大子系統 uboot 硬體linux系統分為使用者空間和核心空間 使用者空間的特性 包含了應用軟體,c庫,對應的cpu的工作模式為usr模式 不能直接訪問硬體裝置 如果進行記憶體...

Linux 系統呼叫原理

unistd.h檔案記錄著系統呼叫中斷號的資訊。syscall nr kill,sys kill security keys keyctl.c define nr add key 217 syscall nr add key,sys add key syscall define5 add key,c...