Go 语言系统调用简析

一、系统调用概述

系统调用是受控的内核入口,借助于这一机制,进程可以请求内核以自己的名义去执行某些动作。Linux 内核以 C 语言语法 API 接口形式(头文件),提供有一系列服务供程序访问。可以通过 man 2 syscall 查看系统调用信息。

关于系统调用,需要注意以下几点: 1、系统调用将处理器从用户态切换到核心态,以便 CPU 访问受到保护的内核内存; 2、系统调用的组成是固定的,每个系统调用都由一个唯一的数字来标识; 3、每个系统调用可辅之以一套参数,对用户控件(进程虚拟地址控件)与内核空间之间(相互)传递的信息加以规范;

以C语言为例,执行系统调用时,幕后会历经诸多步骤。以 x86-32 平台为例,按时间发生顺序对这些步骤加以分析: 1、应用程序通过 C 语言函数库中的外壳(wrapper)函数,来发起系统调用; 2、对系统调用中断处理例程来说,外壳函数必须保证所有的系统调用参数可用。通过堆栈,这些参数传入外壳函数,但内核却希望将这些参数置入特定寄存器。因此,外壳函数会将上述参数复制到寄存器; 3、由于所有系统调用进入内核的方式相同,内核需要设法区分每个系统调用。为此,外壳函数会将系统调用编号复制到一个特殊的 CPU 寄存器 (%eax) 中; 4、外壳函数执行一条中断机器指令(int 0×80),引发处理器从用户态切换到核心态,并执行系统中断 0×80(十进制128)的中断矢量所之指向的代码;(2.6内核 和 glibc 2.3.2 以后的版本支持 sysenter 指令,进入内核速度更快); 5、为响应中断 0×80,内核会调用 system_call 例程(内核源码中 arch/i386/entry.S)来处理这次中断; 6、若系统调用服务例程的返回值表明调用有误,外壳函数会使用该值来设置全局变量 errno,然后外壳函数会返回到调用程序,并同时返回一个整数值,以表明系统调用是否成功;

二、Go 语言封装的系统调用

Go 语言调用系统调用,并没有使用系统提供的 C 语言函数形式,而是自己封装了系统调用。以 AMD64 为例,Go 语言提供了如下调用系统调用的方式:

  1. func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
  2. func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
  3. func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
  4. func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)

复制代码

其中,Syscall 和 RawSyscall 的区别如下:(以6结尾的一样) 从源码可以看出,Syscall 开始和结束,分别调用了 runtime 中的进入系统调用和退出系统调用的函数,这就说明,系统调用被 runtime 运行时(调度器)管理,系统调用可以在任何 goroutine 中执行;而 RawSyscall 并没有,因此它可能会阻塞,导致整个程序阻塞。我们应该总是使用 Syscall,RawSyscall 存在的意义是为那些永远不会阻塞的系统调用准备的,比如 Getpid。我们自己的程序需要时,应该用 Syscall。 Go 中 Syscall 的实现,在汇编文件 syscall/asm_linux_amd64.s 中:

// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);

// Trap # in AX, args in DI SI DX R10 R8 R9, return in AX DX

// Note that this differs from "standard" ABI convention, which

// would pass 4th arg in CX, not R10.

TEXT    ·Syscall(SB),NOSPLIT,$0-56

    CALL    runtime·entersyscall(SB)

    MOVQ    a1+8(FP), DI

    MOVQ    a2+16(FP), SI

    MOVQ    a3+24(FP), DX

    MOVQ    $0, R10

    MOVQ    $0, R8

    MOVQ    $0, R9

    MOVQ    trap+0(FP), AX    // syscall entry

    SYSCALL     // 进入内核,执行内核处理例程

    // 0xfffffffffffff001 是 linux MAX_ERRNO 取反 转无符号,http://lxr.free-electrons.com/source/include/linux/err.h#L17

    CMPQ    AX, $0xfffffffffffff001        // 发生错误,r1=-1

    JLS    ok

    MOVQ    $-1, r1+32(FP)

    MOVQ    $0, r2+40(FP)

    NEGQ    AX             // 错误码,因为错误码是负数,这里转为正数

    MOVQ    AX, err+48(FP)

    CALL    runtime·exitsyscall(SB)

    RET

ok:

    MOVQ    AX, r1+32(FP)

    MOVQ    DX, r2+40(FP)

    MOVQ    $0, err+48(FP)

    CALL    runtime·exitsyscall(SB)

    RET


相关参考文献 https://groups.google.com/forum/#!searchin/golang-nuts/Syscall$20RawSyscall/golang-nuts/y9lT_1loJj4/g4ZrYB2_80YJ 《The Linux Programming Interface —A Linux and UNIX System Programming Handbook》

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2017-07-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏芋道源码1024

精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 )

本小节,我们将 《精尽 Dubbo 源码解析》 和 《Dubbo 用户指南》 做一次映射,方便大家直接找到感兴趣的功能的具体源码实现。当然,如果有整理不到位的地...

7123
来自专栏PHP实战技术

PHP初级开发者常见的5种疑问

一、文件上传需要注意哪些细节?怎么把文件保存到指定目录?怎么避免上传文件重名问题? 1). 首现要在php.ini中开启文件上传; 2). 在php.ini中有...

3846
来自专栏技术之路

翻译qmake文档(三) Creating Project Files

原英文文档:http://qt-project.org/doc/qt-5/qmake-project-files.html 创建项目文件      项目文件...

2006
来自专栏芋道源码1024

精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 )

本小节,我们将 《精尽 Dubbo 源码解析》 和 《Dubbo 用户指南》 做一次映射,方便大家直接找到感兴趣的功能的具体源码实现。当然,如果有整理不到位的地...

4742
来自专栏指尖下的Android

Android4.4运行过程中闪退java.lang.NoClassDefFoundError

上周五项目测试时发现一个奇怪的Bug,项目中依赖了一个第三方框架,但是在android4.0-4.4.4之间的系统中运行会直接闪退,抛出错误异常为java.la...

1152
来自专栏北京马哥教育

python线程笔记

豌豆贴心提醒,本文阅读时间5分钟 来源:伯乐在线 原文:http://python.jobbole.com/87498/ 引言&动机 考虑一下...

3015
来自专栏指尖下的Android

JNI之路径初探---2

上一篇博客写的是Java调用C、C++的例子,本篇就演示一下C、C++怎么调用Java的属性和方法。

1652
来自专栏GreenLeaves

WCF系列教程之WCF服务协定

本文参考自:http://www.cnblogs.com/wangweimutou/p/4422883.html,纯属读书笔记,加深记忆 一、服务协定简介: 1...

1827
来自专栏逆向技术

win32进程概念之句柄表,以及内核对象.

我们知道.我们使用CreateProcess 的时候会返回一个进程句柄.以及线程句柄. 其实在调用CreateProcess的时候.内核中会新建一个EPROCE...

912
来自专栏北京马哥教育

3000 字 Flask 快速学习指南:从入门到开发

作者:过了即是客 Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务。本文参考自Flask官方文档,...

6559

扫码关注云+社区

领取腾讯云代金券