1. 程式人生 > >Linux 下系統呼叫的三種方法

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_opensys_mmapsys_writesys_close 等等系統呼叫;
  • 另外,多個 API 也可能只對應同一個系統呼叫,如glibc 下實現的 malloccallocfree 等函式用來分配和釋放記憶體,都利用了核心的 sys_brk 的系統呼叫。

舉例來說,我們通過 glibc 提供的chmod 函式來改變檔案 etc/passwd

 的屬性為 444:

#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)的形式提供,

LinuxSVN的備份方式

$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

Windowsc++獲取系統時間的方法

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地址、子網掩碼,而且還要和宿