Ich habe die folgende funktionierende Lösung gefunden. Erstellen Sie zuerst die Datei 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);
}
Zum Kompilieren dieser Datei sind keine zusätzlichen CFLAGS erforderlich. Dann verknüpfen Sie Ihr Programm mit -Wl,--wrap=memcpy .
Ich hatte ein ähnliches Problem. Beim Versuch, einige Oracle-Komponenten auf RHEL 7.1 zu installieren, habe ich Folgendes erhalten:
$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ...
/some/oracle/lib/libfoo.so: undefined reference to `[email protected]_2.14'
Es scheint, dass (mein) RHELs glibc nur [email protected]_2.2.5 definiert:
$ 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
Also habe ich es geschafft, dies zu umgehen, indem ich zuerst eine memcpy.c-Datei ohne Wrapping wie folgt erstellt habe:
#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);
}
und eine memcpy.map-Datei, die unsere memcpy als [email protected]_2.14:
exportiertGLIBC_2.14 {
memcpy;
};
Ich habe dann meine eigene memcpy.c wie folgt in eine Shared Lib kompiliert:
$ gcc -shared -fPIC -c memcpy.c
$ gcc -shared -fPIC -Wl,--version-script memcpy.map -o libmemcpy-2.14.so memcpy.o -lc
, verschoben libmemcpy-2.14.so in /irgendeine/oracle/lib (zeigt durch -L Argumente in meiner Verlinkung) und erneut verlinkt durch
$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... /some/oracle/lib/libmemcpy-2.14.so -lfoo ...
(was fehlerfrei kompiliert wurde) und verifiziert durch:
$ 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)
Das hat bei mir funktioniert. Ich hoffe, es tut es auch für Sie.
Ich hatte ein ähnliches Problem. Eine von uns verwendete Bibliothek eines Drittanbieters benötigt den alten [email protected]_2.2.5
. Meine Lösung ist ein erweiterter Ansatz @anight posted.
Ich verzerre auch die memcpy
Befehl, aber ich musste einen etwas anderen Ansatz verwenden, da die von @anight gepostete Lösung bei mir nicht funktionierte.
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;
};
Erstellen Sie den Wrapper:
gcc -c memcpy_wrap.c -o memcpy_wrap.o
Fügen Sie nun endlich beim Verlinken des Programms
hinzu-Wl,--version-script memcpy_wrap.map
memcpy_wrap.o
sodass Sie am Ende so etwas wie:
erhalteng++ <some flags> -Wl,--version-script memcpy_wrap.map <some .o files> memcpy_wrap.o <some libs>
Linken Sie memcpy einfach statisch - ziehen Sie memcpy.o aus libc.a ar x /path/to/libc.a memcpy.o
(unabhängig von der Version - memcpy ist so ziemlich eine eigenständige Funktion) und fügen Sie sie in Ihren endgültigen Link ein. Beachten Sie, dass die statische Verlinkung Lizenzierungsprobleme erschweren kann, wenn Ihr Projekt öffentlich und nicht als Open Source vertrieben wird.
Alternativ könnten Sie memcpy einfach selbst implementieren, obwohl die von Hand abgestimmte Assembler-Version in glibc wahrscheinlich effizienter ist
Beachten Sie, dass [email protected]_2.2.5 auf memmove abgebildet wird (alte Versionen von memcpy wurden konsequent in eine vorhersehbare Richtung kopiert, was dazu führte, dass es manchmal missbraucht wurde, wenn memmove hätte verwendet werden sollen), und dies der einzige Grund für die Versionserhöhung ist - Für diesen speziellen Fall könnten Sie in Ihrem Code einfach memcpy durch memmove ersetzen.
Oder Sie könnten zur statischen Verknüpfung wechseln oder sicherstellen, dass alle Systeme in Ihrem Netzwerk die gleiche oder eine bessere Version als Ihr Build-Computer haben.