Home | History | Annotate | Download | only in Mips
      1 //===- MipsLDBackend.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 #include "Mips.h"
     10 #include "MipsGNUInfo.h"
     11 #include "MipsELFDynamic.h"
     12 #include "MipsLDBackend.h"
     13 #include "MipsRelocator.h"
     14 
     15 #include <llvm/ADT/Triple.h>
     16 #include <llvm/Support/ELF.h>
     17 
     18 #include <mcld/Module.h>
     19 #include <mcld/LinkerConfig.h>
     20 #include <mcld/IRBuilder.h>
     21 #include <mcld/MC/Attribute.h>
     22 #include <mcld/Fragment/FillFragment.h>
     23 #include <mcld/Support/MemoryRegion.h>
     24 #include <mcld/Support/MemoryArea.h>
     25 #include <mcld/Support/MsgHandling.h>
     26 #include <mcld/Support/TargetRegistry.h>
     27 #include <mcld/Target/OutputRelocSection.h>
     28 #include <mcld/Object/ObjectBuilder.h>
     29 
     30 using namespace mcld;
     31 
     32 //===----------------------------------------------------------------------===//
     33 // MipsGNULDBackend
     34 //===----------------------------------------------------------------------===//
     35 MipsGNULDBackend::MipsGNULDBackend(const LinkerConfig& pConfig,
     36                                    MipsGNUInfo* pInfo)
     37   : GNULDBackend(pConfig, pInfo),
     38     m_pRelocator(NULL),
     39     m_pGOT(NULL),
     40     m_pRelDyn(NULL),
     41     m_pDynamic(NULL),
     42     m_pGOTSymbol(NULL),
     43     m_pGpDispSymbol(NULL)
     44 {
     45 }
     46 
     47 MipsGNULDBackend::~MipsGNULDBackend()
     48 {
     49   delete m_pRelocator;
     50   delete m_pGOT;
     51   delete m_pRelDyn;
     52   delete m_pDynamic;
     53 }
     54 
     55 void MipsGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilder)
     56 {
     57   if (LinkerConfig::Object != config().codeGenType()) {
     58     ELFFileFormat* file_format = getOutputFormat();
     59 
     60     // initialize .got
     61     LDSection& got = file_format->getGOT();
     62     m_pGOT = new MipsGOT(got);
     63 
     64     // initialize .rel.dyn
     65     LDSection& reldyn = file_format->getRelDyn();
     66     m_pRelDyn = new OutputRelocSection(pModule, reldyn);
     67   }
     68 }
     69 
     70 void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
     71 {
     72   // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
     73   // same name in input
     74   m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
     75                    "_GLOBAL_OFFSET_TABLE_",
     76                    ResolveInfo::Object,
     77                    ResolveInfo::Define,
     78                    ResolveInfo::Local,
     79                    0x0,  // size
     80                    0x0,  // value
     81                    FragmentRef::Null(), // FragRef
     82                    ResolveInfo::Hidden);
     83 
     84   m_pGpDispSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
     85                    "_gp_disp",
     86                    ResolveInfo::Section,
     87                    ResolveInfo::Define,
     88                    ResolveInfo::Absolute,
     89                    0x0,  // size
     90                    0x0,  // value
     91                    FragmentRef::Null(), // FragRef
     92                    ResolveInfo::Default);
     93 
     94   if (NULL != m_pGpDispSymbol) {
     95     m_pGpDispSymbol->resolveInfo()->setReserved(MipsRelocator::ReserveGpDisp);
     96   }
     97 }
     98 
     99 bool MipsGNULDBackend::initRelocator()
    100 {
    101   if (NULL == m_pRelocator) {
    102     m_pRelocator = new MipsRelocator(*this, config());
    103   }
    104   return true;
    105 }
    106 
    107 Relocator* MipsGNULDBackend::getRelocator()
    108 {
    109   assert(NULL != m_pRelocator);
    110   return m_pRelocator;
    111 }
    112 
    113 void MipsGNULDBackend::doPreLayout(IRBuilder& pBuilder)
    114 {
    115   // initialize .dynamic data
    116   if (!config().isCodeStatic() && NULL == m_pDynamic)
    117     m_pDynamic = new MipsELFDynamic(*this, config());
    118 
    119   // set .got size
    120   // when building shared object, the .got section is must.
    121   if (LinkerConfig::Object != config().codeGenType()) {
    122     if (LinkerConfig::DynObj == config().codeGenType() ||
    123         m_pGOT->hasGOT1() ||
    124         NULL != m_pGOTSymbol) {
    125       m_pGOT->finalizeScanning(*m_pRelDyn);
    126       m_pGOT->finalizeSectionSize();
    127 
    128       defineGOTSymbol(pBuilder);
    129     }
    130 
    131     ELFFileFormat* file_format = getOutputFormat();
    132     // set .rel.dyn size
    133     if (!m_pRelDyn->empty()) {
    134       assert(!config().isCodeStatic() &&
    135             "static linkage should not result in a dynamic relocation section");
    136       file_format->getRelDyn().setSize(
    137                                   m_pRelDyn->numOfRelocs() * getRelEntrySize());
    138     }
    139   }
    140 }
    141 
    142 void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
    143 {
    144 }
    145 
    146 /// dynamic - the dynamic section of the target machine.
    147 /// Use co-variant return type to return its own dynamic section.
    148 MipsELFDynamic& MipsGNULDBackend::dynamic()
    149 {
    150   assert(NULL != m_pDynamic);
    151   return *m_pDynamic;
    152 }
    153 
    154 /// dynamic - the dynamic section of the target machine.
    155 /// Use co-variant return type to return its own dynamic section.
    156 const MipsELFDynamic& MipsGNULDBackend::dynamic() const
    157 {
    158   assert(NULL != m_pDynamic);
    159   return *m_pDynamic;
    160 }
    161 
    162 uint64_t MipsGNULDBackend::emitSectionData(const LDSection& pSection,
    163                                            MemoryRegion& pRegion) const
    164 {
    165   assert(pRegion.size() && "Size of MemoryRegion is zero!");
    166 
    167   const ELFFileFormat* file_format = getOutputFormat();
    168 
    169   if (&pSection == &(file_format->getGOT())) {
    170     assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
    171     uint64_t result = m_pGOT->emit(pRegion);
    172     return result;
    173   }
    174 
    175   fatal(diag::unrecognized_output_sectoin)
    176           << pSection.name()
    177           << "mclinker (at) googlegroups.com";
    178   return 0;
    179 }
    180 
    181 bool MipsGNULDBackend::hasEntryInStrTab(const LDSymbol& pSym) const
    182 {
    183   return ResolveInfo::Section != pSym.type() ||
    184          m_pGpDispSymbol == &pSym;
    185 }
    186 
    187 namespace {
    188   struct DynsymGOTCompare
    189   {
    190     const MipsGOT& m_pGOT;
    191 
    192     DynsymGOTCompare(const MipsGOT& pGOT)
    193       : m_pGOT(pGOT)
    194     {
    195     }
    196 
    197     bool operator()(const LDSymbol* X, const LDSymbol* Y) const
    198     {
    199       return m_pGOT.dynSymOrderCompare(X, Y);
    200     }
    201   };
    202 }
    203 
    204 void MipsGNULDBackend::orderSymbolTable(Module& pModule)
    205 {
    206   if (GeneralOptions::GNU  == config().options().getHashStyle() ||
    207       GeneralOptions::Both == config().options().getHashStyle()) {
    208     // The MIPS ABI and .gnu.hash require .dynsym to be sorted
    209     // in different ways. The MIPS ABI requires a mapping between
    210     // the GOT and the symbol table. At the same time .gnu.hash
    211     // needs symbols to be grouped by hash code.
    212     llvm::errs() << ".gnu.hash is incompatible with the MIPS ABI\n";
    213   }
    214 
    215   Module::SymbolTable& symbols = pModule.getSymbolTable();
    216 
    217   std::stable_sort(symbols.dynamicBegin(), symbols.dynamicEnd(),
    218                    DynsymGOTCompare(*m_pGOT));
    219 }
    220 
    221 MipsGOT& MipsGNULDBackend::getGOT()
    222 {
    223   assert(NULL != m_pGOT);
    224   return *m_pGOT;
    225 }
    226 
    227 const MipsGOT& MipsGNULDBackend::getGOT() const
    228 {
    229   assert(NULL != m_pGOT);
    230   return *m_pGOT;
    231 }
    232 
    233 OutputRelocSection& MipsGNULDBackend::getRelDyn()
    234 {
    235   assert(NULL != m_pRelDyn);
    236   return *m_pRelDyn;
    237 }
    238 
    239 const OutputRelocSection& MipsGNULDBackend::getRelDyn() const
    240 {
    241   assert(NULL != m_pRelDyn);
    242   return *m_pRelDyn;
    243 }
    244 
    245 unsigned int
    246 MipsGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
    247 {
    248   const ELFFileFormat* file_format = getOutputFormat();
    249 
    250   if (&pSectHdr == &file_format->getGOT())
    251     return SHO_DATA;
    252 
    253   return SHO_UNDEFINED;
    254 }
    255 
    256 /// finalizeSymbol - finalize the symbol value
    257 bool MipsGNULDBackend::finalizeTargetSymbols()
    258 {
    259   if (NULL != m_pGpDispSymbol)
    260     m_pGpDispSymbol->setValue(m_pGOT->getGPDispAddress());
    261 
    262   return true;
    263 }
    264 
    265 /// allocateCommonSymbols - allocate common symbols in the corresponding
    266 /// sections. This is called at pre-layout stage.
    267 /// @refer Google gold linker: common.cc: 214
    268 /// FIXME: Mips needs to allocate small common symbol
    269 bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule)
    270 {
    271   SymbolCategory& symbol_list = pModule.getSymbolTable();
    272 
    273   if (symbol_list.emptyCommons() && symbol_list.emptyFiles() &&
    274       symbol_list.emptyLocals() && symbol_list.emptyLocalDyns())
    275     return true;
    276 
    277   SymbolCategory::iterator com_sym, com_end;
    278 
    279   // FIXME: If the order of common symbols is defined, then sort common symbols
    280   // std::sort(com_sym, com_end, some kind of order);
    281 
    282   // get corresponding BSS LDSection
    283   ELFFileFormat* file_format = getOutputFormat();
    284   LDSection& bss_sect = file_format->getBSS();
    285   LDSection& tbss_sect = file_format->getTBSS();
    286 
    287   // get or create corresponding BSS SectionData
    288   SectionData* bss_sect_data = NULL;
    289   if (bss_sect.hasSectionData())
    290     bss_sect_data = bss_sect.getSectionData();
    291   else
    292     bss_sect_data = IRBuilder::CreateSectionData(bss_sect);
    293 
    294   SectionData* tbss_sect_data = NULL;
    295   if (tbss_sect.hasSectionData())
    296     tbss_sect_data = tbss_sect.getSectionData();
    297   else
    298     tbss_sect_data = IRBuilder::CreateSectionData(tbss_sect);
    299 
    300   // remember original BSS size
    301   uint64_t bss_offset  = bss_sect.size();
    302   uint64_t tbss_offset = tbss_sect.size();
    303 
    304   // allocate all local common symbols
    305   com_end = symbol_list.localEnd();
    306 
    307   for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
    308     if (ResolveInfo::Common == (*com_sym)->desc()) {
    309       // We have to reset the description of the symbol here. When doing
    310       // incremental linking, the output relocatable object may have common
    311       // symbols. Therefore, we can not treat common symbols as normal symbols
    312       // when emitting the regular name pools. We must change the symbols'
    313       // description here.
    314       (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
    315       Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
    316       (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
    317 
    318       if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
    319         // allocate TLS common symbol in tbss section
    320         tbss_offset += ObjectBuilder::AppendFragment(*frag,
    321                                                      *tbss_sect_data,
    322                                                      (*com_sym)->value());
    323       }
    324       // FIXME: how to identify small and large common symbols?
    325       else {
    326         bss_offset += ObjectBuilder::AppendFragment(*frag,
    327                                                     *bss_sect_data,
    328                                                     (*com_sym)->value());
    329       }
    330     }
    331   }
    332 
    333   // allocate all global common symbols
    334   com_end = symbol_list.commonEnd();
    335   for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
    336     // We have to reset the description of the symbol here. When doing
    337     // incremental linking, the output relocatable object may have common
    338     // symbols. Therefore, we can not treat common symbols as normal symbols
    339     // when emitting the regular name pools. We must change the symbols'
    340     // description here.
    341     (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
    342     Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
    343     (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
    344 
    345     if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
    346       // allocate TLS common symbol in tbss section
    347       tbss_offset += ObjectBuilder::AppendFragment(*frag,
    348                                                    *tbss_sect_data,
    349                                                    (*com_sym)->value());
    350     }
    351     // FIXME: how to identify small and large common symbols?
    352     else {
    353       bss_offset += ObjectBuilder::AppendFragment(*frag,
    354                                                   *bss_sect_data,
    355                                                   (*com_sym)->value());
    356     }
    357   }
    358 
    359   bss_sect.setSize(bss_offset);
    360   tbss_sect.setSize(tbss_offset);
    361   symbol_list.changeCommonsToGlobal();
    362   return true;
    363 }
    364 
    365 void MipsGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder)
    366 {
    367   // If we do not reserve any GOT entries, we do not need to re-define GOT
    368   // symbol.
    369   if (!m_pGOT->hasGOT1())
    370     return;
    371 
    372   // define symbol _GLOBAL_OFFSET_TABLE_
    373   if ( m_pGOTSymbol != NULL ) {
    374     pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
    375                      "_GLOBAL_OFFSET_TABLE_",
    376                      ResolveInfo::Object,
    377                      ResolveInfo::Define,
    378                      ResolveInfo::Local,
    379                      0x0, // size
    380                      0x0, // value
    381                      FragmentRef::Create(*(m_pGOT->begin()), 0x0),
    382                      ResolveInfo::Hidden);
    383   }
    384   else {
    385     m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
    386                      "_GLOBAL_OFFSET_TABLE_",
    387                      ResolveInfo::Object,
    388                      ResolveInfo::Define,
    389                      ResolveInfo::Local,
    390                      0x0, // size
    391                      0x0, // value
    392                      FragmentRef::Create(*(m_pGOT->begin()), 0x0),
    393                      ResolveInfo::Hidden);
    394   }
    395 }
    396 
    397 /// doCreateProgramHdrs - backend can implement this function to create the
    398 /// target-dependent segments
    399 void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule)
    400 {
    401   // TODO
    402 }
    403 
    404 //===----------------------------------------------------------------------===//
    405 /// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
    406 ///
    407 static TargetLDBackend* createMipsLDBackend(const llvm::Target& pTarget,
    408                                             const LinkerConfig& pConfig)
    409 {
    410   if (pConfig.targets().triple().isOSDarwin()) {
    411     assert(0 && "MachO linker is not supported yet");
    412   }
    413   if (pConfig.targets().triple().isOSWindows()) {
    414     assert(0 && "COFF linker is not supported yet");
    415   }
    416   return new MipsGNULDBackend(pConfig, new MipsGNUInfo(pConfig.targets().triple()));
    417 }
    418 
    419 //===----------------------------------------------------------------------===//
    420 // Force static initialization.
    421 //===----------------------------------------------------------------------===//
    422 extern "C" void MCLDInitializeMipsLDBackend() {
    423   // Register the linker backend
    424   mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
    425                                                 createMipsLDBackend);
    426 }
    427 
    428