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