Linux 下系統呼叫的三種方法
轉自:https://www.cnblogs.com/hazir/p/three_methods_of_syscall.html
系統呼叫(System Call)是作業系統為在使用者態執行的程序與硬體裝置(如CPU、磁碟、印表機等)進行互動提供的一組介面。當用戶程序需要發生系統呼叫時,CPU 通過軟中斷切換到核心態開始執行核心系統呼叫函式。下面介紹Linux 下三種發生系統呼叫的方法:
通過 glibc 提供的庫函式
glibc 是 Linux 下使用的開源的標準 C 庫,它是 GNU 釋出的 libc 庫,即執行時庫。glibc 為程式設計師提供豐富的 API(Application Programming Interface),除了例如字串處理、數學運算等使用者態服務之外,最重要的是封裝了作業系統提供的系統服務,即系統呼叫的封裝。那麼glibc提供的系統呼叫API與核心特定的系統呼叫之間的關係是什麼呢?
- 通常情況,每個特定的系統呼叫對應了至少一個 glibc 封裝的庫函式,如系統提供的開啟檔案系統呼叫
sys_open
對應的是 glibc 中的open
函式; - 其次,glibc 一個單獨的 API 可能呼叫多個系統呼叫,如 glibc 提供的
printf
函式就會呼叫如sys_open
、sys_mmap
、sys_write
、sys_close
等等系統呼叫; - 另外,多個 API 也可能只對應同一個系統呼叫,如glibc 下實現的
malloc
、calloc
、free
等函式用來分配和釋放記憶體,都利用了核心的sys_brk
的系統呼叫。
舉例來說,我們通過 glibc 提供的chmod
函式來改變檔案 etc/passwd
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <stdio.h> int main() { int rc; rc = chmod("/etc/passwd", 0444); if (rc == -1) fprintf(stderr, "chmod failed, errno = %d\n", errno); else printf("chmod success!\n"); return 0; }
在普通使用者下編譯運用,輸出結果為:
chmod failed, errno = 1
上面系統呼叫返回的值為-1,說明系統呼叫失敗,錯誤碼為1,在 /usr/include/asm-generic/errno-base.h
檔案中有如下錯誤程式碼說明:
#define EPERM 1 /* Operation not permitted */
即無許可權進行該操作,我們以普通使用者許可權是無法修改 /etc/passwd 檔案的屬性的,結果正確。
使用 syscall 直接呼叫
使用上面的方法有很多好處,首先你無須知道更多的細節,如 chmod 系統呼叫號,你只需瞭解 glibc 提供的 API 的原型;其次,該方法具有更好的移植性,你可以很輕鬆將該程式移植到其他平臺,或者將 glibc 庫換成其它庫,程式只需做少量改動。
但有點不足是,如果 glibc 沒有封裝某個核心提供的系統呼叫時,我就沒辦法通過上面的方法來呼叫該系統呼叫。如我自己通過編譯核心增加了一個系統呼叫,這時 glibc 不可能有你新增系統呼叫的封裝 API,此時我們可以利用 glibc 提供的syscall
函式直接呼叫。該函式定義在 unistd.h
標頭檔案中,函式原型如下:
long int syscall (long int sysno, ...)
- sysno 是系統呼叫號,每個系統呼叫都有唯一的系統呼叫號來標識。在
sys/syscall.h
中有所有可能的系統呼叫號的巨集定義。 - ... 為剩餘可變長的引數,為系統呼叫所帶的引數,根據系統呼叫的不同,可帶0~5個不等的引數,如果超過特定系統呼叫能帶的引數,多餘的引數被忽略。
- 返回值 該函式返回值為特定系統呼叫的返回值,在系統呼叫成功之後你可以將該返回值轉化為特定的型別,如果系統呼叫失敗則返回 -1,錯誤程式碼存放在
errno
中。
還以上面修改 /etc/passwd 檔案的屬性為例,這次使用 syscall 直接呼叫:
#include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <errno.h> int main() { int rc; rc = syscall(SYS_chmod, "/etc/passwd", 0444); if (rc == -1) fprintf(stderr, "chmod failed, errno = %d\n", errno); else printf("chmod succeess!\n"); return 0; }
在普通使用者下編譯執行,輸出的結果與上例相同。
通過 int 指令陷入
如果我們知道系統呼叫的整個過程的話,應該就能知道使用者態程式通過軟中斷指令int 0x80
來陷入核心態(在Intel Pentium II 又引入了sysenter
指令),引數的傳遞是通過暫存器,eax 傳遞的是系統呼叫號,ebx、ecx、edx、esi和edi 來依次傳遞最多五個引數,當系統呼叫返回時,返回值存放在 eax 中。
仍然以上面的修改檔案屬性為例,將呼叫系統呼叫那段寫成內聯彙編程式碼:
#include <stdio.h> #include <sys/types.h> #include <sys/syscall.h> #include <errno.h> int main() { long rc; char *file_name = "/etc/passwd"; unsigned short mode = 0444; asm( "int $0x80" : "=a" (rc) : "0" (SYS_chmod), "b" ((long)file_name), "c" ((long)mode) ); if ((unsigned long)rc >= (unsigned long)-132) { errno = -rc; rc = -1; } if (rc == -1) fprintf(stderr, "chmode failed, errno = %d\n", errno); else printf("success!\n"); return 0; }
如果 eax 暫存器存放的返回值(存放在變數 rc 中)在 -1~-132 之間,就必須要解釋為出錯碼(在/usr/include/asm-generic/errno.h
檔案中定義的最大出錯碼為 132),這時,將錯誤碼寫入 errno 中,置系統呼叫返回值為 -1;否則返回的是 eax 中的值。
上面程式在 32位Linux下以普通使用者許可權編譯執行結果與前面兩個相同!
相關推薦
從U盤運行Linux操作系統的三種方法
attach 損壞 seo 系統 alt ubunt 沒有 linux操作 ash 摘要: 從U盤運行Linux操作系統的三種方法 usb_linux_0 你或許聽說過在U盤上運行live Linux操作系統,但你知不知道可以永久的保存運行時的數據,或者直接將Linux安裝
Linux 下系統呼叫的三種方法
轉自:https://www.cnblogs.com/hazir/p/three_methods_of_syscall.html 系統呼叫(System Call)是作業系統為在使用者態執行的程序與硬體裝置(如CPU、磁碟、印表機等)進行互動提供的一組介面。當用戶程序需要
LInux安裝jdk的三種方法
環境 Linux版本:CentOS 6.5、Ubuntu 12.04.5 JDK版本:JDK 1.7 目錄 方法一:手動解壓JDK的壓縮包,然後設定環境變數 方法二:用yum安裝JDK 方法三:用rpm安裝JDK 方法四:Ubuntu 上使用apt-get安裝J
以太坊智慧合約中函式呼叫三種方法(很重要!!!)
外部呼叫: sendTransaction/call 函式呼叫一般分外部呼叫和內部呼叫兩種, 外部呼叫是通過JSON-RPC介面實現對合約函式的呼叫, 有3種呼叫方式: testInstance.testFunc.sendTransaction(); testInstance.testFun
Linux下系統呼叫實現檔案操作
系統呼叫(系統呼叫是作業系統提供給使用者程式的一組“特殊”函式介面,使用者通過這組介面獲得作業系統提供的服務)中操作I/O的函式,都是針對檔案描述符的。 通過檔案描述符可以直接對相應檔案進行操作,如:open、close、write、read、ioctl #define STDIN_FIL
關於上一篇滑鼠移到按鈕時的“按下”效果的三種方法
上一篇博文中,關於按鈕按下的效果回過頭研究了下,總結了如下三種方法,只寫出關鍵樣式: 1、相對定位input.button{ position:relative; //用相對定位 }
linux下系統呼叫、API、系統命令,核心函式的區別與聯絡
1.系統呼叫: 應用程式和核心間的橋樑,是應用程式訪問核心的入口點;但通常情況下,應用程式通過作業系統提供的API進行程式設計而不是使用系統呼叫直接程式設計; linux的全部系統呼叫加起來大約只有250個左右。 2.API: API常以c庫(libc)的形式提供,
Linux下SVN的三種備份方式
$youngest=`svnlook youngest $svn_repos`; chomp $youngest; if ($youngest eq $previous_youngest) { print "No new revisions to backup./n"; exit 0; } my $f
linux虛擬主機的三種方法
虛擬主機 虛擬主機是將一臺(或者一組)伺服器的資源(系統資源、網路頻寬、儲存空間等)按照一定的比例分割成若干相對獨立的“小主機”的技術。每一臺這樣的“小主機”在功能上都可以實現WWW、FTP、Mail
ubuntu下修改path三種方法
在 Ubuntu 系統中有兩種設定環境變數 PATH 的方法。第一種適用於為單一使用者設定 PATH,第二種是為全域性設定 PATH。第三種方法適合於暫時修改,重新登入後失效 第一種方法: 在使用者主目錄下有一個 .bashrc 檔案,可以在此檔案中加入 PATH 的
linux 磁碟掛載的三種方法
df 使用df命令,這個命令比較常用,大家都很熟悉。問題是這種方法,有時候掛載點和掛載的卷不在同一行,使用指令碼分析需要一點技巧的 mount 使用mount命令,mount -l,這種方法的缺陷在於沒有卷的大小,但是掛載點和掛載的卷在同一行 檢
Linux下執行時呼叫動態連結庫.so的三種方法(筆記)
在/etc/ld.so.conf.d/下建立xxx.conf,在文字中加入.so所在路徑,如:/usr/xxx等等,然後使用相應ldconfig命令使之生效。 將.so所在路徑新增為LD_LIBRARY_PATH環境變數。 在編譯命令中使用-Wl,-rpath
linux系統呼叫的三種方法
通過glibc提供的庫函式 [23:02:14] gcc chmodtest.c [23:02:17] ls -l kali //記得先建立這個檔案 -rwxrwxrwx. 1 root r
QT 呼叫執行 linux指令碼的三種方法
在linux系統下,Qt執行shell命令的方式有3種: (1)QProcess:execute("ls"); (2)system("ls"); (3)QProcess *process = new QProcess(); process->start("ls"); 注1:以上
Linux下安裝與解除安裝工具(三種方法)
三種方法為:rpm工具、yum工具、原始碼包 rpm工具(操作繁瑣) 光碟機掛載到mnt:mount /dev/cdrom /mnt/centos安裝包中就有rpm包 Packages rpm -ivh rpm包檔案 //安裝rpm -Uvh rpm包檔案 //升級rpm -e 包名 //解除安裝(包名
Linux下安裝與卸載工具(三種方法)
ado 路徑 sha ins nag 查詢 linu ext 光驅掛載 三種方法為:rpm工具、yum工具、源碼包 rpm工具(操作繁瑣) 光驅掛載到mnt:mount /dev/cdrom /mnt/centos安裝包中就有rpm包 Packages rpm -ivh
linux下配置jdk環境變數的三種方法總結
原文連結:http://www.jb51.net/article/93887.htm 一、修改/etc/profile檔案當本機僅僅作為開發使用時推薦使用這種方法,因為此種配置時所有使用者的shell都有權使用這些環境變數,可能會給系統帶來安全性問題。用文字編輯器開啟/etc/profi
linux下配置jdk環境變數的三種方法
一、修改/etc/profile檔案當本機僅僅作為開發使用時推薦使用這種方法,因為此種配置時所有使用者的shell都有權使用這些環境變數,可能會給系統帶來安全性問題。用文字編輯器開啟/etc/profile,在profile檔案末尾加入:JAVA_HOME=/usr/sha
Windows下c++獲取系統時間的三種方法
1、CTime類的static介面GetCurrentTime() 包含的標頭檔案#include <atltime.h> CTime類的物件表示的時間是基於格林威治標準時間(GMT)的。 CTime表示的日期上限是3000年12月31日,下限是1970年1月1
【Linux Is Not Unix】虛擬機器下CentOS配置ip三種方法(1)-橋接模式(bridge)
在bridged模式下,VMWare虛擬出來的作業系統就像是區域網中的一臺獨立的主機,它可以訪問網內任何一臺機器。在bridged模式下,你需要手工為虛擬系統配置IP地址、子網掩碼,而且還要和宿