// R_386_32: S + A X86RelocationFactory::Result abs32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { ResolveInfo* rsym = pReloc.symInfo(); RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); RelocationFactory::DWord S = pReloc.symValue(); if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) { helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); pReloc.target() = S + A; return X86RelocationFactory::OK; } else if(!rsym->isLocal()) { if(rsym->reserved() & X86GNULDBackend::ReservePLT) { S = helper_PLT(pReloc, pParent); pReloc.target() = S + A; } if(rsym->reserved() & X86GNULDBackend::ReserveRel) { if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) { helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); } else { helper_DynRel(pReloc, pReloc.type(), pParent); return X86RelocationFactory::OK; } } } // perform static relocation pReloc.target() = S + A; return X86RelocationFactory::OK; }
// R_386_PC32: S + A - P X86RelocationFactory::Result rel32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { // perform static relocation RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); pReloc.target() = pReloc.symValue() + A - pReloc.place(pParent.getLayout()); return X86RelocationFactory::OK; }
// R_386_GOTPC: GOT_ORG + A - P X86RelocationFactory::Result gotpc32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); // Apply relocation. pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout()); return X86RelocationFactory::OK; }
// R_386_GOTOFF: S + A - GOT_ORG X86RelocationFactory::Result gotoff32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); X86RelocationFactory::Address S = pReloc.symValue(); pReloc.target() = S + A - GOT_ORG; return X86RelocationFactory::OK; }
// R_386_32: S + A X86RelocationFactory::Result abs32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { ResolveInfo* rsym = pReloc.symInfo(); RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); RelocationFactory::DWord S = pReloc.symValue(); bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel( *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo, pLDInfo.output(), true); const LDSection* target_sect = pParent.getLayout().getOutputLDSection( *(pReloc.targetRef().frag())); assert(NULL != target_sect); // If the flag of target section is not ALLOC, we will not scan this relocation // but perform static relocation. (e.g., applying .debug section) if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) { pReloc.target() = S + A; return X86RelocationFactory::OK; } // A local symbol may need REL Type dynamic relocation if (rsym->isLocal() && has_dyn_rel) { helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); pReloc.target() = S + A; return X86RelocationFactory::OK; } // An external symbol may need PLT and dynamic relocation if (!rsym->isLocal()) { if (rsym->reserved() & X86GNULDBackend::ReservePLT) { S = helper_PLT(pReloc, pParent); pReloc.target() = S + A; } // If we generate a dynamic relocation (except R_386_RELATIVE) // for a place, we should not perform static relocation on it // in order to keep the addend store in the place correct. if (has_dyn_rel) { if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) { helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); } else { helper_DynRel(pReloc, pReloc.type(), pParent); return X86RelocationFactory::OK; } } } // perform static relocation pReloc.target() = S + A; return X86RelocationFactory::OK; }
Relocator::Result lea(Relocation& pReloc, NyuziRelocator& pParent) { Relocator::Address S = pReloc.symValue(); Relocator::Address P = pReloc.place(); int offset = S - (P + 4); if (helper_check_signed_overflow(offset, 13)) return Relocator::Overflow; pReloc.target() = helper_replace_field(pReloc.target(), offset, 10, 13); return Relocator::OK; }
// R_HEX_PLT_B22_PCREL: PLT(S) + A - P Relocator::Result relocPLTB22PCREL(Relocation& pReloc, HexagonRelocator& pParent) { // PLT_S depends on if there is a PLT entry. Relocator::Address PLT_S; if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT)) PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent); else PLT_S = pReloc.symValue(); Relocator::Address P = pReloc.place(); uint32_t bitMask = FINDBITMASK(pReloc.target()); uint32_t result = (PLT_S + pReloc.addend() - P) >> 2; pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; }
// R_HEX_GOTREL_LO16: and its class of relocs // (S + A - GOT) : Signed Truncate Relocator::Result relocGOTREL(Relocation& pReloc, HexagonRelocator& pParent) { Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr(); uint32_t bitMask = 0; uint32_t alignment = 1; uint32_t shift = 0; uint32_t result = (uint32_t)(S + A - GOT); switch (pReloc.type()) { case llvm::ELF::R_HEX_GOTREL_LO16: bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_GOTREL_HI16: bitMask = 0x00c03fff; shift = 16; alignment = 4; break; case llvm::ELF::R_HEX_GOTREL_32: bitMask = 0xffffffff; break; case llvm::ELF::R_HEX_GOTREL_32_6_X: bitMask = 0x0fff3fff; shift = 6; break; case llvm::ELF::R_HEX_GOTREL_16_X: case llvm::ELF::R_HEX_GOTREL_11_X: bitMask = FINDBITMASK(pReloc.target()); break; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if (result % alignment != 0) return Relocator::BadReloc; result >>= shift; pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; }
// R_386_PLT32: PLT(S) + A - P X86RelocationFactory::Result plt32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { // PLT_S depends on if there is a PLT entry. X86RelocationFactory::Address PLT_S; if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT)) PLT_S = helper_PLT(pReloc, pParent); else PLT_S = pReloc.symValue(); RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); X86RelocationFactory::Address P = pReloc.place(pParent.getLayout()); pReloc.target() = PLT_S + A - P; return X86RelocationFactory::OK; }
// R_386_GOT32: GOT(S) + A - GOT_ORG X86RelocationFactory::Result got32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { if(!(pReloc.symInfo()->reserved() & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) { return X86RelocationFactory::BadReloc; } X86RelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent); RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); // Apply relocation. pReloc.target() = GOT_S + A - GOT_ORG; return X86RelocationFactory::OK; }
// R_HEX_GPREL16_0 and its class : Unsigned Verify Relocator::Result relocGPREL(Relocation& pReloc, HexagonRelocator& pParent) { Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); Relocator::DWord GP = pParent.getTarget().getGP(); uint32_t result = (uint32_t)(S + A - GP); uint32_t shift = 0; uint32_t alignment = 1; switch (pReloc.type()) { case llvm::ELF::R_HEX_GPREL16_0: break; case llvm::ELF::R_HEX_GPREL16_1: shift = 1; alignment = 2; break; case llvm::ELF::R_HEX_GPREL16_2: shift = 2; alignment = 4; break; case llvm::ELF::R_HEX_GPREL16_3: shift = 3; alignment = 8; break; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } uint32_t range = 1 << 16; uint32_t bitMask = FINDBITMASK(pReloc.target()); if ((shift != 0) && (result % alignment != 0)) return Relocator::BadReloc; result >>= shift; if (result < range - 1) { pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; } return Relocator::Overflow; }
uint32_t NyuziRelocator::getDebugStringOffset(Relocation& pReloc) const { if (pReloc.type() != llvm::ELF::R_NYUZI_ABS32) error(diag::unsupport_reloc_for_debug_string) << getName(pReloc.type()); return pReloc.symInfo()->outSymbol()->fragRef()->offset() + pReloc.target() + pReloc.addend(); }
Relocator::Result abs(Relocation& pReloc, NyuziRelocator& pParent) { Relocator::DWord A = pReloc.addend(); Relocator::DWord S = pReloc.symValue(); pReloc.target() = S + A; return Relocator::OK; }
// R_386_PC32: S + A - P X86RelocationFactory::Result rel32(Relocation& pReloc, const MCLDInfo& pLDInfo, X86RelocationFactory& pParent) { ResolveInfo* rsym = pReloc.symInfo(); RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); RelocationFactory::DWord S = pReloc.symValue(); RelocationFactory::DWord P = pReloc.place(pParent.getLayout()); const LDSection* target_sect = pParent.getLayout().getOutputLDSection( *(pReloc.targetRef().frag())); assert(NULL != target_sect); // If the flag of target section is not ALLOC, we will not scan this relocation // but perform static relocation. (e.g., applying .debug section) if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) { pReloc.target() = S + A - P; return X86RelocationFactory::OK; } // An external symbol may need PLT and dynamic relocation if (!rsym->isLocal()) { if (rsym->reserved() & X86GNULDBackend::ReservePLT) { S = helper_PLT(pReloc, pParent); pReloc.target() = S + A - P; } if (pParent.getTarget().symbolNeedsDynRel( *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo, pLDInfo.output(), false)) { if (helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) { helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); } else { helper_DynRel(pReloc, pReloc.type(), pParent); return X86RelocationFactory::OK; } } } // perform static relocation pReloc.target() = S + A - P; return X86RelocationFactory::OK; }
void AArch64GNULDBackend::scanErrata(Module& pModule, IRBuilder& pBuilder, size_t& num_new_stubs, size_t& stubs_strlen) { // TODO: Implement AArch64 ErrataStubFactory to create the specific erratum // stub and simplify the logics. for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end(); sect != sectEnd; ++sect) { if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) { SectionData* sd = (*sect)->getSectionData(); for (SectionData::iterator it = sd->begin(), ie = sd->end(); it != ie; ++it) { Fragment* frag = llvm::dyn_cast<RegionFragment>(it); if (frag != NULL) { FragmentRef* frag_ref = FragmentRef::Create(*frag, 0); for (unsigned offset = 0; offset < frag->size(); offset += AArch64InsnHelpers::InsnSize) { Stub* stub = getStubFactory()->create(*frag_ref, pBuilder, *getBRIslandFactory()); if (stub != NULL) { // A stub symbol should be local assert(stub->symInfo() != NULL && stub->symInfo()->isLocal()); const AArch64CA53ErratumStub* erratum_stub = reinterpret_cast<const AArch64CA53ErratumStub*>(stub); assert(erratum_stub != NULL); // Rewrite the erratum instruction as a branch to the stub. uint64_t offset = frag_ref->offset() + erratum_stub->getErratumInsnOffset(); Relocation* reloc = Relocation::Create(llvm::ELF::R_AARCH64_JUMP26, *(FragmentRef::Create(*frag, offset)), /* pAddend */0); reloc->setSymInfo(stub->symInfo()); reloc->target() = AArch64InsnHelpers::buildBranchInsn(); addExtraRelocation(reloc); ++num_new_stubs; stubs_strlen += stub->symInfo()->nameSize() + 1; } frag_ref->assign(*frag, offset + AArch64InsnHelpers::InsnSize); } // for each INSN } } // for each FRAGMENT } } // for each TEXT section }
void Relocator::partialScanRelocation(Relocation& pReloc, Module& pModule, const LDSection& pSection) { // if we meet a section symbol if (pReloc.symInfo()->type() == ResolveInfo::Section) { LDSymbol* input_sym = pReloc.symInfo()->outSymbol(); // 1. update the relocation target offset assert(input_sym->hasFragRef()); uint64_t offset = input_sym->fragRef()->getOutputOffset(); pReloc.target() += offset; // 2. get output section symbol // get the output LDSection which the symbol defined in const LDSection& out_sect = input_sym->fragRef()->frag()->getParent()->getSection(); ResolveInfo* sym_info = pModule.getSectionSymbolSet().get(out_sect)->resolveInfo(); // set relocation target symbol to the output section symbol's resolveInfo pReloc.setSymInfo(sym_info); } }
void NyuziRelocator::applyDebugStringOffset(Relocation& pReloc, uint32_t pOffset) { pReloc.target() = pOffset; }
// R_HEX_32 and its class of relocations use only addend and symbol value // S + A : result is unsigned truncate. // Exception: R_HEX_32_6_X : unsigned verify Relocator::Result applyAbs(Relocation& pReloc) { Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); uint32_t result = (uint32_t)(S + A); uint32_t bitMask = 0; uint32_t effectiveBits = 0; uint32_t alignment = 1; uint32_t shift = 0; switch (pReloc.type()) { case llvm::ELF::R_HEX_LO16: bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_HI16: shift = 16; bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_32: bitMask = 0xffffffff; break; case llvm::ELF::R_HEX_16: bitMask = 0x0000ffff; alignment = 2; break; case llvm::ELF::R_HEX_8: bitMask = 0x000000ff; alignment = 1; break; case llvm::ELF::R_HEX_12_X: bitMask = 0x000007e0; break; case llvm::ELF::R_HEX_32_6_X: bitMask = 0xfff3fff; shift = 6; effectiveBits = 26; break; case llvm::ELF::R_HEX_16_X: case llvm::ELF::R_HEX_11_X: case llvm::ELF::R_HEX_10_X: case llvm::ELF::R_HEX_9_X: case llvm::ELF::R_HEX_8_X: case llvm::ELF::R_HEX_7_X: case llvm::ELF::R_HEX_6_X: bitMask = FINDBITMASK(pReloc.target()); break; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if ((shift != 0) && (result % alignment != 0)) return Relocator::BadReloc; result >>= shift; if (effectiveBits) { uint32_t range = 1 << effectiveBits; if (result > (range - 1)) return Relocator::Overflow; } pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; }
// R_HEX_B22_PCREL and its class of relocations, use // S + A - P : result is signed verify. // Exception: R_HEX_B32_PCREL_X : signed truncate // Another Exception: R_HEX_6_PCREL_X is unsigned truncate Relocator::Result applyRel(Relocation& pReloc, int64_t pResult) { uint32_t bitMask = 0; uint32_t effectiveBits = 0; uint32_t alignment = 1; uint32_t result; uint32_t shift = 0; switch (pReloc.type()) { case llvm::ELF::R_HEX_B22_PCREL: bitMask = 0x01ff3ffe; effectiveBits = 22; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B15_PCREL: bitMask = 0x00df20fe; effectiveBits = 15; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B7_PCREL: bitMask = 0x00001f18; effectiveBits = 7; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B13_PCREL: bitMask = 0x00202ffe; effectiveBits = 13; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B9_PCREL: bitMask = 0x003000fe; effectiveBits = 9; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B32_PCREL_X: bitMask = 0xfff3fff; shift = 6; break; case llvm::ELF::R_HEX_B22_PCREL_X: bitMask = 0x01ff3ffe; effectiveBits = 22; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B15_PCREL_X: bitMask = 0x00df20fe; effectiveBits = 15; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B13_PCREL_X: bitMask = 0x00202ffe; effectiveBits = 13; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B9_PCREL_X: bitMask = 0x003000fe; effectiveBits = 9; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B7_PCREL_X: bitMask = 0x00001f18; effectiveBits = 7; pResult &= 0x3f; break; case llvm::ELF::R_HEX_32_PCREL: bitMask = 0xffffffff; effectiveBits = 32; break; case llvm::ELF::R_HEX_6_PCREL_X: // This is unique since it has a unsigned operand and its truncated bitMask = FINDBITMASK(pReloc.target()); result = pReloc.addend() + pReloc.symValue() - pReloc.place(); pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if ((shift != 0) && (pResult % alignment != 0)) return Relocator::BadReloc; pResult >>= shift; if (effectiveBits) { int64_t range = 1LL << (effectiveBits - 1); if ((pResult > (range - 1)) || (pResult < -range)) return Relocator::Overflow; } pReloc.target() |= (uint32_t)ApplyMask<int32_t>(bitMask, pResult); return Relocator::OK; }
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 }
// R_HEX_GOT_LO16 and its class : (G) Signed Truncate // Exception: R_HEX_GOT_16(_X): signed verify // Exception: R_HEX_GOT_11_X : unsigned truncate Relocator::Result relocGOT(Relocation& pReloc, HexagonRelocator& pParent) { if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) { return Relocator::BadReloc; } // set got entry value if needed HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo()); assert(got_entry != NULL); if (HexagonRelocator::SymVal == got_entry->getValue()) got_entry->setValue(pReloc.symValue()); Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent); Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr(); int32_t result = (int32_t)(GOT_S - GOT); uint32_t effectiveBits = 0; uint32_t alignment = 1; uint32_t bitMask = 0; uint32_t result_u; uint32_t shift = 0; switch (pReloc.type()) { case llvm::ELF::R_HEX_GOT_LO16: bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_GOT_HI16: bitMask = 0x00c03fff; shift = 16; alignment = 4; break; case llvm::ELF::R_HEX_GOT_32: bitMask = 0xffffffff; break; case llvm::ELF::R_HEX_GOT_16: bitMask = FINDBITMASK(pReloc.target()); effectiveBits = 16; break; case llvm::ELF::R_HEX_GOT_32_6_X: bitMask = 0xfff3fff; shift = 6; break; case llvm::ELF::R_HEX_GOT_16_X: bitMask = FINDBITMASK(pReloc.target()); effectiveBits = 6; break; case llvm::ELF::R_HEX_GOT_11_X: bitMask = FINDBITMASK(pReloc.target()); result_u = GOT_S - GOT; pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u); return Relocator::OK; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if ((shift != 0) && (result % alignment != 0)) return Relocator::BadReloc; result >>= shift; if (effectiveBits) { int32_t range = 1 << (effectiveBits - 1); if ((result > range - 1) || (result < -range)) return Relocator::Overflow; } pReloc.target() |= ApplyMask<int32_t>(bitMask, result); return Relocator::OK; }