Relocator::Result relocPCREL(Relocation& pReloc, HexagonRelocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); int64_t result; Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); Relocator::DWord P = pReloc.place(); FragmentRef& target_fragref = pReloc.targetRef(); Fragment* target_frag = target_fragref.frag(); LDSection& target_sect = target_frag->getParent()->getSection(); result = (int64_t)(S + A - P); // for relocs inside non ALLOC, just apply if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) == 0) { return applyRel(pReloc, result); } if (!rsym->isLocal()) { if (rsym->reserved() & HexagonRelocator::ReservePLT) { S = helper_get_PLT_address(*rsym, pParent); result = (int64_t)(S + A - P); applyRel(pReloc, result); return Relocator::OK; } } return applyRel(pReloc, result); }
// 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; }
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) { // perform static relocation RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); pReloc.target() = pReloc.symValue() + 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_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_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_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_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; }
// 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; }
Relocator::Result relocAbs(Relocation& pReloc, HexagonRelocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc); bool has_dyn_rel = (rel_entry != NULL); // if the flag of target section is not ALLOC, we eprform only static // relocation. if (0 == (llvm::ELF::SHF_ALLOC & pReloc.targetRef().frag()->getParent()->getSection().flag())) { return applyAbs(pReloc); } // a local symbol with .rela type relocation if (rsym->isLocal() && has_dyn_rel) { rel_entry->setAddend(S + A); return Relocator::OK; } if (!rsym->isLocal()) { if (rsym->reserved() & HexagonRelocator::ReservePLT) { S = helper_get_PLT_address(*rsym, pParent); } if (has_dyn_rel) { if (llvm::ELF::R_HEX_32 == pReloc.type() && helper_use_relative_reloc(*rsym, pParent)) { rel_entry->setAddend(S + A); } else { rel_entry->setAddend(A); return Relocator::OK; } } } return applyAbs(pReloc); }
// 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; }
// 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; }
// 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; }