Ricerca nel sito web

Come funziona il collegamento statico su Linux


Scopri come combinare più file oggetto C in un singolo eseguibile con librerie statiche.

Il codice per le applicazioni scritte utilizzando C di solito ha più file sorgente, ma alla fine dovrai compilarli in un singolo eseguibile.

Puoi farlo in due modi: creando una libreria statica o una libreria dinamica (chiamata anche libreria condivisa). Questi due tipi di librerie variano in termini di come vengono create e collegate. La scelta di quale utilizzare dipende dal caso d'uso.

In un articolo precedente ho dimostrato come creare un eseguibile collegato dinamicamente, che è il metodo più comunemente utilizzato. In questo articolo spiego come creare un eseguibile collegato staticamente.

Utilizzando un linker con librerie statiche

Un linker è un comando che combina insieme diversi pezzi di un programma e riorganizza l'allocazione di memoria per essi.

Le funzioni di un linker includono:

  • Integrare tutte le parti di un programma
  • Capire una nuova organizzazione della memoria in modo che tutti i pezzi combacino
  • Ripristinare gli indirizzi in modo che il programma possa essere eseguito con la nuova organizzazione della memoria
  • Risoluzione dei riferimenti simbolici

Come risultato di tutte queste funzionalità del linker, viene creato un programma eseguibile chiamato eseguibile.

Le librerie statiche vengono create copiando tutti i moduli di libreria necessari utilizzati in un programma nell'immagine eseguibile finale. Il linker collega le librerie statiche come ultimo passaggio nel processo di compilazione. Un eseguibile viene creato risolvendo riferimenti esterni, combinando le routine della libreria con il codice del programma.

Creare i file oggetto

Ecco un esempio di libreria statica, insieme al processo di collegamento. Innanzitutto, crea il file di intestazione mymath.h con queste firme di funzione:

int add(int a, int b);
int sub(int a, int b);
int mult(int a, int b);
int divi(int a, int b);

Crea add.c, sub.c , mult.c e divi.c con queste definizioni di funzione:

// add.c
int add(int a, int b){
return (a+b);
}

//sub.c
int sub(int a, int b){
return (a-b);
}

//mult.c
int mult(int a, int b){
return (a*b);
}

//divi.c
int divi(int a, int b){
return (a/b);
}

Ora genera file oggetto add.o, sub.o, mult.o e divi.o utilizzando GCC :

$ gcc -c add.c sub.c mult.c divi.c

L'opzione -c salta il passaggio di collegamento e crea solo file oggetto.

Crea una libreria statica chiamata libmymath.a, quindi rimuovi i file oggetto, poiché non sono più necessari. (Nota che usare un comando trash è più sicuro di rm.)

$ ar rs libmymath.a add.o sub.o mult.o divi.o
$ trash *.o
$ ls
add.c  divi.c  libmymath.a  mult.c  mymath.h  sub.c

Ora hai creato una semplice libreria matematica di esempio chiamata libmymath, che puoi utilizzare nel codice C. Ovviamente esistono librerie C molto complesse e questo è il processo utilizzato dai loro sviluppatori per generare il prodotto finale che tu ed io installiamo per l'utilizzo nel codice C.

Successivamente, utilizza la tua libreria matematica in un codice personalizzato e quindi collegala.

Creare un'applicazione collegata staticamente

Supponiamo che tu abbia scritto un comando per la matematica. Crea un file chiamato mathDemo.c e incolla al suo interno questo codice:

#include <mymath.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
  int x, y;
  printf("Enter two numbers\n");
  scanf("%d%d",&x,&y);
 
  printf("\n%d + %d = %d", x, y, add(x, y));
  printf("\n%d - %d = %d", x, y, sub(x, y));
  printf("\n%d * %d = %d", x, y, mult(x, y));

  if(y==0){
    printf("\nDenominator is zero so can't perform division\n");
      exit(0);
  }else{
      printf("\n%d / %d = %d\n", x, y, divi(x, y));
      return 0;
  }
}

Nota che la prima riga è un'istruzione include che fa riferimento, per nome, alla tua libreria libmymath.

Crea un file oggetto chiamato mathDemo.o per mathDemo.c:

$ gcc -I . -c mathDemo.c

L'opzione -I dice a GCC di cercare i file header elencati dopo di essa. In questo caso, stai specificando la directory corrente, rappresentata da un singolo punto (.).

Collega mathDemo.o con libmymath.a per creare l'eseguibile finale. Ci sono due modi per esprimere questo al GCC.

Puoi puntare ai file:

$ gcc -static -o mathDemo mathDemo.o libmymath.a

In alternativa, è possibile specificare il percorso della libreria insieme al nome della libreria:

$ gcc -static -o mathDemo -L . mathDemo.o -lmymath

Nell'ultimo esempio, l'opzione -lmymath dice al linker di collegare i file oggetto presenti in libmymath.a con il file oggetto mathDemo.oper creare l'eseguibile finale. L'opzione -L indica al linker di cercare le librerie nell'argomento seguente (simile a quello che faresti con -I).

Analizzando il risultato

Conferma che sia collegato staticamente utilizzando il comando file:

$ file mathDemo
mathDemo: ELF 64-bit LSB executable, x86-64...
statically linked, with debug_info, not stripped

Usando il comando ldd, puoi vedere che l'eseguibile non è collegato dinamicamente:

$ ldd ./mathDemo
        not a dynamic executable

Puoi anche controllare la dimensione dell'eseguibile mathDemo:

$ du -h ./mathDemo
932K    ./mathDemo

Nell'esempio del mio articolo precedente, l'eseguibile dinamico occupava solo 24K.

Esegui il comando per vederlo funzionare:

$ ./mathDemo
Enter two numbers
10
5

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2

Sembra buono!

Quando utilizzare il collegamento statico

Gli eseguibili collegati dinamicamente sono generalmente preferiti rispetto agli eseguibili collegati staticamente perché il collegamento dinamico mantiene modulari i componenti di un'applicazione. Se una libreria riceve un aggiornamento di sicurezza critico, può essere facilmente patchato perché esiste al di fuori delle applicazioni che lo utilizzano.

Quando usi il collegamento statico, il codice di una libreria viene "nascosto" all'interno dell'eseguibile che crei, il che significa che l'unico modo per correggerlo è ricompilare e rilasciare nuovamente un nuovo eseguibile ogni volta che una libreria riceve un aggiornamento, e hai di meglio cose da fare con il tuo tempo, fidati di me.

Tuttavia, il collegamento statico è un'opzione ragionevole se il codice di una libreria esiste nella stessa base di codice dell'eseguibile che lo utilizza o in dispositivi incorporati specializzati che non dovrebbero ricevere aggiornamenti.

Articoli correlati: