GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Verknüpfen mit einer älteren Symbolversion in einer .so-Datei

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:

exportiert
GLIBC_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:

erhalten
g++ <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.


Linux
  1. Link mit einer älteren Version von libstdc++

  2. Verknüpfen mit einer alten Version von libc, um eine größere Anwendungsabdeckung bereitzustellen

  3. grep eine große Liste gegen eine große Datei

  4. Wie kann ich eine Verknüpfung zu einer älteren Version einer gemeinsam genutzten Bibliothek herstellen?

  5. Der Emulator kann die Zeichenfolge „Linux-Version“ in der Kernel-Image-Datei nicht finden

Umstellung von Abonnements von einer älteren Plesk-Version auf Plesk 12

So überprüfen Sie die Ubuntu-Version – schnelle und einfache Methoden

pip install pickle funktioniert nicht - keine solche Datei oder kein Verzeichnis

So installieren Sie eine ältere Version von gcc auf Fedora

Ordnungsgemäßes Löschen von Dateien, die älter als 30 Tage sind

Datei-Geodatabase in QGIS für Ubuntu öffnen?