一、进程和程序:进程由用户内存空间(程序代码和变量)和一系列内核数据结构(维护进程状态信息:进程相关标识号IDs、虚拟内存表、打开的文件描述符、信号传递及处理的有关信息、进程资源使用及限制、当前工作目录和大量的其他信息)组成。
1、二进制格式标识:a.out(汇编程序输出)->COFF->ELF;
2、机器语言指令:对程序算法进行编码;
3、程序入口地址:标识程序开始执行时的其实指令地址;
4、数据:
5、符号表及重定位表:描述程序中函数和变量的位置及名称;
6、共享库和动态链接信息:运行时的共享库、路径名等;
7、其他信息:描述如何创建进程等。
二、进程号和父进程号:PID(进程号上限为32767(32位系统,64位可以达到400万)—可以通过修改pid_max来调整,达到之后进程号计数器重置为300)。
三、进程内存布局:每个进程所分配的内存由很多部分组成,通常称之为段(segment)。size命令可以显示二进制可执行文件的各个段。ABI(应用程序二进制接口,对应寄存器的调用)。
1、文本段:程序机器语言指令,只读;
2、初始化数据段:初始化的全局变量和静态变量;
3、未初始化数据段(BBS):未初始化的全局变量和静态变量;
4、栈:栈帧组成,存储局部变量、实参和返回值;
5、堆:动态内存分配区域;
四、虚拟内存管理:访问局部性,以求高效使用CPU和RAM资源。
空间局部性:程序倾向于访问在最近访问过的内存地址附近的内存(由于指令是顺序执行的,且有时会按顺序处理数据结构)。
时间局部性:程序倾向于在不久的将来再次访问最近刚访问过的内存地址(由于循环)。
将每个程序切割成小型的。固定的叶单元,RAM也划分成为一系列与虚存叶尺寸相同的叶帧。驻留集,交换区,页面错误(page fault);sysconf(_SC_PAGESIZE)可以获取系统虚拟内存的页面大小。
内核位每个进程维护一张叶表,该叶表描述了每页在进程虚拟地址空间的位置;若进程试图访问的地址并无叶表条目与之对应,那么进程将收到一个SIGSEGV信号。
munmap(),shmdt(),brk,srk,malloc族;
分页内存管理单元(PMMU),虚拟内存管理使进程的虚拟地址空间与RAM物理地址空间隔离开来,这带来许多优点:进程与进程、进程与内核相互隔离;多个进程共享内存,shmget()和mmap(),;便于实现内存保护机制;无需关注程序在RAM中的物理布局;一个进程所占用的内存可超出RAM容量;增大进程运行数量,提高CPU的利用率。
五、栈和栈帧:用户栈和内核栈。
函数实参和局部变量;
函数调用的链接信息;
六、命令行参数(argc,argv)
/proc/PID/cmdline,/proc/self/cmdline;program_inovation_name和program_inovation_short_name提供了不含目录的程序的完整路径和程序名称;
ARG_MAX常量定义于 < limits.h >,sysconf(_SC_ARG_MAX)可以获取该上限值;
下限值为_POSIX_ARG_MAX个字节;资源软限制(RLIMIT_STACK),在调用execve()时已经生效;
getopt函数可以解析命令行参数。
七、环境列表:每一个进程都有与其相关的称之为环境列表的字符串数组,或者成为环境(name=value的成对集合)。
新进程创建之时,会继承其父进程的环境副本,这也是一种原始的进程间通信方式(这一信息的传递是单向的、一次性的)。
可以通过设置环境变量来改变一些库函数的行为。
程序访问环境变量:全局变量char **envirion;main函数的char *envp[],作用域在main函数;getenv()函数,
修改环境变量:setenv(),putenv(),unsetenv();clearenv();
执行非局部跳转:setjmp()和longjmp()。函数嵌套的返回,longjmp调用不能跳转到一个已经返回的函数,多线程也不能跨线程返回;优化编译器的问题,恢复CPU寄存器副本导致优化变量值得错误,使用volatile。
一、堆上分配内存:program break(当前内存边界)。
1、brk()和sbrk()用于改变堆的大小;
2、malloc()和free();program break可能不变.
3、malloc()和free()的实现;分配内存有内存块的长度;空闲内存有长度、前一块空闲内存的指针、后一块空闲内存的指针。
4、malloc调试工具和库:mtrace和muntrace(MALLOC_TRACE变量定义了写入跟踪信息的文件名),mcheck和mprobe函数(必须使用cc-lmcheck选项和mcheck库链接),MALLOC_CHECK_环境变量;
5、控制和监测malloc函数包:mallopt函数能修改各项参数以控制malloc所采用的算法,另一参数则规定了从堆中分配的内存块大小的上限,超出上限的内存块则使用mmap系统调用;mallinfo返回的是分配内存的各种统计数据。
6、在堆上分配内存的其他方法:calloc和realloc,;
分配对齐内存:memalign和posix_memalign,
二、在堆栈上分配内存:alloca();
用户ID和组ID:确定系统资源的所有权;对进程对系统资源的权限加以控制。
一、密码文件:/etc/passwd:登录名-密码-用户ID-组ID-注释-主目录-登录shell。NIS(网络信息系统)和LDAP(轻型目录访问协议)密码信息可能会由远端系统保存。密码对于getpwnam和getpwuid等函数,对于应用程序都是透明的。
二、shadow密码文件:/etc/shadow
特权程序才能访问的shadow密码文件。
三、组文件:/etc/group
字段:组名-加密的组密码-组ID-用户列表。
四、获取用户和组的信息
从密码文件中获取记录:getpwnam,getpwuid,返回静态的passwd结构体指针,
shadow密码文件中获取记录:getspnam,getspent,setspent,endspent,返回spwd结构体指针,
组文件中获取记录:getgrnam,getgrgid,返回静态分配的group结构体指针,
扫描密码文件和组文件的所有记录:setpwent,getpwent,endpwent,顺序扫描密码文件的记录;
密码加密和用户认证:crypt函数(DES加密或MD5加密),getpass用于读取用户密码,
注意:指针传参和值传参的区别。
每个进程有一套用数字表示的用户ID和组ID,将这些ID称之为进程凭证。
包括:实际用户ID(real user ID)和实际组ID(real group ID),有效用户ID(effective user ID)和有效组ID(effective group ID),保存的set-user-ID(saved set-user-ID)和保存的set-group-ID(saved set-group-ID),文件系统用户ID(file-system user ID)和文件系统组ID(file-system group ID)(Linux专用),辅助组ID。
一、实际用户ID和实际组ID:登录过程中从密码文件中读取的第三和第四字段,当创建新进程时,将从其父进程中继承这些ID。
二、有效用户ID和有效组ID:此类ID决定系统授予进程的权限,资源的属主则是由用户ID和组ID决定,内核还会使用有效用户ID来决定一个进程是否能够向另一个进程发送信号。通常有效用户ID和组ID与实际的ID相等,但有两种方法能够致使二者不同,其一是系统调用,其二是执行set-user-ID和set-group-ID程序。
三、set-user-ID和set-group-ID程序:chmod u+s proc;chmod g+s proc;
四、保存的set-user-ID(saved set-user-ID)和保存的set-group-ID(saved set-group-ID):由对应的有效ID复制而来。不少系统调用允许将set-user-ID程序的有效ID在实际ID和saved ID之间切换,游走于两种状态之间。
五、文件系统用户ID和组ID:跟随有效用户ID和组ID变化,只有使用Linux特有的两个系统调用setfsuid和setfsgid时,才能刻意制造出文件系统ID与相应的有效ID的不同。
六、辅助组ID:辅助组用于标识进程所属的若干附加的组,新进程继承父进程的ID,登录shell从系统组文件获取。
七、获取和修改进程凭证:
getuid,geteuid,getgid,getegid:获取实际和有效ID;
setuid,setgid:修改有效ID,当非特权调用setuid时,只能将有效用户ID改成实际用户ID或者保存set-user-ID,当特权调用setuid时,实际用户ID、有效用户ID和保存set-user-ID都被置为uid指定的值,过程是单向的;
seteuid,setegid:setreuid,setresuid,setregid;
setreuid,setregid:
getresuid,getresgid:
setresuid,setresgid:0/1效应,要么全部成功,要么全部失败。
setfsuid,stefsgid:
getgroups(获取和修改辅助组ID):调用程序需要分配好空间,返回组ID的数量,为了避免超出数组的大小,可以用常量NGROUPS_MAX+1申请;还可以使用sysconf获取;或者Linux特有的/proc/sys/kernel/ngroups_max只读文件读取;特权进程可以使用setgroups和initgroups来修改辅助组ID,前者用数组来替换,后者扫描/etc/groups文件,为user创建属组列表, 以此来初始化调用进程的辅助组ID。
真实时间:一个为日历时间,一个为进程生命周期流逝时间或者挂钟时间;
进程时间:进程所使用CPU的总时间,适用于对程序、算法性能的检查和优化;
一、日历时间:gettimeofday(),time(),ctime(),