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.