细说linux系统调用--使用c和汇编进行系统调用

linux系统如何打印”Hello World”

1. fprintf

使用fprintf输出到stdout

#include <stdio.h>

int main(int argc, char *argv[]) {
    fprintf(stdout, "Hello World!\n");
    return 0;
}

2. write

使用write将字符串输出到STDOUT_FILENO

#include <unistd.h>

int main(int argc, char *argv) {
    const char msg[] = "Hello World!\n";
    write(STDOUT_FILENO, msg, sizeof(msg)-1);
    return 0;
}

3. syscall

使用glibc提供的syscall进行系统调用SYS_write将字符串输出到STDOUT_FILENO

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h>   /* For SYS_xxx definitions */

int main(int argc, char *argv[]) {
    const char msg[] = "Hello World!\n";
    syscall(SYS_write, STDOUT_FILENO, msg, sizeof(msg)-1);
    return 0;
}

汇编格式对比

Intel CodeAT&T Code
mov eax,1movl $1,%eax
mov ebx,0ffhmovl $0xff,%ebx
int 80hint $0x80
mov ebx, eaxmovl %eax, %ebx
mov eax,[ecx]movl (%ecx),%eax
mov eax,[ebx+3]movl 3(%ebx),%eax
mov eax,[ebx+20h]movl 0x20(%ebx),%eax
add eax,[ebx+ecx*2h]addl (%ebx,%ecx,0x2),%eax
lea eax,[ebx+ecx]leal (%ebx,%ecx),%eax
sub eax,[ebx+ecx*4h-20h]subl -0x20(%ebx,%ecx,0x4),%eax

4. nasm格式汇编

使用nasm格式汇编进行int 80h系统调用,nasm_write.s内容如下

; nasm -f elf64 nasm_write.s && ld -s -o nasm_write nasm_write.o
section .data
    hello db 'Hello world!', 10 ; ‘Hello world!’加一个换行符(10)
    len equ $-hello             ; 字符串长度

section .text
    global _start

_start:
    mov eax, 4      ; 系统调用sys_write
    mov ebx, 1      ; 文件描述符,标准输出
    mov ecx, hello  ; 设置字符串偏移地址到ecx
    mov edx, len    ; 设置字符串长度
    int 80h         ; 中断0x80, kernel系统调用syscall

    mov eax, 1      ; exit的系统调用(sys_exit)
    mov ebx, 0      ; 退出值我为0
    int 80h

编译

nasm -f elf64 nasm_write.s && ld -s -o nasm_write nasm_write.o

5. int 80h

在Linux x86和Linux x86_64系统上可以使用int $0x80制造中断0x80进行系统调用。调用参数:

Syscall #Param 1Param 2Param 3Param 4Param 5Param 6
eaxebxecxedxesiediebp
Return value
eax

在arch/x86/include/asm/unistd_32.h中,exit和write的syscall number为

#define __NR_exit 1
#define __NR_write 4

AT&T格式汇编通过int $0x80进行系统调用

# as -o gas_int.o gas_int.s && ld -s -o gas_int gas_int.o
.data   # section声明
    msg: .ascii "Hello World!\n"
    len = . - msg   # 字符串长度

.text
    .global _start

_start:
    movl $4, %eax
    movl $1, %ebx
    movl $msg, %ecx
    movl $len, %edx
    int $0x80

    movl $1, %eax
    movl $0, %ebx
    int $0x80

编译:

as -o gas_int.o gas_int.s && ld -s -o gas_int gas_int.o

6. syscall

在x86_64上有专用指令进行系统调用

Syscall #Param 1Param 2Param 3Param 4Param 5Param 6
raxrdirsirdxr10r8r9
Return value
rax

在arch/x86/include/asm/unistd_64.h中相应的syscall number

#define __NR_write 1
#define __NR_exit 60

文件gas_syscall.s

# as -o gas_syscall.o gas_syscall.s && ld -s -o gas_syscall gas_syscall.o
.data
    msg: .ascii "Hello World!\n"
    len = . - msg   # 字符串长度

.text
    .global _start

_start:
    movq $1, %rax
    movq $1, %rdi
    movq $msg, %rsi
    movq $len, %rdx
    syscall

    movq $60, %rax
    movq $0, %rdi
    syscall

编译

as -o gas_syscall.o gas_syscall.s && ld -s -o gas_syscall gas_syscall.o

7. 内联方式调用syscall

gcc -nostdlib不连接glibc库

/**
 * 在c语言中内联汇编,使用AT&T风格
 * 编译: gcc -nostdlib inline.c -o inline
 */

/**
 * @brief 通过系统调用打印字符串
 */
void my_printf(char *s, int len) {
    long ret;
    __asm__ volatile(
        "int $0x80"     /* 系统调用 */
        : "=a" (ret)    /* 返回值eax("a") */
        : "0"(4),       /* 系统调用号sys_write */
          "b"(1),       /* 参数ebx,文件句柄1=标准输出 */
          "c"(s),       /* 参数ecx, 字符串 */
          "d"(len)      /* 参数edx, 字符长度 */
    );
}

/**
 * @brief 程序入口
 */
void _start() {
    /* main body of program: call main(), etc */
    char *s = "Hello world!\n";
    my_printf(s, 13);

    /* exit system call */
    asm("movl $1,%eax;"
        "xorl %ebx,%ebx;"
        "int  $0x80"
    );
}

参考
+ Hello, world!
+ Linux System Call Table
+ Linux Assembly HOWTO 6.2. Hello, world!
+ X86 Assembly/Interfacing with Linux
+ X86 Assembly/NASM Syntax
+ What is better “int 0x80” or “syscall”?
+ Linux C中内联汇编的语法格式及使用方法(Inline Assembly in Linux C)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值