2016-04-06 4 views
1

J'essaie de construire un exécutable sur Linux qui répond aux critères suivants:Est-il possible d'établir un lien statique entre libstdC++ et wrap memcpy?

  1. lié statiquement à libstdC++ et libgcc
  2. construit avec une version récente de gcc (version> = 4.8.2) et glibc (version> 2.14)
  3. arrière compatible avec les anciennes versions de la glibc (version < 2,5)

Mon environnement actuel dev est gcc4.8.5, glibc 2.17 sur CentOS 7. Le binaire construit ne fonctionne pas sur les systèmes avec glibc < 2.14 en raison d'une dépendance sur memcpy.

objdump -T main | fgrep GLIBC_2.14 
0000000000000000  DF *UND* 0000000000000000 GLIBC_2.14 memcpy 

Il y avait un changement de rupture à Memcpy introduit dans la glibc 2.14 donc je veux forcer l'utilisation d'une version plus ancienne. Je suis tombé sur ce message de stackoverflow Linking against older symbol version in a .so file mais cela n'a pas fonctionné pour moi en raison des problèmes d'éditeur de liens liés à libstdC++. Voici ma tentative de solution ci-dessous.

main.cpp

#include <iostream> 
#include <string.h> 

int main(int argc, char** argv) 
{ 
    char source[] = "once upon a midnight dreary...", dest[4]; 
    memcpy(dest, source, sizeof dest); 
    std::cout << dest << std::endl; 
} 

wrap_memcpy.cpp

#include <string.h> 

__asm__(".symver memcpy, [email protected]_2.2.5"); 

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

options du compilateur et des erreurs:

g++ -static-libgcc -static-libstdc++ wrap_memcpy.cpp main.cpp -o main -Wl,--wrap=memcpy 

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::ctype<char>::widen(char const*, char const*, char*) const': 
(.text._ZNKSt5ctypeIcE5widenEPKcS2_Pc[_ZNKSt5ctypeIcE5widenEPKcS2_Pc]+0x5f): undefined reference to `__wrap_memcpy' 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::__timepunct<char>::__timepunct(__locale_struct*, char const*, unsigned long)': 
(.text._ZNSt11__timepunctIcEC2EP15__locale_structPKcm[_ZNSt11__timepunctIcEC5EP15__locale_structPKcm]+0x96): undefined reference to `__wrap_memcpy' 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::messages<char>::messages(__locale_struct*, char const*, unsigned long)': 
(.text._ZNSt8messagesIcEC2EP15__locale_structPKcm[_ZNSt8messagesIcEC5EP15__locale_structPKcm]+0x8e): undefined reference to `__wrap_memcpy' 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::messages_byname<char>::messages_byname(char const*, unsigned long)': 
(.text._ZNSt15messages_bynameIcEC2EPKcm[_ZNSt15messages_bynameIcEC5EPKcm]+0xd6): undefined reference to `__wrap_memcpy' 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::__numpunct_cache<char>::_M_cache(std::locale const&)': 
(.text._ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale[_ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale]+0x2ad): undefined reference to `__wrap_memcpy' 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o):(.text._ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale[_ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale]+0x2cd): more undefined references to `__wrap_memcpy' follow 
collect2: error: ld returned 1 exit status 

ce que je fais mal ici? J'ai également essayé d'autres solutions dans le poste de débordement de la pile et j'ai la même erreur. J'ai aussi essayé de construire ceci sur glibc 5.2.1 sous Ubuntu 15.0.4 et j'ai obtenu le même résultat. Notez que lier de manière statique memcpy (qui est sous la licence GPL) dans le binaire n'est pas une option en raison de problèmes de licence.

+0

Le chemin du moins La résistance est probablement de rechercher et remplacer globalement toutes les utilisations de 'memcpy' dans votre code avec' memmove', et vous n'aurez pas besoin de l'ancien 'memcpy'. Sinon, corrigez le code qui dépend du comportement 'memcpy' non garanti, mais si c'était facile, vous l'avez déjà fait. – zwol

+0

Merci pour la réponse. Malheureusement, nous dépendons des bibliothèques tierces qui dépendent du nouveau memcpy (par exemple, boost). #include ajoute également une dépendance à memcpy. – yoshimonster

+0

Peut-être que je ne comprends pas votre problème. Si votre code n'a pas besoin du comportement non garanti de l'ancien 'memcpy', alors pourquoi essayez-vous de l'utiliser? (Autrement dit, pourquoi est-ce un problème pour votre binaire de se référer au nouveau 'memcpy'?) – zwol

Répondre

3

Vous devez insérer __wrap_memcpy dans extern "C" {}, de sorte que cette fonction est exportée en tant que fonction C; sinon son nom sera décoré comme une fonction C++. De plus, je suggère fortement une #ifdef supplémentaire, parce que ce problème se produit uniquement avec les versions ultérieures du compilateur et uniquement pour x64 (les conditions ne sont pas tout à fait parfait, donc peut-être besoin de les ajuster):

#if defined(__GNUC__) && defined(__LP64__) && __LP64__ >= 1 && \ 
(_GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && \ 
(defined(__x86_64__) || defined(__i386__) ||\ 
defined(__i486__) || defined(__i586__) || defined(__i686__)) 

#include <string.h> 

__asm__(".symver memcpy, [email protected]_2.2.5"); 

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

#endif 
+0

Cela a fait l'affaire! Merci beaucoup! – yoshimonster

+0

Cette question m'a permis de gagner du temps. Merci –