关于系统调用函数号的问题,想使用getpid库函数,不知如何查找系统调用号。
可以进入目录LinuxKernel/linux-3.18.6/arch/x86/syscalls/
查看syscall_32.tbl,可以看到系统调用号
getpid()系统调用号为20,转化为十六进制即0x14。
还可以直接搜索linux 系统调用号表
- 使用库函数API获取进程识别码
编写2808.c,只使用了getpid()库函数获取进程识别码,注意:实验楼虚拟机是64位,gcc编译时要加-m32才能输出32位机器码
#include#include #include int main(void) { int u_id; u_id=getpid(); printf("u_id=%un",u_id); return 0; }
运行结果如下:
- C语言代码中嵌入汇编代码
进入目录LinuxKernel/linux-3.18.6/arch/x86/syscalls/
查看syscall_32.tbl,可以看到系统调用号
getpid()系统调用号为20,十六进制即0x14
编写2808_asm.c文件:
#include#include int main(void) { int u_id; asm volatile( "mov $0,%%ebxnt" "movl $0x14,%%eaxnt" "int $0x80nt" "movl %%eax, %0nt" :"=m" (u_id) ); printf("u_id=%un",u_id); return 0; }
编译运行结果如下:
3. 含两个参数的系统调用rename
rename,它在内核中的系统调用处理函数为sys_rename(),系统调用号为38,其功能是给一个文件重命名。
库函数API进行触发:
#includeint main(){ int ret; char *oldname="hello.c"; char *newname="newhello.c"; ret = rename(oldname,newname); if(ret == 0) printf("Renamed successfullyn"); else printf("Unable to rename the file"); return 0; }
创建rename.c和hello.c:
修改成功,出现newhello.c:
嵌入式汇编代码进行触发:
编写rename_asm.c,把newhello.c改回hello.c
//rename_asm.c #includeint main(){ int ret; char *oldname="newhello.c"; char *newname="hello.c"; asm volatile( "movl %1,%%ebxnt" "movl %2,%%ecxnt" "movl $0x26,%%eaxnt" "int $0x80nt" :"=a"(ret) :"b"(oldname),"c"(newname) ); if(ret == 0) printf("Renamed successfullyn"); else printf("Unable to rename the file"); return 0; }
修改成功,把newhello.c改回hello.c:
- 用户态 内核态和中断处理过程
- 用户态:在低的执行级别下,代码能够掌控的范围有所限制,只能访问部分内存。
内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理内存。
中断处理:从用户态进入内核态的主要方式。系统调用只是一种特殊的中断。中断发生后第一件事就是保护现场,进入中断程序,保存需要拥戴的寄存器的数据。中断处理结束前的最后一件事就是恢复现场,退出中断程序,恢复保存寄存器的数据。 - Intel x86 CPU定义了4种不同的执行级别0、1、2、3,数字越小特权越高。Linux系统采用了其中的0、3两个特权级别,分别对应用户态和内核态。
- 用户态和内核态很显著的区分就是CS:EIP的指向范围。用户态只能访问0x00000000~0xbbbbbbbf的地址空间,0xc0000000以上的地址空间只能在内核态下访问。
- 系统调用概述
系统调用的意义是操作系统为用户态进程与硬件设备进行交互提供了一组接口。系统调用有以下功能和特性:
1.把用户从底层的硬件编程中解放出来
2.极大地提高系统的安全性
3.使用户程序具有可移植性 - API和系统调用的关系:
- API(应用程序编程接口):只是一个函数定义。
系统调用通过软中断向内核发出了中断请求,int指令的执行就会触发一个中断请求。 - libc函数库定义的一些API内部使用了系统调用的封装例程,其主要目的是发布系统调用。
一般每个系统调用对应的一个封装例程,函数库再用这些封装例程定义出给程序员调用的API,这样把系统调用最终封装成方便程序员使用的库函数。 - API可能直接提供用户态的服务。
一个API可能只对应一个系统调用,也可能内部由多个系统调用实现;一个系统调用也可能被多个API调用。 - 系统调用的三层机制:xyz(),system_call和sys_xyz()
系统调用号将xyz和sys_xyz关联起来了。
系统调用需要输入输出参数。
system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数。



