標籤:

庫文件與系統調用

庫文件

先從我們熟悉的c庫入手,理解系統調用(system call)。c代碼中調用printf函數,經歷了以下調用過程:

最終輸出的功能由內核中write調用完成,c庫封裝了系統調用。

對於以下hello world程序:

int main()n{n  printf("Hello world.n");n  return 0;n}n

我們可以使用ldd查看程序依賴的庫文件:

linux # ldd hellon    linux-vdso.so.1 => (0x00007fff89fe2000)n    libc.so.6 => /lib64/libc.so.6 (0x00007fd142094000)n    /lib64/ld-linux-x86-64.so.2 (0x00007fd1423f2000)n

輸出結果中顯示了hello程序依賴的動態庫文件,其中linux-vdso.so.1指向進程虛擬內存地址,是一個虛擬的庫文件,在每個程序的虛擬內存都存在,其將內核態的調用映射到用戶地址空間中,使得調用開銷更小。

有些時候,在我們編譯程序時,會出現找不到某某lib的提示,又或者ldd查詢到某庫鏈接指示」not found」,這是因為ldd在/etc/ld.so.cache中不存在相應庫文件的查找路徑(使用strace跟蹤ldd命令可以看到ld.so.cache文件被讀取)。

要解決找不到某庫的問題,我們可以將庫文件路徑加到用戶的LIBRARY_PATH環境變數中,也可以添加到全局的/etc/ld.so.conf配置文件中,添加完後以root用戶執行ldconfig,以更新/etc/ld.so.cache緩存文件。

使用rpm命令可以查到動態庫屬於哪個rpm包:

linux # rpm -qf /lib64/libc.so.6nglibc-2.11.1-0.17.4n

反過來,對某一rpm包,我們可以查其包含的內容:

linux # rpm -ql glibc-2.11.1-0.17.4n/etc/bindresvport.blacklistn/etc/default/nssn/etc/gai.confn/etc/ld.so.cachen/etc/ld.so.confn……n

devel包中包含了c庫函數的頭文件,而普通包中不包含頭文件,可以使用rpm查詢對比開發包和普通包:

rpm -ql glibc-2.4-31.77.88.4nrpm -ql glibc-devel-2.4-31.77.88.4n

系統調用

每一個系統調用對應一個系統調用號(system call number),使用系統調用的過程就是將系統調用號和參數傳遞給內核。

使用objdump,可以對庫文件進行反彙編,以下對/lib64/libc.so.6進行反彙編,並查看getpid函數相應的部分彙編代碼:

00000000000933e0 <__getpid>:n……n933fa: 00n933fb: 85 c0 test %eax,%eaxn933fd: 75 f0 jne 933ef <__getpid+0xf>n933ff: b8 27 00 00 00 mov $0x27,%eaxn93404: 0f 05 syscalln93406: 85 d2 test %edx,%edxn……n

在以上輸出中,mov指令將系統調用號0x27放入eax寄存器中,0x27作為syscall的參數,syscall完成調用getpid的工作。

系統調用與系統調用號對應關係在include/asm/unistd.h中定義,我們可以查到getpid相應的定義語句:

#define __NR_getpid 39n__SYSCALL(__NR_getpid, sys_getpid)n

unistd.h定義了POSIX標準提供的系統調用,所有符合POSIX標準的Unix系統均提供該頭文件。

我們可以直接傳遞系統調用號給syscall函數,完成系統調用,以下程序說明了如何使用syscall直接完成getpid系統調用:

#define _GNU_SOURCEnint main(int argc, char *argv[])n{n pid_t tid;n tid = syscall(SYS_gettid);n printf("%dn", tid);n}n

因而總結來說,使用系統調用的方式有兩種:

  1. c庫中封裝了系統調用,通過c庫間接調用
  2. 傳遞系統調用號,通過syscall直接調用

第2種方式存在的意義在於,當kernel提供了新的系統調用,而c庫又沒有更新時,可以使用syscall調用新的系統調用。

Reference: Chapter 5 - System Calls, Linux kernel development.3rd.Edition


推薦閱讀:

十年回顧-我的Linux之路
openvswitch有什麼用?
感覺autoconf真不太好用,有何替代方案?
Linux頁表中虛擬內存地址如何映射到硬碟數據塊地址?
mount --bind 可以算是ln一個目錄么?

TAG:Linux | Linux内核 |