GNU/Linux >> Linux Esercitazione >  >> Linux

Collegamento alla versione precedente del simbolo in un file .so

Ho trovato la seguente soluzione funzionante. Per prima cosa crea il file memcpy.c:

#include <string.h>

/* some systems do not have newest [email protected]@GLIBC_2.14 - stay with old good one */
asm (".symver memcpy, [email protected]_2.2.5");

void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
    return memcpy(dest, src, n);
}

Non sono necessarie CFLAGS aggiuntive per compilare questo file. Poi collega il tuo programma con -Wl,--wrap=memcpy .


Ho avuto un problema simile. Cercando di installare alcuni componenti Oracle su RHEL 7.1, ho ottenuto questo:

$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... 
/some/oracle/lib/libfoo.so: undefined reference to `[email protected]_2.14'

Sembra che la (mia) glibc di RHEL definisca solo [email protected]_2.2.5:

$ readelf -Ws /usr/lib/x86_64-redhat-linux6E/lib64/libc_real.so | fgrep [email protected]
   367: 000000000001bfe0    16 FUNC    GLOBAL DEFAULT    8 [email protected]@GLIBC_2.2.5
  1166: 0000000000019250    16 FUNC    WEAK   DEFAULT    8 [email protected]@GLIBC_2.2.5

Quindi, sono riuscito ad aggirare questo problema, creando prima un file memcpy.c senza wrapping, come segue:

#include <string.h>
asm (".symver old_memcpy, [email protected]_2.2.5");       // hook old_memcpy as [email protected]
void *old_memcpy(void *, const void *, size_t );
void *memcpy(void *dest, const void *src, size_t n)   // then export memcpy
{
    return old_memcpy(dest, src, n);
}

e un file memcpy.map che esporta il nostro memcpy come [email protected]_2.14:

GLIBC_2.14 {
   memcpy;
};

Ho quindi compilato il mio memcpy.c in una libreria condivisa come questa:

$ gcc -shared -fPIC -c memcpy.c
$ gcc -shared -fPIC -Wl,--version-script memcpy.map -o libmemcpy-2.14.so memcpy.o -lc

, spostato libmemcpy-2.14.so in /some/oracle/lib (indicato dagli argomenti -L nel mio collegamento) e collegato di nuovo da

$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... /some/oracle/lib/libmemcpy-2.14.so -lfoo ...

(che è stato compilato senza errori) e verificato da:

$ ldd /some/oracle/bin/foo
    linux-vdso.so.1 =>  (0x00007fff9f3fe000)
    /some/oracle/lib/libmemcpy-2.14.so (0x00007f963a63e000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f963a428000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f963a20c000)
    librt.so.1 => /lib64/librt.so.1 (0x00007f963a003000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f9639c42000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f963aa5b000)

Questo ha funzionato per me. Spero che lo faccia anche per te.


Ho avuto un problema simile. Una libreria di terze parti che utilizziamo ha bisogno del vecchio [email protected]_2.2.5 . La mia soluzione è un approccio esteso pubblicato da @anight.

Distorco anche il memcpy comando, ma ho dovuto utilizzare un approccio leggermente diverso, poiché la soluzione pubblicata da @anight non ha funzionato per me.

memcpy_wrap.c:

#include <stddef.h>
#include <string.h>

asm (".symver wrap_memcpy, [email protected]_2.2.5");
void *wrap_memcpy(void *dest, const void *src, size_t n) {
  return memcpy(dest, src, n);
}

memcpy_wrap.map:

GLIBC_2.2.5 {
   memcpy;
};

Crea il wrapper:

gcc -c memcpy_wrap.c -o memcpy_wrap.o

Ora finalmente quando colleghi il programma aggiungi

  • -Wl,--version-script memcpy_wrap.map
  • memcpy_wrap.o

in modo che ti ritroverai con qualcosa come:

g++ <some flags> -Wl,--version-script memcpy_wrap.map <some .o files> memcpy_wrap.o <some libs>

Basta collegare memcpy in modo statico - estrarre memcpy.o da libc.a ar x /path/to/libc.a memcpy.o (qualunque sia la versione - memcpy è praticamente una funzione autonoma) e includila nel tuo link finale. Tieni presente che il collegamento statico può complicare i problemi di licenza se il tuo progetto è distribuito al pubblico e non open-source.

In alternativa, potresti semplicemente implementare memcpy tu stesso, sebbene la versione dell'assembly ottimizzata manualmente in glibc sia probabilmente più efficiente

Si noti che [email protected]_2.2.5 è mappato su memmove (vecchie versioni di memcpy copiate costantemente in una direzione prevedibile, il che a volte lo ha portato a un uso improprio quando avrebbe dovuto essere usato memmove), e questa è l'unica ragione per l'aumento della versione - potresti semplicemente sostituire memcpy con memmove nel tuo codice per questo caso specifico.

Oppure potresti passare al collegamento statico o assicurarti che tutti i sistemi sulla tua rete abbiano la stessa versione o una versione migliore rispetto alla tua macchina di compilazione.


Linux
  1. Collegamento con una versione precedente di libstdc++

  2. Collegamento a una vecchia versione di libc per fornire una maggiore copertura dell'applicazione

  3. Avviso libpng:versione libpng incompatibile nell'applicazione e nella libreria

  4. riposizionamento R_X86_64_32S contro errore di collegamento

  5. Come posso collegarmi a una versione precedente di una libreria condivisa

Transizione degli abbonamenti da una versione precedente di Plesk a Plesk 12

Come controllare la versione di Ubuntu:metodi semplici e veloci

grep un elenco di grandi dimensioni su un file di grandi dimensioni

Non è d'accordo sulla versione del simbolo symbol_name dopo insmod

pip install pickle non funziona - nessun file o directory di questo tipo

Come installare una versione precedente di gcc su Fedora