以下の内容はhttps://devlights.hatenablog.com/entry/2025/05/22/073000より取得しました。


Goメモ-579 (Syscall6関数を使ってシステムコールの呼び出し)(syscall.Syscall, unix.Syscall, 引数6つまで)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

syscallパッケージやunixには Syscall6 という関数が用意されています。

これはsyscall(2)のラッパーです。間接システムコールと呼ばれます。

普段ほぼ利用することなんて無い関数ですが、極々たまにglibcにラップされていないシステムコールをGo側から呼び出したい場合などに利用できたりします。

個人的に、存在はしってましたが使ったこと無かったので、試しにサンプル作ってみました。

unixパッケージの方を利用しています。

今回は Syscall6のサンプルです。こちらは引数が6つまでのシステムコールに利用します。

3つまでの場合は Syscallの方を利用した方が分かりやすいですね。

サンプル(間接システムコールの呼び出し)

main.go

package main

import (
    "log"
    "unsafe"

    "golang.org/x/sys/unix"
)

func main() {
    log.SetFlags(0)

    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    //
    // unix.Syscall6()を使って mmap(2) を呼び出し
    //

    // ファイルディスクリプタを取得
    var (
        fileName = "/etc/hosts"
        fd       int
        err      error
    )
    fd, err = unix.Open(fileName, unix.O_RDONLY, 0)
    if err != nil {
        return err
    }
    defer unix.Close(fd)

    // ファイルサイズを取得
    var (
        stat  unix.Stat_t
        fsize int64
    )
    err = unix.Fstat(fd, &stat)
    if err != nil {
        return err
    }

    fsize = stat.Size

    // mmap(2)を利用してメモリにマッピング
    //   引数については man 2 mmap で調べられる
    //
    // そもそも、unixパッケージには
    //   - unix.Mmap()
    //   - unix.Munmap()
    // が存在するので、それを利用するのが普通です。
    //
    // 本サンプルは、unix.Syscall6()を試す為の実装です。
    var (
        trap   = uintptr(unix.SYS_MMAP)
        addr   = uintptr(0)               // アドレスヒント(0は自動割当)
        length = uintptr(fsize)           // ファイルサイズ
        prot   = uintptr(unix.PROT_READ)  // 読み取り専用
        flags  = uintptr(unix.MAP_SHARED) // マッピングフラグ(共有)
        fdptr  = uintptr(fd)              // ファイルディスクリプタ
        offset = uintptr(0)               // オフセット
        errno  unix.Errno

        unmap = func(addr uintptr) {
            unix.Syscall(unix.SYS_MUNMAP, addr, length, uintptr(0))
        }
    )
    addr, _, errno = unix.Syscall6(trap, addr, length, prot, flags, fdptr, offset)
    if errno != 0 {
        err = errno
        return err
    }
    defer unmap(addr)

    // 先頭 Nバイト 分を見る
    const (
        dispSize = 50
    )
    var (
        // VSCodeなどで作業していると「possible misuse of unsafe.Pointer」という警告が出るが
        // mmapの戻り値はメモリアドレスを表すuintptr値なので、以下のunsafe.Pointerへの変換は安全です。
        ptr  = (*byte)(unsafe.Pointer(addr))
        data = unsafe.Slice(ptr, int(fsize))
    )
    if fsize >= dispSize {
        log.Println(string(data[:dispSize]))
    } else {
        log.Println(string(data))
    }

    return nil
}

Taskfile.yml

# https://taskfile.dev

version: '3'

tasks:
  default:
    cmds:
      - rm -f ./app
      - go build -o app .
      - ./app

実行結果

$ task
task: [default] rm -f ./app
task: [default] go build -o app .
task: [default] ./app
# Kubernetes-managed hosts file.
127.0.0.1       localho

参考情報

https://github.com/devlights/try-golang/tree/main/examples/syscall6/syscall6

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。




以上の内容はhttps://devlights.hatenablog.com/entry/2025/05/22/073000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14