linux平台学x86汇编(十七):在汇编中使用linux系统调用

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
        在前面章节我们已经看到,启动系统调用需要使用INT指令。linux系统调用位于中断0x80,执行INT指令时,所有操作转移到内核中的系统调用处理程序,完成后执行转移到INT指令之后的下一条指令。
        linux的系统调用在如下文件(32位系统)可以查看:
$ cat /usr/include/asm/unistd_32.h
#ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H

/*
 * This file contains the system call numbers.
 */

#define __NR_restart_syscall      0
#define __NR_exit  1
#define __NR_fork  2
#define __NR_read  3
#define __NR_write  4
#define __NR_open  5
#define __NR_close  6
#define __NR_waitpid  7
#define __NR_creat  8
#define __NR_link  9
#define __NR_unlink 10
......
        上面文件中系统调用名称后面的整数就是系统调用值,每个系统调用都被分配了唯一的数字以便标识它。在前面章节的范例中我们已经知道eax寄存器用于保存系统调用值。在执行INT指令之前,期望的值被传送到eax寄存器中,这时,系统调用已经准备好了,接下来就是给系统调用准备参数的时候了。和我们自己写的函数输入值存放在堆栈中不同,系统调用的输入参数存放在寄存器中。输入值存放到寄存器中的顺序也是很重要的,系统调用期望的输入值顺序(第1到第5个参数)如下:ebx、ecx、edx、esi、edi。需要超过6个输入参数的系统调用使用不同方法吧参数传递给系统调用,使用ebx寄存器用于保存指向输入参数的内存位置的指针。
        在本系列文章前面我们打印“hello world!”一节中使用到write系统调用代码如下:
_start:                                 #函数在屏幕上输出hello world!
movl $len, %edx               #第三个参数: 字符串长度
movl $msg, %ecx             #第二个参数: hello world!字符串
movl $1, %ebx                  #第一个参数: 输出文件描述符
movl $4, %eax                  #系统调用号sys_write
int $0x80                            #调用内核功能
输入值被依次分配到了ebx、ecx、edx寄存器中,而系统调用号4被分配到了eax寄存器中。 
        系统调用的返回值存放在eax寄存器中,在实际使用时,可以判断系统调用的返回值。
        注意到系统调用函数和C库函数的是由区别的,C库函数的输入参数是在堆栈中,而系统调用的输入参数在寄存器中。在是使用C库函数还是使用系统调用函数问题上,原则是看哪一种方法更适合时间的应用。C库的优点是在操作系统之间方便移植、C库可以在程序之间利用共享库,减少内存需求。linux系统调用的优点是不需要吧外部库链接到程序中,可以尽可能创建最短、最快的代码。

你可能感兴趣的:(linux平台学x86汇编)