[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]

46. Eseguibili, interpretabili e automazione dell'interpretazione

Quando si utilizza un sistema operativo complesso come GNU/Linux, dove il kernel ha un ruolo così importante, è difficile stabilire una distinzione netta tra un programma eseguibile binario e un programma interpretato. A livello astratto si intende che il programma interpretato richiede un programma interprete che è di fatto il suo esecutore, ma anche l'interprete potrebbe a sua volta essere interpretato da un altro programma di livello inferiore. È un po' come quando per tradurre un testo dal cinese all'italiano, si preferisce partire dal lavoro di qualcun altro che l'ha già tradotto in inglese.

Evidentemente si pone il problema di stabilire il livello di astrazione a cui si vuole fare riferimento. Si potrebbe dire che un programma binario «normale» sia quello che viene eseguito direttamente dal kernel senza bisogno di altri sostegni da parte di programmi interpreti aggiuntivi. In questo senso, potrebbe accadere anche che un programma che nel sistema «A» è un binario normale, nel sistema «B» potrebbe essere eseguito per opera di un interprete intermedio, e quindi diventare lì un programma interpretato.

46.1 Script

Il classico tipo di programma interpretato è lo script che normalmente viene individuato dalla stessa shell attraverso cui viene avviato. Per questo è stata stabilita la convenzione per cui questi programmi sono contenuti in file di testo, in cui la prima riga indichi il percorso dell'interprete necessario.

#/bin/bash

Tale convenzione impone che, in questo tipo di script, il simbolo # rappresenti l'inizio di un commento, e che comunque si tratti di un file di testo normale. Inoltre, è stabilito implicitamente, che il programma interprete indicato riceva il nome dello script da interpretare come primo argomento.

Attualmente, non è solo la shell che può accorgersi del fatto che si tratti di uno script; anche il kernel è coinvolto in questa forma di riconoscimento, tanto che si possono creare dei sistemi specifici che, all'avvio, invece di mettere in funzione l'eseguibile init, avviano direttamente uno script attraverso l'interprete relativo.

46.2 Programmi da interpretare che non sono script

Quando il file da interpretare non è così semplice come uno script, per esempio perché non si tratta di un file di testo, si pone il problema di stabilire un metodo per il suo riconoscimento, altrimenti si è costretti a usare sempre un comando che richiami esplicitamente il suo interprete. L'esempio più comune di questa situazione è il programma scritto per un'altra piattaforma che si vuole utilizzare attraverso un interprete (o un emulatore) adatto. Generalmente, questi programmi estranei sono riconoscibili in base a una stringa binaria tipica che si può trovare all'inizio del file che li contiene; in pratica, in base al magic number del file. In altre situazioni, si può essere costretti a definire un'estensione particolare per i nomi di questi file, come avviene nel Dos.

46.3 Gestione del kernel dei binari eterogenei

A partire dall'introduzione dell'interprete Java anche per GNU/Linux, si è sentito maggiormente il problema di organizzare in modo coerente la gestione dei programmi che per un motivo o per l'altro devono essere interpretati attraverso un programma esterno al kernel stesso. Il meccanismo attuale permette una configurazione molto semplice del sistema, attraverso la quale si può automatizzare l'interpretazione di ciò che si vuole.

Per predisporre il kernel a questa forma di gestione, occorre attivare l'opzione seguente in fase di compilazione.

Per verificare che il kernel sia in grado di gestire questa funzione, basta verificare che all'interno della directory /proc/sys/fs/binfmt_misc/ appaiano i file register e status; quest'ultimo in particolare, dovrebbe contenere la parola enabled.

Questa funzionalità può essere attivata, se necessario, con il comando seguente:

echo 1 > /proc/sys/fs/binfmt_misc/status

Per disattivarla, basta utilizzare il valore 0.

echo 0 > /proc/sys/fs/binfmt_misc/status

Quando la gestione è disattivata, la lettura del file /proc/sys/fs/binfmt_misc/status restituisce la stringa disabled.

46.3.1 Configurazione

Trattandosi di un'attività che riguarda il kernel, non c'è un file di configurazione vero e proprio. Per informare il kernel della presenza di programmi da interpretare attraverso eseguibili esterni, occorre sovrascrivere un file virtuale del filesystem /proc/. In generale, questo si ottiene utilizzando un comando echo, il cui standard output viene ridiretto nel file /proc/sys/fs/binfmt_misc/register. Per definire il supporto a un tipo di programma interpretato, si utilizza una riga secondo la sintassi seguente:

:<nome>:<tipo>:[<scostamento>]:<riconoscimento>:[<maschera>]:<programma-interprete>:

Allo stato attuale, dal momento che i due punti verticali separano i vari campi di questo record, tale simbolo non può apparire all'interno di questi.

  1. <nome>

    Il primo campo serve a dare un nome a questo tipo di programma da interpretare. Ciò si tradurrà nella creazione di un file virtuale con lo stesso nome, /proc/sys/fs/binfmt_misc/<nome>, che poi permette di controllarne le funzionalità.

  2. <tipo>

    Il secondo campo definisce il tipo di riconoscimento che si vuole utilizzare. La lettera M indica l'utilizzo di un magic number, ovvero una stringa nella parte iniziale del file, oppure la lettera E specifica che viene presa in considerazione l'estensione nel nome. Questo serve a definire in che modo interpretare il quarto campo di questo record.

  3. <scostamento>

    Nel caso in cui si utilizzi un riconoscimento basato su una stringa iniziale, questa deve essere contenuta nei primi 128 byte, anche se non è detto che inizi dal primo. L'inizio della stringa di riconoscimento può essere indicato espressamente con un numero intero posto all'interno di questo campo: 0 rappresenta il primo byte.

  4. <riconoscimento>

    Il quarto campo consente di inserire la stringa di riconoscimento o l'estensione del file. La stringa, ovvero il magic number, possono essere specificati utilizzando delle sequenze di escape che consentono l'indicazione di valori esadecimali. Per questo si usa il prefisso \x, seguito da due cifre esadecimali che rappresentano un byte alla volta. A questo proposito, è bene ricordare che se il record viene definito in una riga di comando di una shell, è molto probabile che la barra obliqua inversa debba essere raddoppiata.

    La stringa di riconoscimento può essere applicata a ciò che resta dopo il filtro con la maschera indicata nel campo successivo.

    Nel caso si specifichi l'uso dell'estensione per riconoscere il tipo di file, questa non deve contenere il punto iniziale, che così è sottinteso.

  5. <maschera>

    Il quinto campo serve a indicare una maschera da utilizzare per filtrare i bit che compongono la parte di file che deve essere utilizzata per il riconoscimento attraverso il magic number. In pratica, di solito non si utilizza, e si ottiene l'applicazione della maschera predefinita corrisponde a \ff. La maschera viene applicata attraverso un AND con i byte corrispondenti del file; quello che ne deriva viene usato per il paragone con il modello specificato nel quarto campo.

    La maschera predefinita, evidentemente, non provoca alcuna modifica.

  6. <programma-interprete>

    L'ultimo campo serve a indicare il percorso completo dell'interprete da utilizzare per mettere in esecuzione il programma identificato attraverso questo record. Evidentemente, si presume che questo programma possa essere avviato indicando il file da interpretare come primo argomento. Se necessario, l'interprete può essere uno script predisposto opportunamente per avviare il vero interprete nel modo richiesto.

Attualmente, si pongono delle limitazioni a cui è già stato accennato in parte:

Esempi

echo ':Java:M::\xca\xfe\xba\xbe::/usr/bin/java:' > /proc/sys/fs/binfmt_misc/register

Definisce il binario Java, riconoscibile dalla sequenza esadecimale 0xCAFEBABE, a partire dall'inizio del file. Per la sua interpretazione viene specificato il programma /usr/bin/java, e questo potrebbe essere uno script che si occupa di avviare correttamente l'interprete giusto.

echo ':Java:E::java::/usr/bin/java:' > /proc/sys/fs/binfmt_misc/register

Come nell'esempio precedente, con la differenza che l'eseguibile Java viene identificato solo per la presenza dell'estensione .java.

46.3.2 Attuazione pratica

Non si può pensare che ogni volta che si vuole utilizzare un binario estraneo da interpretare, si debba dare il comando apposito, come negli esempi mostrati nella sezione precedente. Evidentemente, si tratta di inserire queste dichiarazioni in uno script della procedura di inizializzazione del sistema; in mancanza d'altro nel solito rc.local contenuto nella directory /etc/rc.d/, oppure in altra simile.

Una volta definito un tipo di eseguibile da interpretare, nella directory /proc/sys/fs/binfmt_misc/ viene creato un file virtuale con il nome corrispondente a quanto indicato nel primo campo del record di definizione. Se questo file viene sovrascritto con il valore -1, si ottiene l'eliminazione del tipo corrispondente. Se si fa la stessa cosa con il file status, si elimina la gestione di tutti i binari specificati precedentemente.

Esempi

echo -1 > /proc/sys/fs/binfmt_misc/Java

Elimina la gestione del tipo di binario Java.

echo -1 > /proc/sys/fs/binfmt_misc/status

Elimina la gestione di tutti i tipi di binari da interpretare.

46.4 Riferimenti

---------------------------

Appunti Linux 1999.09.21 --- Copyright © 1997-1999 Daniele Giacomini --  daniele @ pluto.linux.it


[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]