---
id: c90263519492728e7cc2d0ce840057b6
author: Yunjin Lee
title: Apeluri directe de sistem Linux în Go pur, cu syscall.Syscall și unsafe.Pointer
description: Invocarea apelurilor de sistem Linux precum SYS_SYSINFO direct din Go pur, utilizând structuri aliniate conform ABI, unsafe.Pointer și pachetul standard syscall, fără cgo.
language: ro
date: 2025-10-26T12:31:21.655228078Z
path: /blog/posts/go-syscall-is-a-brilliant-replacement-of-low-level-i-o-za50951e1
category: lowlevel
---

## Rezumat

Vom învăța despre apelurile de sistem directe în Go.
Deoarece Go oferă erori stricte la compilare și un colector de gunoi (GC) riguros, este mult mai bine să înlocuim apelurile de nivel jos cu Pure Go.
Din fericire, majoritatea apelurilor de funcții C sunt reimplementate integral în Go, într-un mod bun și contemporan.
Să le analizăm.

## Apel de sistem

Un apel de sistem este o cerere directă adresată sistemului de operare.
Deoarece sistemul este de obicei scris într-un stil rigid și demodat, întrucât rulează direct pe hardware, trebuie să ținem cont de faptul că apelul său trebuie să transmită o formă strictă și corectă a cererii.
Astfel, chiar dacă nu avem nevoie de unele variabile, trebuie totuși să completăm dimensiunea, indiferent de utilizare.
Să verificăm printr-un exemplu complet funcțional.

## Exemplu complet

```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)
}
```

Acest exemplu include toate variabilele și afișează informații extinse despre informațiile curente ale sistemului.
Putem compara acest cod cu o cutie cu încuietoare și o cheie.
`syscall.SYS_SYSINFO` este o cheie care deschide o cutie aflată în interiorul nucleului.
Prin urmare, utilizarea cheii corecte pentru cutie este importantă.
Ce se va întâmpla dacă folosim `syscall.SYS_GETPID` pentru acest apel?
Aceasta este o cheie pentru o cutie care conține ID-ul procesului.
Aceasta va încerca să obțină un PID dintr-un spațiu destinat informațiilor de sistem.
Drept urmare, niciuna dintre informații nu poate fi citită corect; apelul trebuie să returneze o stare de eșec.

Acum, trebuie să știm ce elemente sunt conținute și cum sunt ordonate.
În primul compartiment al cutiei se află Uptime, cu o dimensiune de 2^64.
Dacă încercăm să citim acest câmp cu 2^32, secvența de biți nu este citită integral.
Nu putem utiliza astfel de fragmente binare parțiale, decât dacă dorim să scriem trucuri de nivel jos.

După citirea a 64 de biți de date binare, ajungem în sfârșit la al doilea compartiment.
Acesta poate fi citit corect doar după ce am citit întregul întreg de 64 de biți anterior.

Prin repetarea acestor fluxuri stricte și logice pentru a obține informații corecte din sistem, putem gestiona corect datele citite.

## Cum să omitem „numele variabilelor”

Deși nu putem „omite” variabilele în sine, este important să distingem variabilele utilizate de cele neutilizate.
Dacă utilizarea programului este suficient de clară, este preferabil să folosim variabile anonime ca substituenți, în locul etichetării fiecărei valori, chiar dacă acestea nu vor fi utilizate pe termen lung.
Să verificăm acest lucru cu un exemplu, „Verificator de memorie liberă”

## Exemplu – Verificator de memorie liberă

Atunci când verificăm memoria liberă și swap-ul, nu avem nevoie de celelalte informații care indică resurse diferite.
Pentru o mai bună vizibilitate, puteți crea variabile anonime pentru a reține anumite spații.

```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  // anonim, iar cele neutilizate sunt marcate cu _
	_         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)
}
```

În consecință, variabilele sunt citite fără etichete.
Deși valorile anonime sunt stocate efectiv într-o structură, nu există etichete sau marcaje lizibile în cod.

## Concluzie

- Utilizarea pachetelor `syscall` și `unsafe` din Go este încă mai sigură decât C/CGo
- Dacă scrieți un proiect mare care poate fi extins cu ușurință:
  - Nu folosiți variabile anonime; atribuiți nume fiecărui membru.
- Dacă scrieți un proiect cu utilizare limitată:
  - Puteți folosi variabile anonime pentru a ocupa spațiile care sunt de fapt neutilizate.
- Pachetul `syscall` din Go este puternic și modern pentru gestionarea apelurilor de nivel jos

## Citiți mai departe

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