Domanda

Questa domanda è legata a questo così come la sua risposta.

Ho appena scoperto qualche bruttura in una costruzione su cui sto lavorando. Gli sguardi situazione un po 'come il seguente (scritto in formato gmake); nota, questo vale in particolare per un modello di memoria a 32 bit su SPARC e x86 hardware:

OBJ_SET1  := some objects
OBJ_SET2  := some objects

# note: OBJ_SET2 doesn't get this flag
${OBJ_SET1} : CCFLAGS += -PIC

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc
  ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<}

obj1.o       : ${OBJ_SET1}
obj2.o       : ${OBJ_SET2}
sharedlib.so : obj1.o obj2.o
obj1.o obj2.o sharedlib.so :
  ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^}

Chiaramente si può lavorare a mescolare oggetti compilati con e senza PIC in un oggetto condiviso (questo è stato in uso per anni). Non so abbastanza di PIC per sapere se si tratta di una buona idea / intelligente, e la mia ipotesi è, in questo caso non è necessaria, ma piuttosto sta accadendo perché qualcuno non importava abbastanza per scoprire il modo giusto per farlo quando virata il nuovo materiale per la compilazione.

La mia domanda è:

  1. Questa funzione è sicura
  2. E 'una buona idea
  3. Quali potenziali problemi possono verificarsi a seguito
  4. Se posso passare tutto per PIC, ci sono trucchi non evidenti che potrei voler guardare fuori per.
È stato utile?

Soluzione

Hai dimenticato Ho anche scritto questa domanda.

Alcune spiegazioni sono in ordine prima:

    codice
  • non-PIC può essere caricato dal sistema operativo in qualsiasi posizione in memoria in [di più?] moderni sistemi operativi. Dopo tutto quello che è stato caricato, passa attraverso una fase che fissa il segmento di testo (dove la roba eseguibile finisce) quindi si rivolge correttamente le variabili globali; per tirare fuori questo, il segmento di testo deve essere scrivibile.
  • PIC dati eseguibili possono essere caricati una volta dal sistema operativo e condivise tra più utenti / processi. Per il sistema operativo per fare questo, però, il segmento di testo deve essere di sola lettura - il che significa che nessun fix-up. Il codice viene compilato per utilizzare un globale Offset Table (GOT) in modo che possa affrontare globali relativi al GOT, eliminando la necessità per Fix-up.
  • Se un oggetto condiviso è costruito senza PIC, anche se è fortemente incoraggiata non sembra che sia strettamente necessario; se il sistema operativo deve fissare-up del segmento di testo poi è costretto a caricare in memoria che è contrassegnato nella lettura-scrittura ... che impedisce la condivisione tra processi / utenti.
  • Se un binario eseguibile è costruito / con / PIC, non so che cosa va storto sotto il cofano, ma ho assistito un paio di strumenti diventano instabili (arresti misteriosi e simili).

Le risposte:

  • Mixing PIC / non-PIC, o utilizzando PIC in eseguibili può causare difficili da prevedere e rintracciare instabilità. Non ho una spiegazione tecnica del perché.
    • ... per includere segfaults, errori del bus, la corruzione dello stack, e probabilmente altro ancora.
  • Non PIC in oggetti condivisi non è probabilmente andando a causare problemi seri, anche se può risultare in più RAM utilizzata se la libreria viene utilizzato più volte attraverso i processi e / o utenti.

update (4/17)

Da allora ho scoperto la causa di alcuni degli incidenti che avevano visto in precedenza. Facciamo un esempio:

/*header.h*/
#include <map>
typedef std::map<std::string,std::string> StringMap;
StringMap asdf;

/*file1.cc*/
#include "header.h"

/*file2.cc*/
#include "header.h"

int main( int argc, char** argv ) {
  for( int ii = 0; ii < argc; ++ii ) {
    asdf[argv[ii]] = argv[ii];
  }

  return 0;
}

... allora:

$ g++ file1.cc -shared -PIC -o libblah1.so
$ g++ file1.cc -shared -PIC -o libblah2.so
$ g++ file1.cc -shared -PIC -o libblah3.so
$ g++ file1.cc -shared -PIC -o libblah4.so
$ g++ file1.cc -shared -PIC -o libblah5.so

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa
#     ^^^^^^^^^
#     This is the evil that made it possible
$ args=(this is the song that never ends);
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done)

Questo esempio particolare non può finire per schiantarsi, ma è fondamentalmente la situazione che esisteva nel codice che di gruppo. Se ha in crash è probabile che tu sia nel distruttore, di solito un errore di doppio libero.

Molti anni precedenti hanno aggiunto -zmuldefs a loro costruzione di sbarazzarsi di errori simbolo si moltiplicano definiti. Il compilatore emette codice per l'esecuzione di costruttori / distruttori su oggetti globali. -zmuldefs forze a vivere nella stessa posizione in memoria, ma lo gestisce ancora costruttori / distruttori una volta per l'exe e ogni libreria che comprendeva l'intestazione incriminato -. da qui il doppio libera

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top