void GarbageCollection::setUpReachedSections() { // traverse all the input relocations to setup the reached sections Module::obj_iterator input, inEnd = m_Module.obj_end(); for (input = m_Module.obj_begin(); input != inEnd; ++input) { LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { // bypass the discarded relocation section // 1. its section kind is changed to Ignore. (The target section is a // discarded group section.) // 2. it has no reloc data. (All symbols in the input relocs are in the // discarded group sections) LDSection* reloc_sect = *rs; LDSection* apply_sect = reloc_sect->getLink(); if ((LDFileFormat::Ignore == reloc_sect->kind()) || (!reloc_sect->hasRelocData())) continue; // bypass the apply target sections which are not handled by gc (currently // we only handle the Regular and BSS sections) if (apply_sect->kind() != LDFileFormat::Regular && apply_sect->kind() != LDFileFormat::BSS) continue; bool add_first = false; SectionListTy* reached_sects = NULL; RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end(); for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd; ++reloc_it) { Relocation* reloc = llvm::cast<Relocation>(reloc_it); ResolveInfo* sym = reloc->symInfo(); // only the target symbols defined in the input fragments can make the // reference if (NULL == sym) continue; if (!sym->isDefine() || !sym->outSymbol()->hasFragRef()) continue; // only the target symbols defined in the concerned sections can make // the reference const LDSection* target_sect = &sym->outSymbol()->fragRef()->frag()->getParent()->getSection(); if (target_sect->kind() != LDFileFormat::Regular && target_sect->kind() != LDFileFormat::BSS) continue; // setup the reached list, if we first add the element to reached list // of this section, create an entry in ReachedSections map if (!add_first) { assert(NULL == reached_sects); reached_sects = &m_ReachedSections[apply_sect]; add_first = true; } reached_sects->insert(target_sect); } reached_sects = NULL; add_first = false; } } }
TEST_F( StaticResolverTest, SetUpBinding) { ResolveInfo* sym = ResolveInfo::Create("abc"); sym->setIsSymbol(true); // ASSERT_FALSE( sym->isSymbol() ); ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setBinding(ResolveInfo::Global); ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( ResolveInfo::Global == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setBinding(ResolveInfo::Weak); ASSERT_TRUE( sym->isSymbol() ); ASSERT_FALSE( sym->isGlobal() ); ASSERT_TRUE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( ResolveInfo::Weak == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setBinding(ResolveInfo::Local); ASSERT_TRUE( sym->isSymbol() ); ASSERT_FALSE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_TRUE( sym->isLocal() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( ResolveInfo::Local == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); }
TEST_F( StaticResolverTest, SetUpDesc) { ResolveInfo* sym = ResolveInfo::Create("abc"); sym->setIsSymbol(true); // ASSERT_FALSE( sym->isSymbol() ); ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setIsSymbol(false); ASSERT_FALSE( sym->isSymbol() ); // ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setDesc(ResolveInfo::Define); ASSERT_FALSE( sym->isSymbol() ); // ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_TRUE( sym->isDefine() ); ASSERT_FALSE( sym->isUndef() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( ResolveInfo::Define == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setDesc(ResolveInfo::Common); ASSERT_FALSE( sym->isSymbol() ); // ASSERT_TRUE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_FALSE( sym->isUndef() ); ASSERT_TRUE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( ResolveInfo::Common == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setDesc(ResolveInfo::Indirect); ASSERT_FALSE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_FALSE( sym->isUndef() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_TRUE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( ResolveInfo::Indirect == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); sym->setDesc(ResolveInfo::Undefined); ASSERT_FALSE( sym->isSymbol() ); ASSERT_TRUE( sym->isGlobal() ); ASSERT_FALSE( sym->isWeak() ); ASSERT_FALSE( sym->isLocal() ); ASSERT_FALSE( sym->isDyn() ); ASSERT_TRUE( sym->isUndef() ); ASSERT_FALSE( sym->isDefine() ); ASSERT_FALSE( sym->isCommon() ); ASSERT_FALSE( sym->isIndirect() ); ASSERT_TRUE( ResolveInfo::NoType == sym->type()); ASSERT_TRUE( 0 == sym->desc() ); ASSERT_TRUE( 0 == sym->binding() ); ASSERT_TRUE( 0 == sym->other() ); }
void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, const LDSymbol& pInputSym, MCLinker& pLinker, const MCLDInfo& pLDInfo, const Output& pOutput) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); 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_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: case llvm::ELF::R_ARM_ABS32_NOI: { // Absolute relocation type, symbol may needs PLT entry or // dynamic relocation entry if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) { // create plt for this symbol if it does not have one if(!(rsym->reserved() & 0x8u)){ // Create .got section if it doesn't exist if(NULL == m_pGOT) createARMGOT(pLinker, pOutput); // create .plt and .rel.plt if not exist if(NULL == m_pPLT) createARMPLTandRelPLT(pLinker, pOutput); // Symbol needs PLT entry, we need to reserve a PLT entry // and the corresponding GOT and dynamic relocation entry // in .got and .rel.plt. (GOT entry will be reserved simultaneously // when calling ARMPLT->reserveEntry()) m_pPLT->reserveEntry(); m_pRelPLT->reserveEntry(*m_pRelocFactory); // set PLT bit rsym->setReserved(rsym->reserved() | 0x8u); } } if(isSymbolNeedsDynRel(*rsym, pOutput, true)) { checkValidReloc(pReloc, pLDInfo, pOutput); // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn // 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; } 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(".'")); } case llvm::ELF::R_ARM_REL32: case llvm::ELF::R_ARM_LDR_PC_G0: case llvm::ELF::R_ARM_SBREL32: case llvm::ELF::R_ARM_THM_PC8: case llvm::ELF::R_ARM_MOVW_PREL_NC: case llvm::ELF::R_ARM_MOVT_PREL: case llvm::ELF::R_ARM_THM_MOVW_PREL_NC: case llvm::ELF::R_ARM_THM_MOVT_PREL: case llvm::ELF::R_ARM_THM_ALU_PREL_11_0: case llvm::ELF::R_ARM_THM_PC12: case llvm::ELF::R_ARM_REL32_NOI: case llvm::ELF::R_ARM_ALU_PC_G0_NC: case llvm::ELF::R_ARM_ALU_PC_G0: case llvm::ELF::R_ARM_ALU_PC_G1_NC: case llvm::ELF::R_ARM_ALU_PC_G1: case llvm::ELF::R_ARM_ALU_PC_G2: case llvm::ELF::R_ARM_LDR_PC_G1: case llvm::ELF::R_ARM_LDR_PC_G2: case llvm::ELF::R_ARM_LDRS_PC_G0: case llvm::ELF::R_ARM_LDRS_PC_G1: case llvm::ELF::R_ARM_LDRS_PC_G2: case llvm::ELF::R_ARM_LDC_PC_G0: case llvm::ELF::R_ARM_LDC_PC_G1: case llvm::ELF::R_ARM_LDC_PC_G2: case llvm::ELF::R_ARM_ALU_SB_G0_NC: case llvm::ELF::R_ARM_ALU_SB_G0: case llvm::ELF::R_ARM_ALU_SB_G1_NC: case llvm::ELF::R_ARM_ALU_SB_G1: case llvm::ELF::R_ARM_ALU_SB_G2: case llvm::ELF::R_ARM_LDR_SB_G0: case llvm::ELF::R_ARM_LDR_SB_G1: case llvm::ELF::R_ARM_LDR_SB_G2: case llvm::ELF::R_ARM_LDRS_SB_G0: case llvm::ELF::R_ARM_LDRS_SB_G1: case llvm::ELF::R_ARM_LDRS_SB_G2: case llvm::ELF::R_ARM_LDC_SB_G0: case llvm::ELF::R_ARM_LDC_SB_G1: case llvm::ELF::R_ARM_LDC_SB_G2: case llvm::ELF::R_ARM_MOVW_BREL_NC: case llvm::ELF::R_ARM_MOVT_BREL: case llvm::ELF::R_ARM_MOVW_BREL: case llvm::ELF::R_ARM_THM_MOVW_BREL_NC: case llvm::ELF::R_ARM_THM_MOVT_BREL: case llvm::ELF::R_ARM_THM_MOVW_BREL: { // Relative addressing relocation, may needs dynamic relocation if(isSymbolNeedsDynRel(*rsym, pOutput, false)) { 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_THM_CALL: case llvm::ELF::R_ARM_PLT32: case llvm::ELF::R_ARM_CALL: case llvm::ELF::R_ARM_JUMP24: case llvm::ELF::R_ARM_THM_JUMP24: case llvm::ELF::R_ARM_SBREL31: case llvm::ELF::R_ARM_PREL31: case llvm::ELF::R_ARM_THM_JUMP19: case llvm::ELF::R_ARM_THM_JUMP6: case llvm::ELF::R_ARM_THM_JUMP11: case llvm::ELF::R_ARM_THM_JUMP8: { // These are branch relocation (except PREL31) // A PLT entry is needed when building shared library // return if we already create plt for this symbol if(rsym->reserved() & 0x8u) return; // if symbol is defined in the ouput file and it's not // preemptible, no need plt if(rsym->isDefine() && !rsym->isDyn() && !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) { return; } // Create .got section if it doesn't exist if(NULL == m_pGOT) createARMGOT(pLinker, pOutput); // create .plt and .rel.plt if not exist if(NULL == m_pPLT) createARMPLTandRelPLT(pLinker, pOutput); // Symbol needs PLT entry, we need to reserve a PLT entry // and the corresponding GOT and dynamic relocation entry // in .got and .rel.plt. (GOT entry will be reserved simultaneously // when calling ARMPLT->reserveEntry()) m_pPLT->reserveEntry(); m_pRelPLT->reserveEntry(*m_pRelocFactory); // set PLT bit rsym->setReserved(rsym->reserved() | 0x8u); 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_ABS: case llvm::ELF::R_ARM_GOT_PREL: { // Symbol needs GOT entry, reserve entry in .got // 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 shared object or the symbol is undefined, a dynamic // relocation is needed to relocate this GOT entry. Reserve an // entry in .rel.dyn if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) { // 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_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 }
void ARMGNULDBackend::setUpReachedSectionsForGC(const Module& pModule, GarbageCollection::SectionReachedListMap& pSectReachedListMap) const { // traverse all the input relocations to find the relocation sections applying // .ARM.exidx sections Module::const_obj_iterator input, inEnd = pModule.obj_end(); for (input = pModule.obj_begin(); input != inEnd; ++input) { LDContext::const_sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { // bypass the discarded relocation section // 1. its section kind is changed to Ignore. (The target section is a // discarded group section.) // 2. it has no reloc data. (All symbols in the input relocs are in the // discarded group sections) LDSection* reloc_sect = *rs; LDSection* apply_sect = reloc_sect->getLink(); if ((LDFileFormat::Ignore == reloc_sect->kind()) || (!reloc_sect->hasRelocData())) continue; if (llvm::ELF::SHT_ARM_EXIDX == apply_sect->type()) { // 1. set up the reference according to relocations bool add_first = false; GarbageCollection::SectionListTy* reached_sects = NULL; RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end(); for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd; ++reloc_it) { Relocation* reloc = llvm::cast<Relocation>(reloc_it); ResolveInfo* sym = reloc->symInfo(); // only the target symbols defined in the input fragments can make the // reference if (NULL == sym) continue; if (!sym->isDefine() || !sym->outSymbol()->hasFragRef()) continue; // only the target symbols defined in the concerned sections can make // the reference const LDSection* target_sect = &sym->outSymbol()->fragRef()->frag()->getParent()->getSection(); if (target_sect->kind() != LDFileFormat::TEXT && target_sect->kind() != LDFileFormat::DATA && target_sect->kind() != LDFileFormat::BSS) continue; // setup the reached list, if we first add the element to reached list // of this section, create an entry in ReachedSections map if (!add_first) { reached_sects = &pSectReachedListMap.getReachedList(*apply_sect); add_first = true; } reached_sects->insert(target_sect); } reached_sects = NULL; add_first = false; // 2. set up the reference from XXX to .ARM.exidx.XXX assert(apply_sect->getLink() != NULL); pSectReachedListMap.addReference(*apply_sect->getLink(), *apply_sect); } } } }