写自己的函数直接调用Linux system call

     众所周知,Linux系统调用是访问Linux内核的必经之路。作为上层软件开发着来说,一般无须考虑自己的程序是如何通过Linux kernel system call 层,因为这是libc的任务,程序员只需要知道libc提供的接口就可以了。但是,有时候为了定制或实现新的LibC一类的需要调用system call的软件包或这软件,了解如何写自己的可以直接调用Linux 系统调用的函数是必要的。在这篇文章中,给出了一个简单的调用write()系统调用的汇编代码和C中嵌入汇编两种方法实现的软件。
    预备知识:
    软件中断的产生。首先是通过“int 0x80”指令产生0x80号软件中断。Linux规定了0x80号中断是内核系统调用的中断门。当然,操作系统设计人员在设计系统时,可以更改该中断号。
  系统调用号。每一个系统调用都分配了唯一的一个系统调用号,该调用号可以通过访问include/asm-i386/unistd.h文件
  
#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
#define __NR_execve              11
#define __NR_chdir               12
#define __NR_time                13
#define __NR_mknod               14
#define __NR_chmod               15
#define __NR_lchown              16
#define __NR_break               17
#define __NR_oldstat             18
#define __NR_lseek               19
#define __NR_getpid              20
#define __NR_mount               21
#define __NR_umount              22
#define __NR_setuid              23
#define __NR_getuid              24
#define __NR_stime               25
#define __NR_ptrace              26
#define __NR_alarm               27
#define __NR_oldfstat            28
   ..........

      例如write()函数的系统调用号是4(#define __NR_write                4)
      确定函数参数。在调用系统调用之前,要确定相应系统调用函数的个数,意义。通常,函数的参数分别通过不同寄存器传递。以X86为例,在linux- 2.6.17中,ebx, ecx, edx 分别代表第1,2,3个参数。由于Linux kenel 不同,其函数参数的传递通常有其对应的compiler确定。函数参数个数的去定可以通过搜索: sys_syscall_name() 函数。以write为例:
      asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count);
    
      现在你已经了解基本的概念和技术,现在看一下下面两个简单的程序,他们是将“hello world”输出到屏幕。当然是同多调用write 系统调用完成的。

/* write.S*/
    
.text

.globl  _start, _exit, message
.align 4

_start:
        /* Reseting EFLAGS */
        pushl $0
        popf

        push %eax               /* Save the register value*/
        push %ebx
        push %ecx
        push %edx

        mov $4, %eax            /* system call number, write_sys() */
        mov $1, %ebx            /* file description */
        mov $message, %ecx      /* message address */
        mov $14, %edx           /* message size */
        int $0x80               ;

        pop %edx                /* Restore the resigter value*/
        pop %ecx
        pop %ebx
        pop %eax

_exit:

        mov $1, %eax
        int $0x80

message:
        .asciz "hello world./n" ;


/* write.c*/

static char message[]={"hello world!/n"};

int main(int argc, char *argvs)
{
        int size;
        asm volatile( /
                "int $0x80" /
                : "=a"(size)
                : "0"(4), "b"(1), "c"(message), "d"(13));

        return 0;
}

             
    有兴趣的可以用反汇编看一下二者经过编译后有什么区别。

你可能感兴趣的:(linux,汇编,System,任务,compiler,linux内核)