Linux 基础
实验四
一.实验过程
1.使用库函数API触发一个系统调用
1.1例子(time库函数)
#include <stdio.h>
#include <time.h>
int main(){
time_t tt;
struct tm *t;
tt=time(NULL);
t=localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
1.2例子内嵌汇编(time库函数)
#include <stdio.h>
#include <time.h>
int main(){
time_t tt;
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t"
"mov $0xd,%%eax\n\t"
"int $0x80\n\t"
"mov %%eax,%0\n\t"
:"=m"(tt)
);
t=localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
2.getpid()库函数
C语言直接调用,其中必须添加sys/types.h的头文件
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
int i=getpid();
printf("my pid is: %d\n",i);
return 0;
}
内嵌汇编代码的getpid
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){
int i;
asm volatile(
"mov $0,%%ebx\n\t"//把ebx寄存器清零
"mov $0x14,%%eax\n\t"//getpid的系统调用号是20
"int $0x80\n\t"//触发系统调用
"mov %%eax,%0\n\t"//通过eax寄存器返回系统调用值
:"=m"(i)
);
printf("my pid is: %d\n",i);
return 0;
}
3.mkdir()函数
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(){
int flag=-1;
flag=mkdir("/home/qed/homework/05/mydir",0755);
if(flag==-1)
printf("u failed!\n");
else
printf("u succeess!\n");
return 0;
}
内嵌汇编代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(){
int flag=-1;
char *dir="/home/qed/homework/05/mydir1";
//flag=mkdir("/home/qed/homework/05/mydir",0755);
asm volatile(
"movl $0x27,%%eax\n\t"
"movl %1,%%ebx\n\t"
"int $0x88\n\t"
"movl %%eax,%0\n\t"
:"=m"(flag)
:"c"(dir)
);
if(flag==-1)
printf("u failed!\n");
else
printf("u succeess!\n");
return 0;
}
二.遇到的问题
在mkdir_asm函数执行的时候遇到了问题
这个问题暂不知道如何解决,在getpid的代码中也遇到了相似的问题,但因在实验楼的环境中运行时未出现如上错误,但在自己的虚拟机上便会出现,起初认为是因为虚拟机是64位,实验楼为32位导致的问题,但是在虚拟机上用-m32命令也未起效。
三.系统调用汇总
内核分为用户态和内核态,在用户态下程序不内直接访问内核数据结构或者内核程序,只有在内核态下才可访问。请求内核服务的进程使用系统调用的特殊机制,每个系统调用都设置了一组识别进程请求的参数,通过执行CPU指令完成用户态向内核态的转换。
32位系统中,通过int $0x80指令触发系统调用。其中EAX寄存器用于传递系统调用号,参数按顺序赋值给EBX、ECX、EDX、ESI、EDI、EBP这6个寄存器。
64位系统则是使用syscall指令来触发系统调用,同样使用EAX寄存器传递系统调用号,RDI、RSI、RDX、RCX、R8、R9这6个寄存器则用来传递参数。
操作系统对于中断处理流程一般为(顺序有先后):
关中断:CPU关闭中段响应,即不再接受其它外部中断请求
保存断点:将发生中断处的指令地址压入堆栈,以使中断处理完后能正确地返回。
识别中断源:CPU识别中断的来源,确定中断类型号,从而找到相应的中断服务程序的入口地址。
保护现场所:将发生中断处理有关寄存器(中断服务程序中要使用的寄存器)以及标志寄存器的内存压入堆栈。
执行中断服务程序:转到中断服务程序入口开始执行,可在适当时刻重新开放中断,以便允许响应较高优先级的外部中断。
恢复现场并返回:把“保护现场”时压入堆栈的信息弹回原寄存器,然后执行中断返回指令(IRET),从而返回主程序继续运行。