Cosa si intende per "una chiamata di sistema" se non l'implementazione nel linguaggio di programmazione?


14

Vorrei capire il termine "chiamata di sistema". Sono a conoscenza del fatto che le chiamate di sistema vengono utilizzate per ottenere i servizi del kernel da un'applicazione spazio utente.

La parte con cui ho bisogno di chiarimenti è la differenza tra una "chiamata di sistema" e una "implementazione C della chiamata di sistema".

Ecco una citazione che mi confonde:

Sui sistemi simili a Unix, quell'API di solito fa parte di un'implementazione della libreria C (libc), come glibc, che fornisce funzioni wrapper per le chiamate di sistema, spesso denominate come le chiamate di sistema che chiamano

Quali sono le "chiamate di sistema che chiamano"? Dov'è la loro fonte? Posso includerli direttamente nel mio codice?

La "chiamata di sistema" in senso generico è solo un'interfaccia definita da POSIX ma per vedere effettivamente l'implementazione si potrebbe esaminare l'origine C e in essa vedere come va effettivamente lo spazio utente reale alla comunicazione del kernel?

Nota di fondo: sto cercando di capire se, alla fine, ogni funzione c finisce per interagire con i dispositivi di /dev.

Risposte:


21

Le chiamate di sistema in sono un concetto. Rappresentano azioni che i processi possono richiedere al kernel di eseguire.

Tali chiamate di sistema sono implementate nel kernel del sistema simile a UNIX. Questa implementazione (scritta in C, e in asm per piccole parti) esegue effettivamente l'azione nel sistema.

Quindi, i processi utilizzano un'interfaccia per richiedere al sistema l'esecuzione delle chiamate di sistema. Questa interfaccia è specificata da POSIX. Questo è un insieme di funzioni della libreria standard C. In realtà sono wrapper, possono eseguire alcuni controlli e quindi chiamare una funzione specifica del sistema nel kernel che gli dice di fare le azioni richieste dalla chiamata di sistema. E il trucco è che quelle funzioni che sono l'interfaccia sono chiamate come le stesse chiamate del sistema e sono spesso chiamate direttamente "chiamate di sistema".

È possibile chiamare la funzione nel kernel che esegue la chiamata di sistema direttamente tramite il meccanismo specifico del sistema. Il problema è che rende il tuo codice assolutamente non portatile.

Quindi, una chiamata di sistema è:

  • un concetto, una sequenza di azioni eseguite dal kernel per offrire un servizio a un processo utente
  • la funzione della libreria standard C che dovresti usare nel tuo codice per ottenere questo servizio dal kernel.

1
Hai un esempio della "funzione wrapper" e una vera chiamata di sistema? (percorsi dei file in Linux o collegamenti a fonti)
TheMeaningfulEngineer,

3
Ad esempio, questa è l'implementazione della getpidchiamata di sistema nel kernel Linux: lxr.free-electrons.com/source/kernel/timer.c?v=2.6.35#L1337 . E questa è la funzione wrapper nella libreria standard GNU C glibc-2.19: fossies.org/dox/glibc-2.19/… .
lgeorget,

@Igeorget: i tuoi link non funzionano più. Link aggiornato per l'implementazione del kernel: github.com/torvalds/linux/blob/… . Non sono riuscito a trovare ciò che fa glibc in questi giorni, è impossibile navigare in quel codice.
rchard2scout

6

Una chiamata di sistema è un modo per chiedere al tuo sistema operativo (kernel) di eseguire alcune operazioni per conto del tuo programma, che il programma non può fare da solo (o è semplicemente scomodo). Il motivo per cui non è possibile eseguire alcune operazioni è che consentire a un programma casuale di eseguirle potrebbe compromettere l'integrità del sistema, come eseguire I / O (direttamente su RAM, sovrascrivere qualsiasi cosa).

POSIX definisce un'interfaccia per i programmi, alcune funzioni che il tuo programma può chiamare. Alcuni di questi si traducono più o meno direttamente in chiamate di sistema, altri richiedono una maggiore elaborazione. È il runtime per la tua lingua, ad es. La libreria C, che è responsabile dell'offerta dell'interfaccia POSIX e di impacchettare argomenti e ricevere i risultati direttamente al chiamante.

I sistemi Unixy offrono interfacce POSIX più o meno direttamente come chiamate di sistema. In genere c'è un modo per invocare direttamente le chiamate di sistema, cercare syscall(2)i dettagli su come utilizzare questa funzione in Linux.


1
Si tocca un punto importante a cui le altre risposte si limitano a rispolverare. Qualsiasi funzione che un programmatore in grado ragionevolmente potrebbe scrivere per se stesso (come strlen, strcpy, sqrt, e qsort) può essere e, probabilmente, è nello spazio utente, caricato da una libreria. (Principalmente libc; funzioni matematiche simili sqrte le funzioni trigonometriche e iperboliche sono probabilmente in libm, la libreria matematica.) ... (continua)
Scott,

1
(continua) ... Ma non è possibile che un utente possa scrivere la propria fork, killo openfunzione, poiché richiedono l'accesso allo spazio di memoria del kernel del sistema operativo (ad es. la tabella dei processi) o istruzioni privilegiate (ad es. I / O). Pertanto, il codice che esegue queste funzioni deve trovarsi nel kernel del sistema operativo; quindi, funzioni di sistema o chiamate di sistema.
Scott,

5

Certo, facciamo quante direzioni possiamo guardare da questo elefante? cosa.

La vera chiamata di sistema è, nel tuo programma integrato, l'istruzione della macchina che innesca l'escalation dei privilegi in modalità kernel, e nel kernel stesso è il codice che l'istruzione richiama. Il codice libc (e ogni linguaggio runtime) imposta i registri della macchina e i parametri in-storage in cui il codice del kernel si aspetta di trovarli, che possono essere posti decisamente strani a causa di vincoli sull'istruzione della macchina.

Una volta nel codice del sistema operativo stesso, c'è un po 'di riavvolgimento dell'immagine speculare delle cose specifiche della macchina che ha eseguito il runtime utente e quindi una chiamata di subroutine perfettamente ordinaria.
Se vuoi vedere esattamente come funziona in un sistema operativo su larga scala, estrarre il kernel source ( git clone https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/) e fare ad es git grep -i system\ call. Estrarre la fonte glibc e fare altrettanto.


È vero, ma rovistare in Linux o glibc è un po 'pesante ...
vonbrand,

3

In Linux almeno il meccanismo di chiamata del sistema funziona sotto la maggior parte delle architetture inserendo alcuni dati specificamente formattati (di solito un qualche tipo di struttura) in alcuni registri o indirizzi di memoria predefiniti.

Il problema si presenta tuttavia nel forzare effettivamente la CPU a fare il passaggio nello spazio del kernel in modo che possa eseguire il codice del kernel privilegiato per servire la chiamata. Questo viene fatto forzando un errore di qualche tipo (un errore è una divisione per 0, un overflow indefinito o un segfault, ecc.) Che forza il kernel a subentrare nell'esecuzione per gestire l'errore.

Normalmente il kernel gestisce gli errori uccidendo il processo che causa o eseguendo un gestore fornito dall'utente. Tuttavia, nel caso di una syscall controllerà invece i registri e le posizioni di memoria predefiniti e se contengono una richiesta syscall eseguirà tale operazione utilizzando i dati forniti dal processo utente nella struttura in memoria. Questo di solito deve essere fatto con alcuni assemblaggi appositamente realizzati a mano e per facilitare l'uso del syscall per l'utente, la libreria C del sistema deve avvolgerlo come una funzione. Per un'interfaccia di livello inferiore, consultare http://man7.org/linux/man-pages/man2/syscall.2.html per alcune informazioni su come funzionano le syscalls e su come chiamare quindi senza un wrapper C.

Questo è dato da una semplificazione eccessiva, non è vero in tutte le architetture (mips ha una speciale istruzione syscall) e non funziona necessariamente allo stesso modo su tutti i sistemi operativi. Tuttavia, se avete commenti o domande, chiedete.

Modificato: Nota, riguardo al tuo commento su cose in / dev / questa è in realtà un'interfaccia di livello superiore per il kernel, non una inferiore. Questi dispositivi in ​​realtà usano (circa) 4 syscalls sotto. Scrivere su di loro è lo stesso di un syscall di scrittura, leggere un syscall di lettura, aprirli / chiuderli equivalenti ai syscall aperti e chiusi ed eseguire uno ioctl provoca uno speciale syscall ioctl che di per sé è un'interfaccia per accedere a uno dei tanti ioctl del sistema chiamate (speciali, di solito chiamate specifiche del dispositivo con un utilizzo troppo ristretto per scrivere un'intera scala per loro).


1

Ogni chiamata di sistema ha un numero intero associato. Questo numero intero è una funzione del valore di ritorno della chiamata di sistema, del numero di argomenti per la chiamata di sistema e del tipo di argomenti. Questo numero di chiamata di sistema non è altro che un offset nel vettore di chiamata di sistema globale, questo vettore che è accessibile solo in modalità privilegiata contiene il puntatore ai gestori appropriati. Il processo quando si richiama una chiamata di sistema, verrebbe generato un interrupt software (trap interrupt), quindi verrà eseguito un gestore trap che determina quale chiamata di sistema deve essere invocata. Quindi il kernel copia gli argomenti della chiamata di sistema passata dall'utente che si trova nello stack nei registri del processore e, una volta completato il servizio richiesto, i dati verranno copiati nello stack dai registri del processore. Questo è uno dei motivi per cui ci sono argomenti limitati per le chiamate di sistema,


Ogni chiamata (operazione) è identificata internamente da un numero, vero. Ma il numero dipende dall'operazione , non dal valore restituito né dal numero di argomenti. Una spiegazione di come funzionava da userland su x86 è qui
vonbrand,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.