• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //===----------------------------------------------------------------------===//
MipsGNULDBackend(const LinkerConfig & pConfig,MipsGNUInfo * pInfo)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 
~MipsGNULDBackend()47 MipsGNULDBackend::~MipsGNULDBackend()
48 {
49   delete m_pRelocator;
50   delete m_pGOT;
51   delete m_pRelDyn;
52   delete m_pDynamic;
53 }
54 
initTargetSections(Module & pModule,ObjectBuilder & pBuilder)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 
initTargetSymbols(IRBuilder & pBuilder,Module & pModule)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 
initRelocator()99 bool MipsGNULDBackend::initRelocator()
100 {
101   if (NULL == m_pRelocator) {
102     m_pRelocator = new MipsRelocator(*this, config());
103   }
104   return true;
105 }
106 
getRelocator()107 Relocator* MipsGNULDBackend::getRelocator()
108 {
109   assert(NULL != m_pRelocator);
110   return m_pRelocator;
111 }
112 
doPreLayout(IRBuilder & pBuilder)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 
doPostLayout(Module & pModule,IRBuilder & pBuilder)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.
dynamic()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.
dynamic() const156 const MipsELFDynamic& MipsGNULDBackend::dynamic() const
157 {
158   assert(NULL != m_pDynamic);
159   return *m_pDynamic;
160 }
161 
emitSectionData(const LDSection & pSection,MemoryRegion & pRegion) const162 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@googlegroups.com";
178   return 0;
179 }
180 
hasEntryInStrTab(const LDSymbol & pSym) const181 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 
DynsymGOTCompare__anon50749ebb0111::DynsymGOTCompare192     DynsymGOTCompare(const MipsGOT& pGOT)
193       : m_pGOT(pGOT)
194     {
195     }
196 
operator ()__anon50749ebb0111::DynsymGOTCompare197     bool operator()(const LDSymbol* X, const LDSymbol* Y) const
198     {
199       return m_pGOT.dynSymOrderCompare(X, Y);
200     }
201   };
202 }
203 
orderSymbolTable(Module & pModule)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 
getGOT()221 MipsGOT& MipsGNULDBackend::getGOT()
222 {
223   assert(NULL != m_pGOT);
224   return *m_pGOT;
225 }
226 
getGOT() const227 const MipsGOT& MipsGNULDBackend::getGOT() const
228 {
229   assert(NULL != m_pGOT);
230   return *m_pGOT;
231 }
232 
getRelDyn()233 OutputRelocSection& MipsGNULDBackend::getRelDyn()
234 {
235   assert(NULL != m_pRelDyn);
236   return *m_pRelDyn;
237 }
238 
getRelDyn() const239 const OutputRelocSection& MipsGNULDBackend::getRelDyn() const
240 {
241   assert(NULL != m_pRelDyn);
242   return *m_pRelDyn;
243 }
244 
245 unsigned int
getTargetSectionOrder(const LDSection & pSectHdr) const246 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
finalizeTargetSymbols()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
allocateCommonSymbols(Module & pModule)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 
defineGOTSymbol(IRBuilder & pBuilder)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
doCreateProgramHdrs(Module & pModule)399 void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule)
400 {
401   // TODO
402 }
403 
404 //===----------------------------------------------------------------------===//
405 /// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
406 ///
createMipsLDBackend(const llvm::Target & pTarget,const LinkerConfig & pConfig)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 //===----------------------------------------------------------------------===//
MCLDInitializeMipsLDBackend()422 extern "C" void MCLDInitializeMipsLDBackend() {
423   // Register the linker backend
424   mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
425                                                 createMipsLDBackend);
426 }
427 
428