• Regolamento Macrocategoria DEV
    Prima di aprire un topic nella Macrocategoria DEV, è bene leggerne il suo regolamento. Sei un'azienda o un hosting/provider? Qui sono anche contenute informazioni per collaborare con Sciax2 ed ottenere l'accredito nella nostra community!

Info [C] Sulle DLL ...

nothing

Utente Esperto
Autore del topic
4 Gennaio 2010
1.249
58
Miglior risposta
0
Ricordo che un programma scritto in C, per usufruire di una funzione di una DLL, normalmente, ha bisogno di :

1) conoscerne la firma, ovvero il nome della funzione, il tipo di dato restituito, i parametri in numero e tipo (queste informazioni sono normalmente contenute nei file header, i file con estensione .h e sono utilizzate in fase di compilazione)

2) utilizzare la corrispondente Import Library, un file con estensione .LIB che non contiene il codice effettivo della funzione ma le informazioni necessarie perché in fase di linking e loading l'eseguibile risultante possa caricare la giusta DLL e puntare al corretto indirizzo.

Ad esempio, per capire meglio, poniamo il caso che il nostro programma sia

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

che ottiene i dati di versione del sistema operativo e utilizza la funzione GetVersion della libreria dinamica kernel32.dll

Per quanto riguarda il punto 1), la sua firma è contenuta nel file header winbase.h (a sua volta incluso in windows.h posto all'inizio del codice) ovvero

WINBASEAPI DWORD WINAPI GetVersion (VOID);

in cui le informazioni fondamentali sono il nome stesso della funzione (GetVersion), il tipo di dato restituito (DWORD, un valore a 32 bit) e il numero e tipo dei parametri accettati (VOID, ovvero nessun parametro)

Dopo la fase di compilazione, il linker si occuperà di cercare tra librerie indicate (i file .lib indicati come Import Library) quella in cui sono contenute le informazioni della funzione GetVersion.
A questo punto, includerà nell'eseguibile (in una tabella detta Import Table) il nome della DLL (kernel32.dll) con i nomi delle funzioni e i loro indirizzi relativi (entry point) nella dll stessa.

Questo permetterà al linker di trasformare correttamente la linea

DWORD osv = GetVersion();

in

FF 15 C4 81 41 00 call dword ptr [__imp__GetVersion@0 (4181C4h)]

in cui all'indirizzo 4181C4 della Import Table verrà posto l'indirizzo definitivo della GetVersion (ovviamente questo valore, 4181C4 può variare da programma a programma ...).

L'indirizzo definitivo (proprio perché il linking è dinamico) si otterrà solo all'inizio dell'esecuzione del file exe.

Sarà il Loader del sistema operativo a calcolare ed inserire i valori finali (semplificando) in questo modo :

1) otterrà l'indirizzo virtuale di base in cui è caricata la DLL (supponiamo che la kernel32.dll sia caricata a partire dall'indirizzo 7C800000)

2) sommerà il valore dell'Entry Point per la funzione GetVersion trovata nella Import Table (ottenibile con un programma come Depends), ad esempio per XP SP3, 1127A

3) otterrà il valore 7C81127A che verrà depositato nella Import Table all'indirizzo 4181C4 che è esattamente dove la

call dword ptr [__imp__GetVersion@0 (4181C4h)] [/b]

si aspetta di trovare il codice della GetVersion e che verrà eseguita.

Se vi è tutto chiaro, in un prossimo post vedremo come lavorare "dinamicamente" con le funzioni delle DLL, dal supporto offerto da Windows per questo tipo di lavoro e come questo tipo di uso delle funzioni delle DLL sia a volte necessario.

Per chiarimenti e approfondimenti e per rendere questa sezione un po' più interessante ... commentate ...
 
Riferimento: [C] Sulle DLL ...

Davvero interessante, complimenti.


Ricordo che un programma scritto in C, per usufruire di una funzione di una DLL, normalmente, ha bisogno di :

1) conoscerne la firma, ovvero il nome della funzione, il tipo di dato restituito, i parametri in numero e tipo (queste informazioni sono normalmente contenute nei file header, i file con estensione .h e sono utilizzate in fase di compilazione)

2) utilizzare la corrispondente Import Library, un file con estensione .LIB che non contiene il codice effettivo della funzione ma le informazioni necessarie perché in fase di linking e loading l'eseguibile risultante possa caricare la giusta DLL e puntare al corretto indirizzo.

Ad esempio, per capire meglio, poniamo il caso che il nostro programma sia

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

Non ho ben capito questa parte di codice. Il programma legge i byte di ordine inferiore e superiore per verificare se il sistema sia a 32 o 64 bit(anche utilizzando la DWORD)?

nothing ha detto:
Dopo la fase di compilazione, il linker si occuperà di cercare tra librerie indicate (i file .lib indicati come Import Library) quella in cui sono contenute le informazioni della funzione GetVersion.
A questo punto, includerà nell'eseguibile (in una tabella detta Import Table) il nome della DLL (kernel32.dll) con i nomi delle funzioni e i loro indirizzi relativi (entry point) nella dll stessa.

Questo permetterà al linker di trasformare correttamente la linea

DWORD osv = GetVersion();

in

FF 15 C4 81 41 00 call dword ptr [__imp__GetVersion@0 (4181C4h)]

in cui all'indirizzo 4181C4 della Import Table verrà posto l'indirizzo definitivo della GetVersion (ovviamente questo valore, 4181C4 può variare da programma a programma ...).

In base a quale criterio vi è questa trasformazione in FF 15 C4 81 41 00 call dword ptr [__imp__GetVersion@0 (4181C4h)?
 
Riferimento: [C] Sulle DLL ...

Non ho ben capito questa parte di codice. Il programma legge i byte di ordine inferiore e superiore per verificare se il sistema sia a 32 o 64 bit(anche utilizzando la DWORD)?

No, i 32 e i 64 bit non c'entrano (anche perché la GetVersion è una delle prime API e non è stata praticamente modificata dai tempi di Win95) ...
A questo proposito, ricordo che la GetVersion è solo un esempio ma è una API obsoleta. Al suo posto si dovrebbe utilizzare la GetVersionEx e/o la GetProduct ...

Ottenuta la DWORD osv dalla funzione, hai 32 bit che comprendono una WORD alta xxyy e una word bassa wwzz ... ovvero una DWORD

xxyywwzz

Quello che ci interessa è

zz

che è il byte basso della word bassa (LOBYTE della LOWORD) e

ww

che è il byte alto della word bassa (HIBYTE della LOWORD) che indicheranno rispettivamente major version e minor version del sistema operativo.

Ad esempio, per Windows 7 avrai

zz = 6 e ww = 1

ovvero Windows 6.1

Ognuno di questi valori è conservato in una DWORD solo per praticità (un valore a 32 bit viene trattato più velocemente di uno a 8 bit in un sistema a 32 bit), ma puoi benissimo scrivere

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!


In base a quale criterio vi è questa trasformazione in FF 15 C4 81 41 00 call dword ptr [__imp__GetVersion@0 (4181C4h)?

FF 15 è l'opcode per le CPU x86/64 per l'istruzione CALL indiretta con indirizzo in una DWORD e C4 81 41 00 (ovviamente letti al contrario 004181C4) è il puntatore all'indirizzo di destinazione. Ovvero è il puntatore all'entry della import table dove il loader ha posto l'indirizzo della GetVersion. Questo puntatore è calcolato e impostato dal Linker.
 
Riferimento: [C] Sulle DLL ...

Ok, grazie ora mi è chiaro.

osv < 0x80000000 invece è posto proprio per verificare i bit del sistema(intendo il formato standart della variabile nel sistema operativo)?
 
Riferimento: [C] Sulle DLL ...

osv < 0x80000000 invece è posto proprio per verificare i bit del sistema(intendo il formato standart della variabile nel sistema operativo)?

No. La funzione GetVersion ha la particolarità di restituire il bit 31 (il più significativo della DWORD) a 1 se il sistema operativo è precedente a NT (Win98, WinMe, Win95, Win 3.1) mentre è a 0 per i sistemi da NT in poi.

Quindi, se il bit è a 0 allora il valore di osv sarà < di 0x80000000.

Se è così vuol dire che il sistema operativo è "di classe NT" (con tutto quello che ne consegue) e per i sistemi operativi di questo tipo è disponibile (negli altri bit della WORD alta) il numero di "build".
 
Riferimento: [C] Sulle DLL ...

Ti ringrazio per aver postato questa breve introduzione alle DLL in C, inoltre volevo chiederti se potevi spiegare tutto ciò che ha a che fare con la WORD, DWORD, PTR e quant'altro.

sarà < di 0x80000000.

Perchè proprio "8" ?
 
Riferimento: [C] Sulle DLL ...

... se potevi spiegare tutto ciò che ha a che fare con la WORD, DWORD, PTR e quant'altro.

Certo ... magari in un apposito post ...

Perchè proprio "8" ?

Perché quel valore è un numero intero senza segno a 32 bit espresso in esadecimale e se lo converti in binario (cifra per cifra) avrai

1000 0000 0000 0000 0000 0000 0000 0000

e viene usato proprio per capire se il bit 31 (il più importante a sinistra) è a 1 o a 0.

Infatti, non avendo segno, se < allora quel bit sarà a 0.
 
Riferimento: [C] Sulle DLL ...

Certo ... magari in un apposito post ...



Perché quel valore è un numero intero senza segno a 32 bit espresso in esadecimale e se lo converti in binario (cifra per cifra) avrai

1000 0000 0000 0000 0000 0000 0000 0000

e viene usato proprio per capire se il bit 31 (il più importante a sinistra) è a 1 o a 0.

Infatti, non avendo segno, se < allora quel bit sarà a 0.

Perfetto, ho capito. Un'altra cosa : il riferimento alle funzioni come GetVersion si trovano nei file .h ( giusto ? ), ma dato che nessun ambiente di sviluppo ha l'intellisense come si dovrebbe sapere quali funzioni ci sono in ogni singolo header ? Non credo che si debbano imparare a memoria...
 
Riferimento: [C] Sulle DLL ...

Perfetto, ho capito. Un'altra cosa : il riferimento alle funzioni come GetVersion si trovano nei file .h ( giusto ? ), ma dato che nessun ambiente di sviluppo ha l'intellisense come si dovrebbe sapere quali funzioni ci sono in ogni singolo header ? Non credo che si debbano imparare a memoria...

Si imparano ... si imparano ...

E ovviamente si cerca nella documentazione ufficiale (MSDN).

Infatti, quelle "non documentate" sono le funzioni più interessanti ... :emoji_slight_smile:
 
Riferimento: [C] Sulle DLL ...

No. La funzione GetVersion ha la particolarità di restituire il bit 31 (il più significativo della DWORD) a 1 se il sistema operativo è precedente a NT (Win98, WinMe, Win95, Win 3.1) mentre è a 0 per i sistemi da NT in poi.

Quindi, se il bit è a 0 allora il valore di osv sarà < di 0x80000000.

Se è così vuol dire che il sistema operativo è "di classe NT" (con tutto quello che ne consegue) e per i sistemi operativi di questo tipo è disponibile (negli altri bit della WORD alta) il numero di "build".

Grazie sei stato molto chiaro:emoji_smiley:; anche a me interesserebbe molto approfondire questo discorso!