The Linux Programming Interface〈系統概念〉

系統呼叫

系統呼叫流程,以使用 execve() 來說

1
2
3
4
5
6
7
int main()
{

char *argv[] = {"ls","-al","/etc/passwd",(char *)0};
char *envp[] = {"PATH=/bin",0};
execve("/bin/ls",argv,envp);
return 0;
}

execve 是 syscall 編號 11

編號定義位於kernel\linux-3.6.5\arch\x86\include\generated\asm\unistd_32/64.h

不同版本 Kernel 放的位置可能有點差別,另外 32/64 定義編號也會不一樣

1
2
3
4
5
6
7
8
9
10
# 32 位元編號定義
#define __NR_link 9
#define __NR_unlink 10
#define __NR_execve 11

# 64 位元編號定義
#define __NR_fork 57
#define __NR_vfork 58
#define __NR_execve 59
#define __NR_exit 60

常用的函式名稱其實都是呼叫底下的 syscall

1
2
3
fopen       -> open
printf -> write
malloc/free -> brk

Linux 上標準 C 函式庫為 glibc

其他還有 uClibs、dietlibc 等等

查看目前系統上面是使用什麼函示庫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 先編譯的一個執行檔
$ ./a.out

# 使用 ldd
$ ldd a.out
linux-vdso.so.1 => (0x00007fffa65fe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4fd2061000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4fd2440000)

# 執行 libc.so.6
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.19-0ubuntu6.6) stable release version 2.19, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.13.11 system on 2015-02-25.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/eglibc/+bugs>.

可攜帶程式

範例參考

在程式編譯時,可以藉由巨集或參數來決定區塊是否要編譯

1
2
#define _SOURCE 1
$cc -D_SOURCE prog.c

而類型則可以用typedef來取代,如下範例

當你看到一些以_t為結尾的通常都是 replace 基本類型

比如uid_t就取代intpid_t取代unsigned int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef long                I64_T;
typedef unsigned long UI64_T;
typedef int I32_T;
typedef unsigned int UI32_T;
typedef short int I16_T;
typedef unsigned short int UI16_T;
typedef char I8_T;
typedef unsigned char UI8_T;
typedef unsigned short int BOOLEAN;
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned long u_long;
typedef unsigned char unchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;

再來是結構的問題,例如以下結構為

1
2
3
4
5
struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_flg;
};

如果使用下面初始化方法是不可攜帶的

1
2
3
# 因為欄位順序可能不同
# 不同平台欄位特性可能不同
struct sembuf s = {3, -1, SEM_UNDO};

所以要用以下方法初始化

1
2
3
4
5
6
7
struct sembuf s
s.sem_num = 3;
s.sem_op = -1;
s.sem_flg = SEM_UNDO;

# 如果使用 C99 可以這樣寫
struct sembuf s = { s.sem_num = 3, s.sem_op = -1, s.sem_flg = SEM_UNDO};

Man 指令

Man page 後面數字代表意思,例如date(1)

1
2
3
4
5
6
7
8
9
1 	使用者在shell環境中可以操作的指令或可執行檔
2 系統核心可呼叫的函數與工具等
3 一些常用的函數(function)與函式庫(library),大部分為C的函式庫(libc)
4 裝置檔案的說明,通常在/dev下的檔案
5 設定檔或者是某些檔案的格式
6 遊戲(games)
7 慣例與協定等,例如Linux檔案系統、網路協定、ASCII code等等的說明
8 系統管理員可用的管理指令
9 跟kernel有關的文件

習題

reboot syscall 中 magic2 的故事