Collegamento dinamico - Linux vs. finestre


10

In Windows, quando compilo il codice C / C ++ in un progetto DLL in MSVC, ottengo 2 file:

  1. MyDll.dll
  2. MyDll.lib

dove per quanto ho capito MyDll.libcontiene una sorta di tabella di puntatori che indica le posizioni delle funzioni nella dll. Quando si usa questa dll, diciamo in un file exe, MyDll.libviene incorporato nel file exe durante il collegamento, quindi in fase di esecuzione "sa" dove si trovano le funzioni MyDll.dlle possono usarle.

Ma se compilo lo stesso codice sotto Linux ottengo solo un file MySo.sosenza MySo.a(l'equivalente al libfile in Linux), quindi come fa un file eseguibile sotto Linux a sapere dove si trovano le funzioni MySo.sose nulla è incorporato in esso durante il collegamento?

Risposte:


1

Su Linux, il linker (non il linker dinamico) cerca nelle librerie condivise specificate al momento del collegamento e crea riferimenti ad esse all'interno dell'eseguibile. Quando il linker dinamico carica questi file eseguibili, carica in memoria le librerie condivise di cui hanno bisogno e risolve i simboli, consentendo l'esecuzione dei file binari.

MySo.a, se creato, includerebbe effettivamente i simboli da collegare direttamente nel file binario anziché le "tabelle di ricerca dei simboli" utilizzate su Windows.

la risposta di rustyx spiega il processo su Windows in modo più approfondito di quello che posso; è da tanto che non uso Windows.


1
"Windows adotta un approccio diverso ... specifica al sistema operativo esattamente dove si trovano i simboli nella DLL" - questo contraddice wiki , che dice che i nomi delle funzioni sono ancora risolti (all'avvio o alla prima chiamata alla funzione libreria) anche quando si usa ordinali (a meno che non venga utilizzato l'associazione diretta dell'indirizzo che nessuno farebbe perché costringe gli utenti della biblioteca a ricompilare e ridistribuire il loro codice ogni volta che cambia la biblioteca).
yugr

@yugr Rimossa quella parte, stavo comunque afferrando le cannucce.
SS Anne,

4

Il linker MSVC può collegare insieme file di oggetti (.obj) e librerie di oggetti (.lib) per produrre un .EXE o un .DLL.

Per collegarsi a una DLL, il processo in MSVC consiste nell'utilizzare una cosiddetta libreria di importazione (.LIB) che funge da collante tra i nomi delle funzioni C e la tabella di esportazione della DLL (in una DLL una funzione può essere esportata per nome o da ordinale : quest'ultimo veniva spesso utilizzato per API non documentate).

Tuttavia, nella maggior parte dei casi la tabella di esportazione DLL ha tutti i nomi delle funzioni e quindi la libreria di importazione (.LIB) contiene informazioni ampiamente ridondanti (" funzione di importazione ABC -> funzione esportata ABC ", ecc.).
È anche possibile generare un .LIB da un .DLL esistente.

I linker su altre piattaforme non hanno questa "funzionalità" e possono collegarsi direttamente con le librerie dinamiche.


"I linker su altre piattaforme non dispongono di questa funzionalità", sebbene sia facile da implementare (ad esempio Implib.so lo fa per Linux) per ottenere un caricamento ritardato e altre chicche.
yugr

@yugr: ecco perché "feature" è tra virgolette - non è qualcosa che generalmente vuoi fare ed è un lavoro extra che devi fare su Windows.
Chris Dodd,

1

La differenza che stai vedendo è più di un dettaglio di implementazione - sia Linux che Windows funzionano allo stesso modo - il codice chiama una funzione stub che è staticamente collegata nel tuo eseguibile e questo stub carica quindi DLL / shlib se necessario (in caso di ritardo caricamento , altrimenti la libreria viene caricata all'avvio del programma) e (alla prima chiamata) risolve il simbolo tramite GetProcAddress/ dlsym.

L'unica differenza è che su Linux queste funzioni stub (che sono chiamate stub PLT) vengono generate dinamicamente quando si collega l'app con la libreria dinamica (la libreria contiene informazioni sufficienti per generarle), mentre su Linux sono invece generate quando la stessa DLL è creato, in un .libfile separato .

I due approcci sono così simili che in realtà è possibile imitare le librerie di importazione di Windows su Linux (vedi progetto Implib.so ).


0

Su Linux, si passa MySo.soal linker ed è in grado di estrarre solo ciò che è necessario per la fase di collegamento, inserendo un riferimento MySo.sonecessario in fase di esecuzione.


-3

.dllo .sosono librerie condivise (collegate in runtime), mentre .aed .libè una libreria statica (collegata in fase di compilazione). Questa non è una differenza tra Windows e Linux.

La differenza è, come vengono gestiti. Nota: la differenza sta solo nella dogana, come vengono utilizzati. Non sarebbe troppo difficile realizzare build Linux su Windows e viceversa, tranne che praticamente nessuno lo fa.

Se usiamo una dll o chiamiamo una funzione anche dal nostro binario, c'è un modo semplice e chiaro. Ad esempio, in C, vediamo che:

int example(int x) {
  ...do_something...
}

int ret = example(42);

Tuttavia, a livello di asm, potrebbero esserci molte differenze. Ad esempio, su x86, callviene eseguito un codice operativo, che 42viene indicato nello stack. O in alcuni registri. O ovunque. Nessuno lo sa prima di scrivere la dll , come verrà usata. O come i progetti vorranno utilizzarlo, possibile scritto con un compilatore (o in una lingua!) Che non esiste nemmeno adesso (o è sconosciuto per gli sviluppatori della dll).

Ad esempio, per impostazione predefinita, sia C che Pascal inseriscono gli argomenti (e ottengono i valori restituiti) dallo stack, ma lo stanno facendo in un ordine diverso . Puoi anche scambiare argomenti tra le tue funzioni nei registri mediante alcune ottimizzazioni dipendenti dal compilatore.

Come vedi correttamente, l'abitudine di Windows è che costruendo una dll, creiamo anche un minimo .a/ .libcon esso. Questa libreria statica minima è solo un wrapper, i simboli (funzioni) di quella DLL sono raggiunti attraverso di essa. Ciò rende necessarie le conversioni di chiamata a livello di asm.

Il suo vantaggio è la compatibilità. Lo svantaggio è che se hai solo una DLL, puoi avere difficoltà a capire come si chiamano le sue funzioni. Questo rende l'utilizzo delle DLL un'attività di hacking, se lo sviluppatore della DLL non ti dà il.a . Pertanto, serve principalmente a scopi di chiusura, ad esempio, quindi è più facile ottenere denaro extra per gli SDK.

Un altro svantaggio è che anche se si utilizza una libreria dinamica, è necessario compilare staticamente questo piccolo wrapper.

In Linux, l'interfaccia binaria delle dll è standard e segue la convenzione C. Pertanto, non .aè necessario e esiste una compatibilità binaria tra le librerie condivise, in cambio non abbiamo i vantaggi dell'abitudine di microsoft.


1
Fornire un collegamento di prova che le funzioni di stub possono modificare l'ordine degli argomenti. Non ne ho mai sentito parlare prima ed è difficile da credere, dato quanto grandi sarebbero le spese generali.
yugr

@yugr Un semplice riordino del registro / stack non è un sovraccarico di prestazioni. Se usi dll compilate da msvc dai binari compilati da msvc, ovviamente non accadrà troppo, ma potrebbe accadere.
Peter - Ripristina Monica il

1
Potremmo discuterne, ma nel caso abbiate ragione, dovrebbe essere facile fornire prove che le funzioni di stub sono in grado di elaborare argomenti non banali (ed essere più che semplici trampolini fittizi).
yugr

@yugr Gli stub hanno accesso alle firme delle funzioni della dll, il che rende banale l'elaborazione non banale.
Peter - Ripristina Monica il

1
Ti suggerisco solo di completare la tua risposta con alcuni link di prova riguardanti ciò che fa la libreria di importazione (perché alcune delle affermazioni sono discutibili).
yugr
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.