Home | History | Annotate | Download | only in X86
      1 //===- X86RelocationFactory.cpp -------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include <llvm/ADT/Twine.h>
     11 #include <llvm/Support/ErrorHandling.h>
     12 #include <llvm/Support/DataTypes.h>
     13 #include <llvm/Support/ELF.h>
     14 #include <mcld/MC/MCLDInfo.h>
     15 #include <mcld/LD/Layout.h>
     16 
     17 #include "X86RelocationFactory.h"
     18 #include "X86RelocationFunctions.h"
     19 
     20 using namespace mcld;
     21 
     22 DECL_X86_APPLY_RELOC_FUNCS
     23 
     24 //===--------------------------------------------------------------------===//
     25 // X86RelocationFactory
     26 X86RelocationFactory::X86RelocationFactory(size_t pNum,
     27                                            X86GNULDBackend& pParent)
     28   : RelocationFactory(pNum),
     29     m_Target(pParent) {
     30 }
     31 
     32 X86RelocationFactory::~X86RelocationFactory()
     33 {
     34 }
     35 
     36 void X86RelocationFactory::applyRelocation(Relocation& pRelocation,
     37                                            const MCLDInfo& pLDInfo)
     38 {
     39   Relocation::Type type = pRelocation.type();
     40 
     41   /// the prototype of applying function
     42   typedef Result (*ApplyFunctionType)(Relocation& pReloc,
     43 				      const MCLDInfo& pLDInfo,
     44                                       X86RelocationFactory& pParent);
     45 
     46   // the table entry of applying functions
     47   struct ApplyFunctionTriple {
     48     ApplyFunctionType func;
     49     unsigned int type;
     50     const char* name;
     51   };
     52 
     53   // declare the table of applying functions
     54   static ApplyFunctionTriple apply_functions[] = {
     55     DECL_X86_APPLY_RELOC_FUNC_PTRS
     56   };
     57 
     58   if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
     59     llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
     60 			     llvm::Twine((int) type) +
     61 			     llvm::Twine(" to symbol `") +
     62                              pRelocation.symInfo()->name() +
     63                              llvm::Twine("'."));
     64     return;
     65   }
     66 
     67   // apply the relocation
     68   Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
     69 
     70   // check result
     71   if (Overflow == result) {
     72     llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
     73                              llvm::Twine(apply_functions[type].name) +
     74                              llvm::Twine("' causes overflow. on symbol: `") +
     75                              llvm::Twine(pRelocation.symInfo()->name()) +
     76                              llvm::Twine("'."));
     77     return;
     78   }
     79 
     80   if (BadReloc == result) {
     81     llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
     82                              llvm::Twine(apply_functions[type].name) +
     83                              llvm::Twine("' encounters unexpected opcode. "
     84                                          "on symbol: `") +
     85                              llvm::Twine(pRelocation.symInfo()->name()) +
     86                              llvm::Twine("'."));
     87     return;
     88   }
     89 }
     90 
     91 
     92 
     93 // non-member functions
     94 
     95 //=========================================//
     96 // Relocation helper function              //
     97 //=========================================//
     98 
     99 // Check if symbol can use relocation R_386_RELATIVE
    100 static bool
    101 helper_use_relative_reloc(const ResolveInfo& pSym,
    102                           const MCLDInfo& pLDInfo,
    103                           const X86RelocationFactory& pFactory)
    104 
    105 {
    106   // if symbol is dynamic or undefine or preemptible
    107   if(pSym.isDyn() ||
    108      pSym.isUndef() ||
    109      pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
    110     return false;
    111   return true;
    112 }
    113 
    114 static
    115 GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
    116                                   const MCLDInfo& pLDInfo,
    117                                   X86RelocationFactory& pParent)
    118 {
    119   // rsym - The relocation target symbol
    120   ResolveInfo* rsym = pReloc.symInfo();
    121   X86GNULDBackend& ld_backend = pParent.getTarget();
    122 
    123   bool exist;
    124   GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
    125   if (!exist) {
    126     // If we first get this GOT entry, we should initialize it.
    127     if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
    128       // No corresponding dynamic relocation, initialize to the symbol value.
    129       got_entry.setContent(pReloc.symValue());
    130     }
    131     else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
    132       // Initialize corresponding dynamic relocation.
    133       Relocation& rel_entry =
    134         *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
    135       assert(!exist && "GOT entry not exist, but DynRel entry exist!");
    136       if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
    137         // Initialize got entry to target symbol address
    138         got_entry.setContent(pReloc.symValue());
    139         rel_entry.setType(llvm::ELF::R_386_RELATIVE);
    140         rel_entry.setSymInfo(0);
    141       }
    142       else {
    143         got_entry.setContent(0);
    144         rel_entry.setType(llvm::ELF::R_386_GLOB_DAT);
    145         rel_entry.setSymInfo(rsym);
    146       }
    147       rel_entry.targetRef().assign(got_entry);
    148     }
    149     else {
    150       llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
    151     }
    152   }
    153   return got_entry;
    154 }
    155 
    156 
    157 static
    158 X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
    159 {
    160   return pParent.getTarget().getGOT().getSection().addr();
    161 }
    162 
    163 
    164 static
    165 X86RelocationFactory::Address helper_GOT(Relocation& pReloc,
    166                                          const MCLDInfo& pLDInfo,
    167                                          X86RelocationFactory& pParent)
    168 {
    169   GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo,  pParent);
    170   return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
    171 }
    172 
    173 
    174 static
    175 PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
    176                                   X86RelocationFactory& pParent)
    177 {
    178   // rsym - The relocation target symbol
    179   ResolveInfo* rsym = pReloc.symInfo();
    180   X86GNULDBackend& ld_backend = pParent.getTarget();
    181 
    182   bool exist;
    183   PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
    184   if (!exist) {
    185     // If we first get this PLT entry, we should initialize it.
    186     if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
    187       GOTEntry& gotplt_entry =
    188         *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
    189       // Initialize corresponding dynamic relocation.
    190       Relocation& rel_entry =
    191         *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
    192       assert(!exist && "PLT entry not exist, but DynRel entry exist!");
    193       rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
    194       rel_entry.targetRef().assign(gotplt_entry);
    195       rel_entry.setSymInfo(rsym);
    196     }
    197     else {
    198       llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
    199     }
    200   }
    201   return plt_entry;
    202 }
    203 
    204 
    205 
    206 static
    207 X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent)
    208 {
    209   return pParent.getTarget().getPLT().getSection().addr();
    210 }
    211 
    212 
    213 static
    214 X86RelocationFactory::Address helper_PLT(Relocation& pReloc,
    215                                          X86RelocationFactory& pParent)
    216 {
    217   PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
    218   return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
    219 }
    220 
    221 // Get an relocation entry in .rel.dyn and set its type to pType,
    222 // its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
    223 static
    224 void helper_DynRel(Relocation& pReloc,
    225                    X86RelocationFactory::Type pType,
    226                    X86RelocationFactory& pParent)
    227 {
    228   // rsym - The relocation target symbol
    229   ResolveInfo* rsym = pReloc.symInfo();
    230   X86GNULDBackend& ld_backend = pParent.getTarget();
    231   bool exist;
    232 
    233   Relocation& rel_entry =
    234     *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
    235   rel_entry.setType(pType);
    236   rel_entry.targetRef() = pReloc.targetRef();
    237 
    238   if(pType == llvm::ELF::R_386_RELATIVE)
    239     rel_entry.setSymInfo(0);
    240   else
    241     rel_entry.setSymInfo(rsym);
    242 }
    243 
    244 
    245 //=========================================//
    246 // Each relocation function implementation //
    247 //=========================================//
    248 
    249 // R_386_NONE
    250 X86RelocationFactory::Result none(Relocation& pReloc,
    251                                   const MCLDInfo& pLDInfo,
    252                                   X86RelocationFactory& pParent)
    253 {
    254   return X86RelocationFactory::OK;
    255 }
    256 
    257 // R_386_32: S + A
    258 X86RelocationFactory::Result abs32(Relocation& pReloc,
    259                                    const MCLDInfo& pLDInfo,
    260                                    X86RelocationFactory& pParent)
    261 {
    262   ResolveInfo* rsym = pReloc.symInfo();
    263   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
    264   RelocationFactory::DWord S = pReloc.symValue();
    265 
    266   if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
    267     helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
    268     pReloc.target() = S + A;
    269     return X86RelocationFactory::OK;
    270   }
    271   else if(!rsym->isLocal()) {
    272     if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
    273       S = helper_PLT(pReloc, pParent);
    274       pReloc.target() = S + A;
    275     }
    276     if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
    277       if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
    278         helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
    279       }
    280       else {
    281         helper_DynRel(pReloc, pReloc.type(), pParent);
    282         return X86RelocationFactory::OK;
    283       }
    284     }
    285   }
    286 
    287   // perform static relocation
    288   pReloc.target() = S + A;
    289   return X86RelocationFactory::OK;
    290 }
    291 
    292 // R_386_PC32: S + A - P
    293 X86RelocationFactory::Result rel32(Relocation& pReloc,
    294                                    const MCLDInfo& pLDInfo,
    295                                    X86RelocationFactory& pParent)
    296 {
    297   // perform static relocation
    298   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
    299   pReloc.target() = pReloc.symValue() + A
    300       - pReloc.place(pParent.getLayout());
    301   return X86RelocationFactory::OK;
    302 }
    303 
    304 // R_386_GOTOFF: S + A - GOT_ORG
    305 X86RelocationFactory::Result gotoff32(Relocation& pReloc,
    306                                       const MCLDInfo& pLDInfo,
    307                                       X86RelocationFactory& pParent)
    308 {
    309   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
    310   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
    311   X86RelocationFactory::Address S = pReloc.symValue();
    312 
    313   pReloc.target() = S + A - GOT_ORG;
    314   return X86RelocationFactory::OK;
    315 }
    316 
    317 // R_386_GOTPC: GOT_ORG + A - P
    318 X86RelocationFactory::Result gotpc32(Relocation& pReloc,
    319                                      const MCLDInfo& pLDInfo,
    320                                      X86RelocationFactory& pParent)
    321 {
    322   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
    323   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
    324   // Apply relocation.
    325   pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
    326   return X86RelocationFactory::OK;
    327 }
    328 
    329 // R_386_GOT32: GOT(S) + A - GOT_ORG
    330 X86RelocationFactory::Result got32(Relocation& pReloc,
    331                                    const MCLDInfo& pLDInfo,
    332                                    X86RelocationFactory& pParent)
    333 {
    334   if(!(pReloc.symInfo()->reserved()
    335        & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
    336     return X86RelocationFactory::BadReloc;
    337   }
    338   X86RelocationFactory::Address GOT_S   = helper_GOT(pReloc, pLDInfo, pParent);
    339   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
    340   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
    341   // Apply relocation.
    342   pReloc.target() = GOT_S + A - GOT_ORG;
    343   return X86RelocationFactory::OK;
    344 }
    345 
    346 // R_386_PLT32: PLT(S) + A - P
    347 X86RelocationFactory::Result plt32(Relocation& pReloc,
    348                                    const MCLDInfo& pLDInfo,
    349                                    X86RelocationFactory& pParent)
    350 {
    351   // PLT_S depends on if there is a PLT entry.
    352   X86RelocationFactory::Address PLT_S;
    353   if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
    354     PLT_S = helper_PLT(pReloc, pParent);
    355   else
    356     PLT_S = pReloc.symValue();
    357   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
    358   X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
    359   pReloc.target() = PLT_S + A - P;
    360   return X86RelocationFactory::OK;
    361 }
    362