---
id: c90263519492728e7cc2d0ce840057b6
author: Yunjin Lee
title: Chiamate di sistema Linux dirette in Go puro con syscall.Syscall e unsafe.Pointer
description: Invocare le system call del kernel Linux, come SYS_SYSINFO, direttamente da Go puro utilizzando struct allineate all'ABI, unsafe.Pointer e il pacchetto standard syscall, senza cgo.
language: it
date: 2025-10-26T12:31:21.655228078Z
path: /blog/posts/go-syscall-is-a-brilliant-replacement-of-low-level-i-o-za50951e1
category: lowlevel
---

## Riepilogo

Impareremo a conoscere le chiamate di sistema dirette in Go.
Poiché Go offre errori di compilazione rigorosi e un garbage collector rigido, è molto preferibile sostituire le chiamate di basso livello con Pure Go.
Fortunatamente, la maggior parte delle chiamate di funzione del C è stata completamente reimplementata in Go, in modo valido e contemporaneo.
Diamo un'occhiata.

## Chiamata di sistema

Una chiamata di sistema è una richiesta diretta al sistema operativo.
Poiché il sistema è solitamente scritto in uno stile rigido e antiquato, dato che viene eseguito direttamente sull'hardware, dobbiamo considerare che la sua chiamata debba fornire una forma della richiesta rigorosa e corretta.
Quindi, anche se non ci servono alcune variabili, dobbiamo comunque riempire la dimensione indipendentemente dall'uso.
Vediamo un esempio completamente funzionante.

## Esempio completo

```go
package main
import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	Uptime    int64
	Loads     [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	Procs     uint16
	Pad       uint16
	_         [4]byte
	Totalhigh uint64
	Freehigh  uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	scale := float64(1 << 16)
	fmt.Printf("Uptime: %d seconds\n", info.Uptime)
	fmt.Printf("Load Average: %.2f %.2f %.2f\n",
		float64(info.Loads[0])/scale,
		float64(info.Loads[1])/scale,
		float64(info.Loads[2])/scale)
	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Processes: %d\n", info.Procs)
}
```

Questo esempio include tutte le variabili e stampa informazioni dettagliate sulle informazioni di sistema correnti.
Possiamo paragonare questo codice a una serratura e a una chiave.
`syscall.SYS_SYSINFO` è una chiave che apre una serratura situata all'interno del kernel.
Pertanto, è importante usare la chiave corretta per la serratura.
Cosa succede se usiamo `syscall.SYS_GETPID` per questa chiamata?
Questa è la chiave per una serratura che contiene l'ID del processo.
Ciò tenterà di ottenere un PID da uno spazio dedicato alle informazioni di sistema.
Di conseguenza, nessuna delle informazioni può essere letta correttamente; la chiamata deve restituire uno stato di errore.

Ora, dobbiamo sapere quali elementi sono contenuti e come sono ordinati.
Nella prima posizione della serratura troviamo Uptime, di dimensione 2^64.
Se proviamo a leggerlo con 2^32, la sequenza di bit non viene letta completamente.
Non possiamo utilizzare questi tipi di sequenze parziali di bit, a meno che non si voglia ricorrere a trucchi di basso livello.

Dopo aver letto 64 bit di dati binari, finalmente ci troviamo nella seconda posizione.
Essa può essere letta correttamente solo dopo aver letto il precedente intero a 64 bit.

Ripetendo questi flussi rigorosi e logici, è possibile ottenere le informazioni corrette dal sistema e gestire correttamente i dati letti.

## Come saltare i "nomi delle variabili"

Anche se non possiamo "saltare" le variabili stesse, è importante distinguere le variabili utilizzate da quelle scartate.
Se l'uso del programma è sufficientemente chiaro, è preferibile usare variabili senza nome come segnaposto piuttosto che etichettare ogni valore, anche se non verranno utilizzati per sempre.
Vediamo questo aspetto con un esempio, "Free Memory Checker".

## Esempio - Free Memory Checker

Quando si controllano la memoria libera e lo swap, non abbiamo bisogno delle altre informazioni che indicano risorse diverse.
Per ottenere una migliore leggibilità, è possibile creare variabili anonime per contenere specifici spazi.

```go
package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	_          int64
	_         [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	_         uint16  // anonimi, e quelli non utilizzati sono contrassegnati con _
	_         uint16
	_         [4]byte
	_         uint64
	_         uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
}
```

Di conseguenza, le variabili vengono lette senza etichette.
Sebbene i valori anonimi siano effettivamente memorizzati in una struttura, nel codice non ci sono etichette o segni leggibili.

## Conclusione

- Usare `syscall` e `unsafe` di Go è ancora più sicuro rispetto a C/CGo
- Se si sta scrivendo un progetto ampio che può essere facilmente esteso:
  - Non utilizzare variabili anonime; assegnare un nome a ciascun membro.
- Se si sta scrivendo un progetto con un utilizzo limitato:
  - È possibile usare variabili anonime per riservare gli spazi effettivamente inutilizzati.
- `syscall` di Go è potente e moderno per gestire le chiamate di basso livello

## Approfondimenti

[syscall](https://pkg.go.dev/syscall)
[unsafe](https://pkg.go.dev/unsafe)
[x/sys/unix](https://pkg.go.dev/golang.org/x/sys/unix)
