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