Ottenere l'indirizzo e il valore di una Costante e di una variabile globale situate in una libreria condivisa

Da Gambas-it.org - Wikipedia.

Il Metodo ".GetExternSymbol()" della Classe System ritorna un Puntatore all'indirizzo di un simbolo situato in una libreria condivisa. Tale simbolo deve essere una variabile Globale o una Costante "cost". Non funziona invece usando la Direttiva #define.
La variabile globale o la Costante può, dunque essere di tipo numerica (Int, Double, Long), ma anche di tipo Puntatore e di tipo Struttura.

Ottenuto l'indirizzo della variabile globale o della Costante, presente nella libreria condivisa, sarà possibile dunque dereferenziare successivamente il Puntatore per ricavare il valore assegnato a quelle risorse.
Tale funzione consente, così, di ricavare il valore di una Costante o di una variabile - purché globale -, anche se la libreria che la contiene non prevede esplicitamente, in modo codificato, il ritorno del suo valore.

Va precisato che la libreria esterna deve essere individuata esclusivamente con il suo semplice nome, privo dell'estensione ".so" e dell'eventuale numero di versione della libreria.


Ottenere l'indirizzo di una Costante, di una variabile globale istanziata e di un'altra non istanziata


Poniamo il caso che la libreria condivisa .so contenga il seguente breve codice scritto in linguaggio C:

const int COSTANTE = 111;
int variabile_globale_istanziata = 222;
int variabile_globale_NON_istanziata;

void funzioneEsterna() {

  variabile_globale_NON_istanziata = 333;

}

e che il codice Gambas sia il seguente:

Private Extern funzioneEsterna() In "/percorso/della/libreria/condivisa"


Public Sub Main()
 
 Dim p As Pointer

' Invoca la funzione esterna, presente nella libreria condivisa, affinché la "variabile_globale_NON_istanziata" assuma il valore numerico previsto:
 funzioneEsterna()

' Usa il Metodo "System.GetExternSymbol()" per ottenere un Puntatore alla Costante "COSTANTE" presente nella libreria condivisa indicata nel primo argomento del predetto Metodo della Classe "System".
' RICORDARE che la libreria esterna deve essere individuata esclusivamente con il suo semplice nome, privo dell'estensione ".so" e dell'eventuale numero di versione della libreria.
 p = System.GetExternSymbol("/percorso/della/libreria/condivisa", "COSTANTE")

' Dereferenzia il Puntatore per ottenere il valore definito della Costante "COASTANTE", e lo mostriamo in console:
 Print Int@(p)

' Ora fa la stessa operazione con la "variabile_globale_istanziata":
 p = System.GetExternSymbol("/percorso/della/libreria/condivisa", "variabile_globale_istanziata")

 Print Int@(p)

 ' Infine con la "variabile_globale_NON_istanziata":
 p = System.GetExternSymbol("/percorso/della/libreria/condivisa", "variabile_globale_NON_istanziata")

 Print Int@(p)

End


Ottenere l'indirizzo di una variabile di tipo Struttura e sua dereferenziazione

Come già detto, è possibile ottenere il puntatore di una variabile di tipo Struttura, presente in una libreria esterna, ossia l'indirizzo di memoria di detta variabile.

Nel secondo argomento si dovrà scrivere la variabile (che ovviamente dovrà essere Globale) della Struttura:

System.GetExternSymbol("/percorso/della/libreria/condivisa", "variabile_Struttura") As Pointer

Dereferenziare il Puntatore mediante la sua assegnazione alla variabile di tipo Struttura

Successivamente all'assegnamento del Puntatore alla variabile di tipo Struttura, presente in una libreria esterna, sarà possibile effettuare la dereferenziazione di tale Puntatore per ottenere i valori dei singoli campi della Struttura della libreria esterna.

Si potrà ottenere ciò, procedendo in modo analogo a quanto descritto nella pagina di questa WIKI, relativa alla dereferenziazione senza Memory-Stream di un Puntatore ad una Struttura.

Innanzitutto si provvede a ricreare la Struttura esterna, come defininita nella libreria esterna. Quindi nel codice si invocherà innanzitutto la funzione estrena, e successivamente il Metodo "System.GetExternSymbol()", indicando nel secondo argomento - come già descritto - il nome della variabile di tipo Struttura presente nella libreria esterna. Nell'esempio che segue supponiamo che la Struttura, presente nella libreria esterna, abbia tre campi che provvederemo quindi a riconfermarli nella copia della Struttura in Gambas:

Public Struct struttura
  a As Integer
  b As Short
  c As Integer
End Struct

Library "nome_della_libreria_esterna:numero_versione"

Private Extern nome_della_Funzione_esterna(parametro_1, parametro_2, etc...)


Public Sub main()

 Dim p As Pointer
 Dim vs As Struttura

 nome_della_Funzione_esterna(par1, par2, etc)

' Otteniamo l'indirizzo di memoria della variabile della Struttura esterna:
 p = System.GetExternSymbol("/percorso/della/libreria/esterna", "variabile_Struttura_esterna")

' Dereferenziamo il "puntatore" ottenuto assegnandolo alla Struttura:
 vs = p

 With vs
   Print a
   Print b
   Print c
 End With

End

Dereferenziare il Pointer mediante i Memory Stream

Si potrà anche fare uso dei Memory Stream, per dereferenziare il Puntatore ottenuto dal Metodo "System.GetExternSymbol()".

Con il seguente esempio pratico, intendiamo raccogliere i valori finali dei tre membri della Struttura esterna:

Private Extern Prova(n As Integer) As Integer In "/tmp/libreria"


Public Sub Main()

 Dim p As Pointer
 Dim st As Stream
 Dim i, c As Integer
 Dim sh As Short
 
 Creaso()
 
 Prova(10)
 
 p = System.GetExternSymbol("/tmp/libreria", "vs")
 
 st = Memory p For Read Write
 
 Read #st, i
 Print i
 
 Read #st, sh
 Print sh
 
 Seek #st, 8
 Read #st, i
 Print i
 Print "---------"

 st.Close

End


Private Procedure Creaso()
 
 File.Save("/tmp/libreria.c", "struct STRUTTURA {\n" &
           "   int a;\n" &
           "   short b;\n" &
           "   int c;\n};\n\n" &
           "struct STRUTTURA vs;\n\n\n" &
           "int Prova(int i) {\n\n"
           "   vs.a = i + 2;\n" &
           "   vs.b = i * 2;\n" &
           "   vs.c = i - 2;\n\n" &
           "   return (0);\n\n}")
 
 Shell "gcc -o /tmp/libreria.so /tmp/libreria.c -shared -fPIC" Wait
 
End