库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

第一章 环境

Ubuntu 14.10

Linux 3.18.6

第二章 源代码

转自:http://www.cnblogs.com/bastard/archive/2012/08/31/2664896.html

并进行过修改。

C

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main ()
{
  pid_t fpid; 
  int count=0;
  fpid=fork();
  if (fpid < 0)
    printf("error in fork!");
  else if (fpid == 0)
    {
      printf("I am the child process, my process id is %d\n",getpid());
      count++;
    }
  else
    {
      printf("I am the parent process, my process id is %d\n",getpid());
      count++;
    }
  printf("Result is: %d\n",count);
  return 0;
}

AT&T

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main ()
{
  pid_t fpid; 
  int count=0;
  asm volatile(
	       "mov $0,%%ebx\n\t"
	       "mov $0x2,%%eax\n\t"
	       "int $0x80\n\t"
	       "mov %%eax,%0\n\t"
	       :"=m"(fpid)
	       );
  if (fpid < 0)
    printf("error in fork!");
  else if (fpid == 0)
    {
      printf("I am the child process, my process id is %d\n",getpid());
      count++;
    }
  else
    {
      printf("I am the parent process, my process id is %d\n",getpid());
      count++;
    }
  printf("Result is: %d\n",count);
  return 0;
}

在编译的时候提示:

fork_call.c: Assembler messages:
fork_call.c:10: Error: operand size mismatch for `int'
fork_call.c:11: Error: operand type mismatch for `mov'

对比才发现是一些符号的问题,在此检讨,要细心,多分析。

结果:

C


AT&T


下面便是调试了。

第三章 调试

输入以下命令开始调试

$gcc -m32 -g -o fork_call fork_call.c
$gdb fork_call -tui -q
接着先查看源代码

(gdb)layout src
设置断点
(gdb)break main
查看寄存器
(gdb)layout regs
逐条运行
(gdb)si
这里提一下:si的运行取决于layout所看的视图是汇编视图还是源代码视图,汇编视图逐汇编语句运行,源代码视图逐源代码语句运行。
调试截图:






第四章 分析

由调试过程可知:

首先将ebx设置成0,然后将eax设置成2,这样就可以通过syscall_32.tbl进行调用fork()函数运行。然后返回eax返回函数值0xf4b,于是便完成了调度。不过,在将eax设置成2后,有一个段代码:int 0x80。这个的意思是产生中断,这样我们便可以从用户态转换为内核态,从而调用了系统的函数fork()。


第五章 总结

系统是通过中断的方式将用户态转换为内核态,同时调用系统函数来实现系统功能。当系统中断出现时,CPU保护现场和上下文切换来保护目前用户态所运行的状态,并通过返回系统调用函数的值来让用户判断是否已经有效地调用,结果如何。如exit(),waitpid(),getpid(),fork(),sysinfo()等等。这些方式就是系统级应用程序接口对用户系统编程提供的帮助,使用户更好地管理内核。

下面是一篇博文对int 0x80的解析:(http://blog.csdn.net/u010467259/article/details/40130599)

软中断实现过程:

原因:通过限定应用程序和内核程序使用不同的内存分配函数,将用户空间程序限制在0-3G空间,将内核程序限制在3G~4G空间,这样就实现了用户空间和内核空间的隔离;
交互方式:通过 软中断(int $0x80 )实现用户空间与内核空间的交互。
系统调用是一个软中断,中断号是0x80,它是上层应用程序与Linux系统内核进行交互通信的唯一接口。通过int 0x80,就可使用内核资源。不过,通常应用程序都是使用具有标准接口定义的C函数库间接的使用内核的系统调用,即应用程序调用C函数库中的函数,C函数库中再通过int 0x80进行系统调用。 所以,系统调用过程是这样的:
应用程序调用libc中的函数->libc中的函数引用系统调用宏->系统调用宏中使用int 0x80完成系统调用并返回。

最基本代码实现:
在linux中 , int $0x80 这种异常被称作系统调用(system call) ,内核中也提供了许多系统服务供用户程序使用 ,但这些系统服务不能像库函数一样用的为所欲为, 原因在于 :执行用户程序的时候CPU处于用户模式 ,经由异常处理的程序进入到内核 ,用户只能通过寄存器传递几个参数 ,之后就要按照内核设计好的代码路线走 ,调用结束后 ,CPU在切回到用户模式, 继续执行下一条 int $0x80 的下一条指令。 

第六章 拓展

汇编调用getpid()函数。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
  pid_t fpid;
  int ret=0;
  int count=0;
  asm volatile(
	       "mov $0,%%ebx\n\t"
	       "mov $0x2,%%eax\n\t"
	       "int $0x80\n\t"
	       "mov %%eax,%0\n\t"
	       :"=m"(fpid)
	       );
  if (fpid < 0)
    printf("error in fork!");
  else if (fpid == 0)
    {
      asm volatile(
		   "mov $0,%%ebx\n\t"
		   "mov $0x14,%%eax\n\t"
		   "int $0x80\n\t"
		   "mov %%eax,%0\n\t"
		   :"=m"(ret)
		   );
      printf("I am the child process, my process id is %d\n",ret);
      count++;
    }
  else
    {
      asm volatile(
		   "mov $0,%%ebx\n\t"
		   "mov $0x14,%%eax\n\t"
		   "int $0x80\n\t"
		   "mov %%eax,%0\n\t"
		   :"=m"(ret)
		   );
      printf("I am the parent process, my process id is %d\n",ret);
      count++;
    }
  printf("Result is: %d\n",count);
  return 0;
}

汇编调用open(char *,char *)函数

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
  FILE *file=NULL;
  char *filename="1.txt";
  char *r="r";
  asm volatile(
	       "mov $0,%%ebx\n\t"
	       "mov %1,%%ebx\n\t"
	       "mov %2,%%ecx\n\t"
	       "mov $0x5,%%eax\n\t"
	       "int $0x80\n\t"
	       "mov %%eax,%0\n\t"
	       :"=m"(file)
	       :"b"(filename),"c"(r)
	       );
  return 0;
}


附录


卢晅 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值