void ARMGNULDBackend::createARMGOT(MCLinker& pLinker, const Output& pOutput) { // get .got LDSection and create MCSectionData ELFFileFormat* file_format = getOutputFormat(pOutput); LDSection& got = file_format->getGOT(); m_pGOT = new ARMGOT(got, pLinker.getOrCreateSectData(got)); // define symbol _GLOBAL_OFFSET_TABLE_ when .got create if( m_pGOTSymbol != NULL ) { pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>( "_GLOBAL_OFFSET_TABLE_", false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, // size 0x0, // value pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0), ResolveInfo::Hidden); } else { m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>( "_GLOBAL_OFFSET_TABLE_", false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, // size 0x0, // value pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0), ResolveInfo::Hidden); } }
bool ARMGNULDBackend::initRelocFactory(const MCLinker& pLinker) { if (NULL == m_pRelocFactory) { m_pRelocFactory = new ARMRelocationFactory(1024, *this); m_pRelocFactory->setLayout(pLinker.getLayout()); } return true; }
/// allocateCommonSymbols - allocate common symbols in the corresponding /// sections. /// @refer Google gold linker: common.cc: 214 bool ARMGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const { SymbolCategory& symbol_list = pLinker.getOutputSymbols(); if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) return true; // addralign := max value of all common symbols uint64_t addralign = 0x0; // Due to the visibility, some common symbols may be forcefully local. SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd(); for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) { if (ResolveInfo::Common == (*com_sym)->desc()) { if ((*com_sym)->value() > addralign) addralign = (*com_sym)->value(); } } // global common symbols. com_end = symbol_list.commonEnd(); for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) { if ((*com_sym)->value() > addralign) addralign = (*com_sym)->value(); } // FIXME: If the order of common symbols is defined, then sort common symbols // com_sym = symbol_list.commonBegin(); // std::sort(com_sym, com_end, some kind of order); // get or create corresponding BSS LDSection LDSection* bss_sect_hdr = NULL; if (ResolveInfo::ThreadLocal == (*com_sym)->type()) { bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr( ".tbss", LDFileFormat::BSS, llvm::ELF::SHT_NOBITS, llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC); } else { bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss", LDFileFormat::BSS, llvm::ELF::SHT_NOBITS, llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC); } // get or create corresponding BSS MCSectionData assert(NULL != bss_sect_hdr); llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr); // allocate all common symbols uint64_t offset = bss_sect_hdr->size(); // allocate all local common symbols com_end = symbol_list.localEnd(); for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) { if (ResolveInfo::Common == (*com_sym)->desc()) { // We have to reset the description of the symbol here. When doing // incremental linking, the output relocatable object may have common // symbols. Therefore, we can not treat common symbols as normal symbols // when emitting the regular name pools. We must change the symbols' // description here. (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define); llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size()); (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0)); uint64_t size = pLinker.getLayout().appendFragment(*frag, bss_section, (*com_sym)->value()); offset += size; } } // allocate all global common symbols com_end = symbol_list.commonEnd(); for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) { // We have to reset the description of the symbol here. When doing // incremental linking, the output relocatable object may have common // symbols. Therefore, we can not treat common symbols as normal symbols // when emitting the regular name pools. We must change the symbols' // description here. (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define); llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size()); (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0)); uint64_t size = pLinker.getLayout().appendFragment(*frag, bss_section, (*com_sym)->value()); offset += size; } bss_sect_hdr->setSize(offset); symbol_list.changeCommonsToGlobal(); return true; }
void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, const LDSymbol& pInputSym, MCLinker& pLinker, const MCLDInfo& pLDInfo, const Output& pOutput) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); updateAddend(pReloc, pInputSym, pLinker.getLayout()); switch(pReloc.type()){ // Set R_ARM_TARGET1 to R_ARM_ABS32 // Ref: GNU gold 1.11 arm.cc, line 9892 case llvm::ELF::R_ARM_TARGET1: pReloc.setType(llvm::ELF::R_ARM_ABS32); case llvm::ELF::R_ARM_ABS32: case llvm::ELF::R_ARM_ABS32_NOI: { // If buiding PIC object (shared library or PIC executable), // a dynamic relocations with RELATIVE type to this location is needed. // Reserve an entry in .rel.dyn if(isPIC(pLDInfo, pOutput)) { // create .rel.dyn section if not exist if(NULL == m_pRelDyn) createARMRelDyn(pLinker, pOutput); m_pRelDyn->reserveEntry(*m_pRelocFactory); // set Rel bit rsym->setReserved(rsym->reserved() | 0x1u); } return; } case llvm::ELF::R_ARM_ABS16: case llvm::ELF::R_ARM_ABS12: case llvm::ELF::R_ARM_THM_ABS5: case llvm::ELF::R_ARM_ABS8: case llvm::ELF::R_ARM_BASE_ABS: case llvm::ELF::R_ARM_MOVW_ABS_NC: case llvm::ELF::R_ARM_MOVT_ABS: case llvm::ELF::R_ARM_THM_MOVW_ABS_NC: case llvm::ELF::R_ARM_THM_MOVT_ABS: { // Update value keep in relocation place if we meet a section symbol if(rsym->type() == ResolveInfo::Section) { pReloc.target() = pLinker.getLayout().getOutputOffset( *pInputSym.fragRef()) + pReloc.target(); } // If building PIC object (shared library or PIC executable), // a dynamic relocation for this location is needed. // Reserve an entry in .rel.dyn if(isPIC(pLDInfo, pOutput)) { checkValidReloc(pReloc, pLDInfo, pOutput); // create .rel.dyn section if not exist if(NULL == m_pRelDyn) createARMRelDyn(pLinker, pOutput); m_pRelDyn->reserveEntry(*m_pRelocFactory); // set Rel bit rsym->setReserved(rsym->reserved() | 0x1u); } return; } case llvm::ELF::R_ARM_GOTOFF32: case llvm::ELF::R_ARM_GOTOFF12: { // A GOT section is needed if(NULL == m_pGOT) createARMGOT(pLinker, pOutput); return; } // Set R_ARM_TARGET2 to R_ARM_GOT_PREL // Ref: GNU gold 1.11 arm.cc, line 9892 case llvm::ELF::R_ARM_TARGET2: pReloc.setType(llvm::ELF::R_ARM_GOT_PREL); case llvm::ELF::R_ARM_GOT_BREL: case llvm::ELF::R_ARM_GOT_PREL: { // A GOT entry is needed for these relocation type. // return if we already create GOT for this symbol if(rsym->reserved() & 0x6u) return; if(NULL == m_pGOT) createARMGOT(pLinker, pOutput); m_pGOT->reserveEntry(); // If building PIC object, a dynamic relocation with // type RELATIVE is needed to relocate this GOT entry. // Reserve an entry in .rel.dyn if(isPIC(pLDInfo, pOutput)) { // create .rel.dyn section if not exist if(NULL == m_pRelDyn) createARMRelDyn(pLinker, pOutput); m_pRelDyn->reserveEntry(*m_pRelocFactory); // set GOTRel bit rsym->setReserved(rsym->reserved() | 0x4u); return; } // set GOT bit rsym->setReserved(rsym->reserved() | 0x2u); return; } case llvm::ELF::R_ARM_BASE_PREL: { // FIXME: Currently we only support R_ARM_BASE_PREL against // symbol _GLOBAL_OFFSET_TABLE_ if(rsym != m_pGOTSymbol->resolveInfo()) { llvm::report_fatal_error(llvm::Twine("Do not support relocation '") + llvm::Twine("R_ARM_BASE_PREL' against symbol '") + llvm::Twine(rsym->name()) + llvm::Twine(".'")); } return; } case llvm::ELF::R_ARM_COPY: case llvm::ELF::R_ARM_GLOB_DAT: case llvm::ELF::R_ARM_JUMP_SLOT: case llvm::ELF::R_ARM_RELATIVE: { // These are relocation type for dynamic linker, shold not // appear in object file. llvm::report_fatal_error(llvm::Twine("unexpected reloc ") + llvm::Twine((int)pReloc.type()) + llvm::Twine(" in object file")); break; } default: { break; } } // end switch }