2017-07-25 3 views
1

J'ai simple passe de LLVM qui renomme toutes les fonctions définies dans l'unité de traduction en cours (i.e.: le fichier source en question, après toutes les étapes de pré-traitement ont eu lieu - voir here). Mon passe est la suivante:Comment relier deux modules de code binaire LLVM?

#include <vector> 
#include <iostream> 
#include <fstream> 
#include <string> 
#include <sstream> 

#include "llvm/Pass.h" 
#include "llvm/IR/Function.h" 
#include "llvm/Support/raw_ostream.h" 
#include "llvm/ADT/STLExtras.h" 
#include "llvm/ADT/SmallString.h" 
#include "llvm/IR/DerivedTypes.h" 
#include "llvm/IR/Module.h" 
#include "llvm/IR/Type.h" 
#include "llvm/IR/TypeFinder.h" 
#include "llvm/Transforms/IPO.h" 
#include "llvm/IR/Argument.h" 
#include "llvm/IR/GlobalValue.h" 

using namespace llvm; 

namespace { 

    struct FunctionRename : public ModulePass { 
    static char ID; // Pass identification 
    FunctionRename() : ModulePass(ID) {} 

    bool runOnModule(Module &M) override { 
     // Rename all functions 
     for (auto &F : M) { 
     StringRef Name = F.getName(); 
     // Leave library functions alone because their presence or absence 
     // could affect the behaviour of other passes. 
     if (F.isDeclaration()) 
      continue; 
     F.setLinkage(GlobalValue::LinkOnceAnyLinkage); 
     F.setName(Name + "_renamed"); 
     } 
     return true; 
    } 
    }; 
} 

char FunctionRename::ID = 0; 
static RegisterPass<FunctionRename> X("functionrename", "Function Rename Pass"); 
// ===-------------------------------------------------------==// 
// 
// Function Renamer - Renames all functions 
// 

Après avoir exécuté le passage sur un fichier de code binaire, file.bc, je sortie le résultat dans un nouveau fichier file_renamed.bc, comme suit

opt -load /path/to/libFunctionRenamePass.so -functionrename <file.bc> file_renamed.bc

Je tente alors de relier les deux fichiers comme suit

llvm-link file.bc file_renamed.bc -o file_linked.bc

Cependant, je reçois toujours affrontements de symboles pour les fichiers source C (à partir de laquelle le fichier initial est généré code binaire) où les constructeurs et destructeurs sont impliqués. Mon attente est que la ligne

F.setLinkage(GlobalValue::LinkOnceAnyLinkage)

empêcherait les affrontements de symboles qui se produisent pour tous les symboles définis dans file.bc et file_renamed.bc.

Qu'est-ce que je fais mal?

+0

Pouvez-vous fournir le texte réel des erreurs que vous recevez? – jvstech

Répondre

0

Ma solution complète est la suivante:

#include <vector> 
#include <iostream> 
#include <fstream> 
#include <string> 
#include <sstream> 

#include "llvm/Pass.h" 
#include "llvm/IR/Function.h" 
#include "llvm/Support/raw_ostream.h" 
#include "llvm/ADT/STLExtras.h" 
#include "llvm/ADT/SmallString.h" 
#include "llvm/IR/DerivedTypes.h" 
#include "llvm/IR/Module.h" 
#include "llvm/IR/Type.h" 
#include "llvm/IR/TypeFinder.h" 
#include "llvm/Transforms/IPO.h" 
#include "llvm/IR/Argument.h" 
#include "llvm/IR/GlobalValue.h" 
#include "llvm/IR/Metadata.h" 

using namespace llvm; 

namespace { 

    struct FunctionRename : public ModulePass { 
    static char ID; // Pass identification 
    FunctionRename() : ModulePass(ID) {} 

    bool runOnModule(Module &M) override { 

     for (auto it = M.global_begin(); it != M.global_end(); ++it) 
     { 
     GlobalVariable& gv = *it; 
     if (!gv.isDeclaration()) 
      gv.setLinkage(GlobalValue::LinkerPrivateLinkage); 
     } 

     for (auto it = M.alias_begin(); it != M.alias_end(); ++it) 
     { 
     GlobalAlias& ga = *it; 
     if (!ga.isDeclaration()) 
      ga.setLinkage(GlobalValue::LinkerPrivateLinkage); 
     } 

     // Rename all functions 
     for (auto &F : M) { 
     StringRef Name = F.getName(); 
     // Leave library functions alone because their presence or absence 
     // could affect the behaviour of other passes. 
     if (F.isDeclaration()) 
      continue; 
     F.setLinkage(GlobalValue::WeakAnyLinkage); 
     F.setName(Name + "_renamed"); 
     } 
     return true; 
    } 
    }; 
} 

char FunctionRename::ID = 0; 
static RegisterPass<FunctionRename> X("functionrename", "Function Rename Pass"); 
// ===-------------------------------------------------------==// 
// 
// Function Renamer - Renames all functions 
// 

Dans la boucle pour traiter les fonctions, for(auto &F : M) { ... }, je préfère utiliser WeakAnyLinkage au lieu de LinkOnceAnyLinkage pour les raisons suivantes.

Les globes avec LinkOnceAnyLinkage - comme son nom l'indique - sont fusionnés avec d'autres symboles du même nom lorsque la liaison se produit, et les globaux non référencés avec ce lien peuvent être rejetés.

Globals avec WeakAnyLinkage partagent la même sémantique de GLOBALS avec LinkOnceAnyLinkage, sauf que GLOBALS avec WeakAnyLinkage non référencés ne peuvent pas être mis au rebut.

De plus, dans les deux boucles pour traiter les globales et les alias, j'utilise LinkerPrivateLinkage, car je ne veux pas que les globaux dans file_renamed.bc soient accessibles par des objets en dehors de ce module. En outre, la boucle de traitement des alias est nécessaire (au moins sur mon environnement) pour éviter les conflits de symboles liés aux constructeurs et destructeurs d'objets complets (par exemple: les destructeurs C1 et D1 selon Itanium C++ ABI).

1

Quand j'ai essayé l'exécution de votre code sur un fichier de code binaire exemple, l'étape LLVM liaison a échoué en raison des variables globales:

ERROR: Linking globals named 'my_global': symbol multiply defined! 

Après avoir ajouté une deuxième boucle à la routine de RunOnModule pour traiter les variables globales, LLVM-link réussit et le code en fin de compte lié. Cependant, mon simple test du code C++ avec les constructeurs a fonctionné avec et sans cette modification.