进程的内核空间映射到同一块物理地址。进程只能读写用户空间。用户空间映射到不同的物理地址,进程只能读写自己的用户空间。
PCB在内核空间,操作系统按照页管理内存。
每个页可以设置读写访问权限。参考MMU的设置代码。
Linux只用了两个特权级别。(Intel的CPU 4个特权级)
ISO C规定一个进程可以登记最多32个函数,这些函数由exit自动调用
atexit(stdlib.h)函数用来登记这些函数:调用顺序和登记顺序相反,同一函数登记多次也会调用多次。
每个程序都接收到一张环境表。环境表是字符指针数组。
extern char **environ;这个全局变量包含该指针数组的地址。
大多数UNIX系统支持main函数的第三个参数,就是char*envp[]环境表的地址。
POSIX.1规定使用environ而不使用第三个参数。ISO规定main函数由两个参数。
size命令报告程序的存储空间各个段的长度。
gcc -static hello.c 阻止gcc使用共享库
gcc hello.c gcc默认使用共享库
共享库的编译方法:
先创建共享库源文件add.c
1 int add(int a,int b)
2 {
3 return a+b;
4 }
编译
gcc add.c -fPIC -shared -o libadd.so
-fPIC 生成位置无关代码
-shared 生成共享库
编写测试文件main.c
1 #include
2
3 int add(int,int);
4
5 int main()
6 {
7 printf("%d\n",add(1,2));
8 }
编译
gcc main.c -L /home/myhome/apue/libso/ -ladd -o main.o
-L 指明共享库的路径
-ladd 指明共享库的名称
执行以下操作
cd /etc/ld.so.conf.d/
创建文件usr-libs.conf
vim usr-libs.conf
写入/home/myhome/apue/libso
sudo ldconfig
alloca在当前函数的栈帧上分配空间,不是在堆上,因此不必关心释放问题。有些系统函数已被调用后不能增加栈帧长度,也就不支持alloca。书中讨论的四个平台都提供这个函数。
#include
char * getenv(const char * name)返回指针指向name=value中的value。
应当使用这个函数,而不是直接访问environ。
int putenv(char *str)参数为name=value,如果已存在,删除原来的
setenv
unsetenv
环境表在进程地址空间的顶部,不能向上增长,也不能向下增长。
如果更改的value长度大于原来的value,则malloc为新的字符串分配空间,将环境表中针对name的指针指向新的空间。
增加新的name,malloc分配新的空间,把环境表复制到新的空间,name=value的指针放到环境表的尾部,再将空指针放在其后,原来的指针不变。environ指向新的环境表。环境表原来在栈顶之上,现在移动到堆上。
C语言中,goto不能跨函数跳转。
setjmp和longjmp可以。
#include
实验:longjmp之后,各种类型的变量的变化
1 #include
2 #include "apue.h"
3 #include
4
5 static void f1(int ,int ,int ,int);
6 static void f2(void);
7
8 static jmp_buf jmpbuffer;
9 static int global;
10
11 int main()
12 {
13 int autoval;
14 register int regval;
15 volatile int volaval;
16 static int staval;
17 global = 1;
18 autoval = 2;
19 regval = 3;
20 volaval =4;
21 staval = 5;
22
23 if(setjmp(jmpbuffer)!=0)
24 {
25 printf("global=%d,autoval=%d,regval=%d,volaval=%d,staval=%d\n",global,autoval,regval,volaval,staval);
26 exit(0);
27 }
28
29 global = 100;
30 autoval = 200;
31 regval = 300;
32 volaval =400;
33 staval = 500;
34 f1(autoval,regval,volaval,staval);
35 exit(0);
36
37 }
38
39 static void f2()
40 {
41 longjmp(jmpbuffer,1);
42 }
43 static void f1(int a,int b,int c,int d)
44 {
45 printf("in f1():\n");
46 printf("global=%d,autoval=%d,regval=%d,volaval=%d,staval=%d\n",global,a,b,c,d);
47 f2();
48
49 }
50
运行结果
未优化
in f1():
global=100,autoval=200,regval=300,volaval=400,staval=500
global=100,autoval=200,regval=300,volaval=400,staval=500
用-O选项优化之后
in f1():
global=100,autoval=200,regval=300,volaval=400,staval=500
global=100,autoval=2,regval=3,volaval=400,staval=500
解释:存储器中的变量在longjmp之后,值为最近呈现的值,CPU和浮点寄存器中的变量将恢复为调用setjmp的值。
关于volatile的理解:自动变量和寄存器变量经过优化之后,会放到寄存器中(P174),volatile变量仍然在存储器中。
如果要编写非局部跳转的程序,最好用volatile。
getrlimit
setrlimit
1 #include
2 #include "apue.h"
3 #include
4
5 int main()
6 {
7 struct rlimit limit;
8 getrlimit(RLIMIT_CORE,&limit);
9 printf("rlimit_cur=%lu\n",(unsigned long)limit.rlim_cur);
10 printf("rlimit_max=%lu\n",(unsigned long)limit.rlim_max);
11 }
运行结果
rlimit_cur=0
rlimit_max=18446744073709551615