X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=df94444f153016202640e3ac052cbac9c53ecb80;hp=dfb5d2bbf48922aaf9347b43e1fc4e38488d282c;hb=4e1da5b259a86278710be32441de7b88b9287ec1;hpb=193d612d40c5f81f5559ea6e11e70f6b6e51fb39 diff --git a/process.tex b/process.tex index dfb5d2b..df94444 100644 --- a/process.tex +++ b/process.tex @@ -444,10 +444,10 @@ seguenti segmenti: automaticamente il codice necessario, seguendo quella che viene chiamata una \textit{calling convention}; quella standard usata con il C ed il C++ è detta \textit{cdecl} e prevede che gli argomenti siano caricati nello - \textit{stack} dal chiamante da destra a sinistra, e che si il chiamante + \textit{stack} dal chiamante da destra a sinistra, e che sia il chiamante stesso ad eseguire la ripulitura dello \textit{stack} al ritorno della funzione, se ne possono però utilizzare di alternative (ad esempio nel - pascal gli argomenti sono inseriti da sinistra a destra ed è compito del + Pascal gli argomenti sono inseriti da sinistra a destra ed è compito del chiamato ripulire lo \textit{stack}), in genere non ci si deve preoccupare di questo fintanto che non si mescolano funzioni scritte con linguaggi diversi.} @@ -760,7 +760,7 @@ funzioni di allocazione della memoria. Per poterle utilizzare è necessario definire una della macro di funzionalità (vedi sez.~\ref{sec:intro_gcc_glibc_std}) fra \macro{\_BSD\_SOURCE}, \macro{\_SVID\_SOURCE} e \macro{\_XOPEN\_SOURCE} (ad un valore maggiore o -ugiale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è: +uguale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è: \begin{prototype}{unistd.h}{int brk(void *end\_data\_segment)} Sposta la fine del segmento dei dati. @@ -851,27 +851,47 @@ però non è standardizzata da POSIX e pertanto non è disponibile su tutte le versioni di kernel unix-like;\footnote{nel caso di Linux devono essere comunque definite le macro \macro{\_BSD\_SOURCE} e \macro{\_SVID\_SOURCE}.} il suo prototipo è: -\begin{functions} - \headdecl{unistd.h} - \headdecl{sys/mman.h} +% \begin{functions} +% \headdecl{unistd.h} +% \headdecl{sys/mman.h} - \funcdecl{int mincore(void *addr, size\_t length, unsigned char *vec)} - Ritorna lo stato delle pagine di memoria occupate da un processo. +% \funcdecl{int mincore(void *addr, size\_t length, unsigned char *vec)} +% Ritorna lo stato delle pagine di memoria occupate da un processo. - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori seguenti: - \begin{errlist} - \item[\errcode{ENOMEM}] o \param{addr} + \param{length} eccede la dimensione - della memoria usata dal processo o l'intervallo di indirizzi specificato - non è mappato. - \item[\errcode{EINVAL}] \param{addr} non è un multiplo delle dimensioni di - una pagina. - \item[\errcode{EFAULT}] \param{vec} punta ad un indirizzo non valido. - \item[\errcode{EAGAIN}] il kernel è temporaneamente non in grado di fornire - una risposta. - \end{errlist} +% \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di +% errore, nel qual caso \var{errno} assumerà uno dei valori seguenti: +% \begin{errlist} +% \item[\errcode{ENOMEM}] o \param{addr} + \param{length} eccede la dimensione +% della memoria usata dal processo o l'intervallo di indirizzi specificato +% non è mappato. +% \item[\errcode{EINVAL}] \param{addr} non è un multiplo delle dimensioni di +% una pagina. +% \item[\errcode{EFAULT}] \param{vec} punta ad un indirizzo non valido. +% \item[\errcode{EAGAIN}] il kernel è temporaneamente non in grado di fornire +% una risposta. +% \end{errlist} +% } +% \end{functions} + +\begin{funcproto}{ +\fhead{unistd.h} +\fhead{sys/mman.h} +\fdecl{int mincore(void *addr, size\_t length, unsigned char *vec)} +\fdesc{Ritorna lo stato delle pagine di memoria occupate da un processo.} } -\end{functions} +{La funzione ritorna 0 in caso di successo e $-1$ in caso di errore, nel qual +caso \var{errno} assumerà uno dei valori seguenti: +\begin{errlist} + \item[\errcode{ENOMEM}] o \param{addr} + \param{length} eccede la dimensione + della memoria usata dal processo o l'intervallo di indirizzi specificato + non è mappato. + \item[\errcode{EINVAL}] \param{addr} non è un multiplo delle dimensioni di + una pagina. + \item[\errcode{EFAULT}] \param{vec} punta ad un indirizzo non valido. + \item[\errcode{EAGAIN}] il kernel è temporaneamente non in grado di fornire + una risposta. +\end{errlist}} +\end{funcproto} La funzione permette di ottenere le informazioni sullo stato della mappatura della memoria per il processo chiamante, specificando l'intervallo da @@ -960,16 +980,39 @@ fintanto che ci sarà almeno un processo che la blocca. Le funzioni per bloccare e sbloccare la \index{paginazione} paginazione di singole sezioni di memoria sono \funcd{mlock} e \funcd{munlock}; i loro prototipi sono: -\begin{functions} - \headdecl{sys/mman.h} +% \begin{functions} +% \headdecl{sys/mman.h} - \funcdecl{int mlock(const void *addr, size\_t len)} - Blocca la paginazione su un intervallo di memoria. +% \funcdecl{int mlock(const void *addr, size\_t len)} +% Blocca la paginazione su un intervallo di memoria. - \funcdecl{int munlock(const void *addr, size\_t len)} - Rimuove il blocco della paginazione su un intervallo di memoria. +% \funcdecl{int munlock(const void *addr, size\_t len)} +% Rimuove il blocco della paginazione su un intervallo di memoria. - \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in +% \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in +% caso di errore, nel qual caso \var{errno} assumerà uno dei +% valori seguenti: +% \begin{errlist} +% \item[\errcode{ENOMEM}] alcuni indirizzi dell'intervallo specificato non +% corrispondono allo spazio di indirizzi del processo o si è ecceduto +% il numero massimo consentito di pagine bloccate. +% \item[\errcode{EINVAL}] \param{len} non è un valore positivo. +% \item[\errcode{EPERM}] con un kernel successivo al 2.6.9 il processo non è +% privilegiato e si un limite nullo per \const{RLIMIT\_MEMLOCK}. +% \end{errlist} +% e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i +% privilegi richiesti per l'operazione.} +% \end{functions} + +\begin{funcproto}{ + \fhead{sys/mman.h} + \fdecl{int mlock(const void *addr, size\_t len)} + \fdesc{Blocca la paginazione su un intervallo di memoria.} + + \fdecl{int munlock(const void *addr, size\_t len)} + \fdesc{Rimuove il blocco della paginazione su un intervallo di memoria.} + } +{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori seguenti: \begin{errlist} @@ -982,7 +1025,8 @@ prototipi sono: \end{errlist} e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i privilegi richiesti per l'operazione.} -\end{functions} +\end{funcproto} + Le due funzioni permettono rispettivamente di bloccare e sbloccare la \index{paginazione} paginazione per l'intervallo di memoria specificato dagli @@ -1071,7 +1115,7 @@ buffer sia un multiplo intero di questa dimensione, usualmente 512 byte. In tal caso l'uso di \func{malloc} non è sufficiente, ed occorre utilizzare una funzione specifica. -Tradizionalmente per rispondere a questa esigenza sono state crate due +Tradizionalmente per rispondere a questa esigenza sono state create due funzioni diverse, \funcd{memalign} e \funcd{valloc}, oggi obsolete; i rispettivi prototipi sono: \begin{functions} @@ -1104,7 +1148,7 @@ Nessuna delle due funzioni ha una chiara standardizzazione (nessuna delle due compare in POSIX.1), ed inoltre ci sono indicazioni discordi sui file che ne contengono la definizione;\footnote{secondo SUSv2 \func{valloc} è definita in \texttt{stdlib.h}, mentre sia le \acr{glibc} che le precedenti \acr{libc4} e - \acr{lic5} la dichiarano in \texttt{malloc.h}, lo stesso vale per + \acr{libc5} la dichiarano in \texttt{malloc.h}, lo stesso vale per \func{memalign} che in alcuni sistemi è dichiarata in \texttt{stdlib.h}.} per questo motivo il loro uso è sconsigliato, essendo state sostituite dalla nuova \funcd{posix\_memalign}, che è stata standardizzata in POSIX.1d; il suo @@ -1177,7 +1221,7 @@ di scrittura oltre i limiti dei buffer allocati. Per questo motivo la funzione deve essere chiamata prima di qualunque allocazione di memoria, altrimenti fallirà con un valore di ritorno pari a $-1$. -Se come argomento di \func{mcheck} si passa \var{NULL} verrà utilizzata una +Se come argomento di \func{mcheck} si passa \val{NULL} verrà utilizzata una funzione predefinita che stampa un messaggio di errore ed invoca la funzione \func{abort} (vedi sez.~\ref{sec:sig_alarm_abort}), altrimenti si dovrà create una funzione personalizzata che verrà eseguita ricevendo un unico argomento di @@ -1206,12 +1250,12 @@ tab.~\ref{tab:mcheck_status_value}. buffer.\\ \macro{MCHECK\_TAIL} & i dati immediatamente seguenti il buffer sono stati modificati, succede quando si va scrivere - oltre la dimensione correttta del buffer.\\ + oltre la dimensione corretta del buffer.\\ \macro{MCHECK\_FREE} & il buffer è già stato disallocato.\\ \hline \end{tabular} \caption{Valori dello stato dell'allocazione di memoria ottenibili dalla - funzione di teminazione installata con \func{mcheck}.} + funzione di terminazione installata con \func{mcheck}.} \label{tab:mcheck_status_value} \end{table} @@ -1360,9 +1404,9 @@ ritornato il carattere \texttt{':'}, infine se viene incontrato il valore \texttt{'-{}-'} la scansione viene considerata conclusa, anche se vi sono altri elementi di \param{argv} che cominciano con il carattere \texttt{'-'}. -\begin{figure}[htb] +\begin{figure}[!htbp] \footnotesize \centering - \begin{minipage}[c]{15.6cm} + \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/option_code.c} \end{minipage} \normalsize @@ -1438,7 +1482,7 @@ terminata da un puntatore nullo. L'indirizzo della lista delle variabili di ambiente è passato attraverso la variabile globale \var{environ}, che viene definita automaticamente per -cisascun processo, e a cui si può accedere attraverso una semplice +ciascun processo, e a cui si può accedere attraverso una semplice dichiarazione del tipo: \includecodesnip{listati/env_ptr.c} un esempio della struttura di questa lista, contenente alcune delle variabili @@ -1481,7 +1525,7 @@ fig.~\ref{fig:proc_envirno_list}. Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo \textsl{\texttt{nome=valore}} ed in questa forma che le funzioni di gestione che vedremo a breve se le aspettano, se pertanto si dovesse costruire -manualemente un ambiente si abbia cura di rispettare questa convenzione. +manualmente un ambiente si abbia cura di rispettare questa convenzione. Inoltre alcune variabili, come quelle elencate in fig.~\ref{fig:proc_envirno_list}, sono definite dal sistema per essere usate da diversi programmi e funzioni: per queste c'è l'ulteriore convenzione di @@ -1832,15 +1876,14 @@ sono definite delle apposite macro; la procedura da seguire è la seguente: \item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. \end{enumerate*} + In generale è perfettamente legittimo richiedere meno argomenti di quelli che potrebbero essere stati effettivamente forniti, e nella esecuzione delle \macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti saranno ignorati; se invece si richiedono più argomenti di quelli forniti si -otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso della macro -\macro{va\_end} è inutile, ma si consiglia di usarlo ugualmente per -compatibilità. - -Le definizioni delle tre macro sono le seguenti: +otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso di +\macro{va\_end} è inutile, ma si consiglia di usarla ugualmente per +compatibilità. Le definizioni delle macro citate sono le seguenti: \begin{functions} \headdecl{stdarg.h} @@ -1859,12 +1902,11 @@ Le definizioni delle tre macro sono le seguenti: In generale si possono avere più puntatori alla lista degli argomenti, ciascuno andrà inizializzato con \macro{va\_start} e letto con \macro{va\_arg} -e ciascuno potrà scandire la lista degli argomenti per conto suo. - -Dopo l'uso di \macro{va\_end} la variabile \param{ap} diventa indefinita e -successive chiamate a \macro{va\_arg} non funzioneranno. Si avranno risultati -indefiniti anche chiamando \macro{va\_arg} specificando un tipo che non -corrisponde a quello dell'argomento. +e ciascuno potrà scandire la lista degli argomenti per conto suo. Dopo l'uso +di \macro{va\_end} la variabile \param{ap} diventa indefinita e successive +chiamate a \macro{va\_arg} non funzioneranno. Si avranno risultati indefiniti +anche chiamando \macro{va\_arg} specificando un tipo che non corrisponde a +quello dell'argomento. Un altro limite delle macro è che i passi 1) e 3) devono essere eseguiti nel corpo principale della funzione, il passo 2) invece può essere eseguito anche @@ -1874,13 +1916,12 @@ usato (lo standard richiederebbe la chiamata esplicita di \macro{va\_end}), dato che il valore di \param{ap} risulterebbe indefinito. Esistono dei casi in cui è necessario eseguire più volte la scansione degli -argomenti e poter memorizzare una posizione durante la stessa. La cosa più -naturale in questo caso sembrerebbe quella di copiarsi il puntatore alla lista -degli argomenti con una semplice assegnazione. Dato che una delle -realizzazioni più comuni di \macro{va\_list} è quella di un puntatore nello -\itindex{stack} \textit{stack} all'indirizzo dove sono stati salvati gli -argomenti, è assolutamente normale pensare di poter effettuare questa -operazione. +argomenti e poter memorizzare una posizione durante la stessa. In questo caso +sembrerebbe naturale copiarsi il puntatore alla lista degli argomenti con una +semplice assegnazione. Dato che una delle realizzazioni più comuni di +\macro{va\_list} è quella di un puntatore nello \itindex{stack} \textit{stack} +all'indirizzo dove sono stati salvati gli argomenti, è assolutamente normale +pensare di poter effettuare questa operazione. In generale però possono esistere anche realizzazioni diverse, per questo motivo \macro{va\_list} è definito come \index{tipo!opaco} \textsl{tipo opaco} @@ -2050,7 +2091,7 @@ interagiscono direttamente con la gestione dello \itindex{stack} \func{setjmp} è implementata con una macro, pertanto non si può cercare di ottenerne l'indirizzo, ed inoltre delle chiamate a questa funzione sono sicure solo in uno dei seguenti casi: -\begin{itemize} +\begin{itemize*} \item come espressione di controllo in un comando condizionale, di selezione o di iterazione (come \code{if}, \code{switch} o \code{while}); \item come operando per un operatore di uguaglianza o confronto in una @@ -2059,11 +2100,12 @@ solo in uno dei seguenti casi: \item come operando per l'operatore di negazione (\code{!}) in una espressione di controllo di un comando condizionale, di selezione o di iterazione; \item come espressione a sé stante. -\end{itemize} +\end{itemize*} In generale, dato che l'unica differenza fra la chiamata diretta e quella -ottenuta da un \func{longjmp} è costituita dal valore di ritorno di -\func{setjmp}, essa è usualmente chiamata all'interno di un comando \code{if}. +ottenuta nell'uscita con un \func{longjmp} è costituita dal valore di ritorno +di \func{setjmp}, quest'ultima usualmente viene chiamata all'interno di un +comando \code{if}. Uno dei punti critici dei salti non-locali è quello del valore delle variabili, ed in particolare quello delle variabili automatiche della funzione @@ -2099,13 +2141,122 @@ dichiarandole tutte come \direct{volatile}.\footnote{la direttiva \index{salto~non-locale|)} +\subsection{La \textit{endianess}} +\label{sec:sock_endianess} + +\itindbeg{endianess} + +Uno dei problemi di programmazione che può dar luogo ad effetti imprevisti è +quello relativo alla cosiddetta \textit{endianess}. Questa è una +caratteristica generale dell'architettura hardware di un computer che dipende +dal fatto che la rappresentazione di un numero binario può essere fatta in due +modi, chiamati rispettivamente \textit{big endian} e \textit{little endian} a +seconda di come i singoli bit vengono aggregati per formare le variabili +intere (ed in genere in diretta corrispondenza a come sono poi in realtà +cablati sui bus interni del computer). + +\begin{figure}[!htb] + \centering \includegraphics[height=3cm]{img/endianess} + \caption{Schema della disposizione dei dati in memoria a seconda della + \textit{endianess}.} + \label{fig:sock_endianess} +\end{figure} + +Per capire meglio il problema si consideri un intero a 32 bit scritto in una +locazione di memoria posta ad un certo indirizzo. Come illustrato in +fig.~\ref{fig:sock_endianess} i singoli bit possono essere disposti in memoria +in due modi: a partire dal più significativo o a partire dal meno +significativo. Così nel primo caso si troverà il byte che contiene i bit più +significativi all'indirizzo menzionato e il byte con i bit meno significativi +nell'indirizzo successivo; questo ordinamento è detto \textit{big endian}, +dato che si trova per prima la parte più grande. Il caso opposto, in cui si +parte dal bit meno significativo è detto per lo stesso motivo \textit{little + endian}. + +Si può allora verificare quale tipo di \textit{endianess} usa il proprio +computer con un programma elementare che si limita ad assegnare un valore ad +una variabile per poi ristamparne il contenuto leggendolo un byte alla volta. +Il codice di detto programma, \file{endtest.c}, è nei sorgenti allegati, +allora se lo eseguiamo su un normale PC compatibile, che è \textit{little + endian} otterremo qualcosa del tipo: +\begin{verbatim} +[piccardi@gont sources]$ ./endtest +Using value ABCDEF01 +val[0]= 1 +val[1]=EF +val[2]=CD +val[3]=AB +\end{verbatim}%$ +mentre su un vecchio Macintosh con PowerPC, che è \textit{big endian} avremo +qualcosa del tipo: +\begin{verbatim} +piccardi@anarres:~/gapil/sources$ ./endtest +Using value ABCDEF01 +val[0]=AB +val[1]=CD +val[2]=EF +val[3]= 1 +\end{verbatim}%$ + +L'attenzione alla \textit{endianess} nella programmazione è importante, perché +se si fanno assunzioni relative alla propria architettura non è detto che +queste restino valide su un'altra architettura. Inoltre, come vedremo ad +esempio in sez.~\ref{sec:sock_addr_func}, si possono avere problemi quando ci +si trova a usare valori di un formato con una infrastruttura che ne usa +un altro. + +La \textit{endianess} di un computer dipende essenzialmente dalla architettura +hardware usata; Intel e Digital usano il \textit{little endian}, Motorola, +IBM, Sun (sostanzialmente tutti gli altri) usano il \textit{big endian}. Il +formato dei dati contenuti nelle intestazioni dei protocolli di rete (il +cosiddetto \textit{network order} è anch'esso \textit{big endian}; altri +esempi di uso di questi due diversi formati sono quello del bus PCI, che è +\textit{little endian}, o quello del bus VME che è \textit{big endian}. + +Esistono poi anche dei processori che possono scegliere il tipo di formato +all'avvio e alcuni che, come il PowerPC o l'Intel i860, possono pure passare +da un tipo di ordinamento all'altro con una specifica istruzione. In ogni caso +in Linux l'ordinamento è definito dall'architettura e dopo l'avvio del sistema +in genere resta sempre lo stesso,\footnote{su architettura PowerPC è possibile + cambiarlo, si veda sez.~\ref{sec:process_prctl}.} anche quando il processore +permetterebbe di eseguire questi cambiamenti. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/endian.c} + \end{minipage} + \normalsize + \caption{La funzione \func{endian}, usata per controllare il tipo di + architettura della macchina.} + \label{fig:sock_endian_code} +\end{figure} + +Per controllare quale tipo di ordinamento si ha sul proprio computer si è +scritta una piccola funzione di controllo, il cui codice è riportato +fig.~\ref{fig:sock_endian_code}, che restituisce un valore nullo (falso) se +l'architettura è \textit{big endian} ed uno non nullo (vero) se l'architettura +è \textit{little endian}. + +Come si vede la funzione è molto semplice, e si limita, una volta assegnato +(\texttt{\small 9}) un valore di test pari a \texttt{0xABCD} ad una variabile +di tipo \ctyp{short} (cioè a 16 bit), a ricostruirne una copia byte a byte. +Per questo prima (\texttt{\small 10}) si definisce il puntatore \var{ptr} per +accedere al contenuto della prima variabile, ed infine calcola (\texttt{\small + 11}) il valore della seconda assumendo che il primo byte sia quello meno +significativo (cioè, per quanto visto in fig.~\ref{fig:sock_endianess}, che sia +\textit{little endian}). Infine la funzione restituisce (\texttt{\small 12}) +il valore del confronto delle due variabili. +\itindend{endianess} + + % LocalWords: like exec kernel thread main ld linux static linker char envp Gb % LocalWords: sez POSIX exit system call cap abort shell diff errno stdlib int % LocalWords: SUCCESS FAILURE void atexit stream fclose unistd descriptor init % LocalWords: SIGCHLD wait function glibc SunOS arg argp execve fig high kb Mb % LocalWords: memory alpha swap table printf Unit MMU paging fault SIGSEGV BSS -% LocalWords: multitasking text segment NULL Block Started Symbol +% LocalWords: multitasking text segment NULL Block Started Symbol fill black % LocalWords: heap stack calling convention size malloc calloc realloc nmemb % LocalWords: ENOMEM ptr uClib cfree error leak smartpointers hook Dmalloc brk % LocalWords: Gray Watson Electric Fence Bruce Perens sbrk longjmp SUSv BSD ap @@ -2119,8 +2270,14 @@ dichiarandole tutte come \direct{volatile}.\footnote{la direttiva % LocalWords: clearenv libc value overwrite string reference result argument % LocalWords: socket variadic ellipsis header stdarg execl self promoting last % LocalWords: float double short register type dest src extern setjmp jmp buf -% LocalWords: env return if while Di page cdecl -% LocalWords: environment +% LocalWords: env return if while Di page cdecl rectangle node anchor west PS +% LocalWords: environment rounded corners dashed south width height draw east +% LocalWords: exithandler handler violation inline SOURCE SVID XOPEN mincore +% LocalWords: length unsigned vec EFAULT EAGAIN dell'I memalign valloc posix +% LocalWords: boundary memptr alignment sizeof overrun mcheck abortfn enum big +% LocalWords: mprobe DISABLED HEAD TAIL touch right emacs OSTYPE endianess IBM +% LocalWords: endian little endtest Macintosh PowerPC Intel Digital Motorola +% LocalWords: Sun order VME %%% Local Variables: %%% mode: latex