16f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===- HexagonPLT.cpp -----------------------------------------------------===// 26f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// 36f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// The MCLinker Project 46f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// 56f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// This file is distributed under the University of Illinois Open Source 66f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// License. See LICENSE.TXT for details. 76f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// 86f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===// 96f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines#include "HexagonPLT.h" 10f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include "HexagonRelocationFunctions.h" 116f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 1237b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/LDSection.h" 1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LinkerConfig.h" 1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/MsgHandling.h" 1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines 166f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines#include <llvm/Support/ELF.h> 176f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines#include <llvm/Support/Casting.h> 186f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 1937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace mcld { 206f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 216f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===// 226f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// PLT entry data 236f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===// 24f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen HinesHexagonPLT0::HexagonPLT0(SectionData& pParent) 2537b74a387bb3993387029859c2d9d051c41c724eStephen Hines : PLT::Entry<sizeof(hexagon_plt0)>(pParent) { 266f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 276f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 28f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen HinesHexagonPLT1::HexagonPLT1(SectionData& pParent) 2937b74a387bb3993387029859c2d9d051c41c724eStephen Hines : PLT::Entry<sizeof(hexagon_plt1)>(pParent) { 306f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 316f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 326f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===// 336f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// HexagonPLT 346f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===// 356f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen HinesHexagonPLT::HexagonPLT(LDSection& pSection, 3637b74a387bb3993387029859c2d9d051c41c724eStephen Hines HexagonGOTPLT& pGOTPLT, 3737b74a387bb3993387029859c2d9d051c41c724eStephen Hines const LinkerConfig& pConfig) 38cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines : PLT(pSection), m_GOTPLT(pGOTPLT) { 39cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines assert(LinkerConfig::DynObj == pConfig.codeGenType() || 40cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines LinkerConfig::Exec == pConfig.codeGenType() || 41cfcb22478ca64c308df58f9abe6fa2dedb213c16Stephen Hines LinkerConfig::Binary == pConfig.codeGenType()); 426f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 43f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines m_PLT0 = hexagon_plt0; 4437b74a387bb3993387029859c2d9d051c41c724eStephen Hines m_PLT0Size = sizeof(hexagon_plt0); 45f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // create PLT0 46551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines new HexagonPLT0(*m_pSectionData); 47f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines pSection.setAlign(16); 486f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 496f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 5037b74a387bb3993387029859c2d9d051c41c724eStephen HinesHexagonPLT::~HexagonPLT() { 516f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 526f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 5337b74a387bb3993387029859c2d9d051c41c724eStephen HinesPLTEntryBase* HexagonPLT::getPLT0() const { 54551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines iterator first = m_pSectionData->getFragmentList().begin(); 556f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 56551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(first != m_pSectionData->getFragmentList().end() && 576f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines "FragmentList is empty, getPLT0 failed!"); 586f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 596f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first)); 606f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 616f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines return plt0; 626f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 636f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 6437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid HexagonPLT::finalizeSectionSize() { 656f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines uint64_t size = 0; 666f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines // plt0 size 676f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines size = getPLT0()->size(); 686f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 69f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // get first plt1 entry 70f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines HexagonPLT::iterator it = begin(); 71f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines ++it; 72f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (end() != it) { 73f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // plt1 size 74f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it)); 75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines size += (m_pSectionData->size() - 1) * plt1->size(); 76f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 776f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines m_Section.setSize(size); 786f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 796f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines uint32_t offset = 0; 80551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines SectionData::iterator frag, fragEnd = m_pSectionData->end(); 81551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 826f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines frag->setOffset(offset); 836f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines offset += frag->size(); 846f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } 856f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 866f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 8737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool HexagonPLT::hasPLT1() const { 88551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (m_pSectionData->size() > 1); 89f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 90f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 9137b74a387bb3993387029859c2d9d051c41c724eStephen HinesHexagonPLT1* HexagonPLT::create() { 92551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return new HexagonPLT1(*m_pSectionData); 93f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 94f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 9537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid HexagonPLT::applyPLT0() { 96f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines PLTEntryBase* plt0 = getPLT0(); 97f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t pltBase = m_Section.addr(); 98f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 99f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines unsigned char* data = 0; 100f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines data = static_cast<unsigned char*>(malloc(plt0->size())); 101f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 102f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (!data) 103f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines fatal(diag::fail_allocate_memory_plt); 104f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 105f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines memcpy(data, m_PLT0, plt0->size()); 106f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint32_t gotpltAddr = m_GOTPLT.addr(); 107f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 10837b74a387bb3993387029859c2d9d051c41c724eStephen Hines int32_t* dest = reinterpret_cast<int32_t*>(data); 10937b74a387bb3993387029859c2d9d051c41c724eStephen Hines int32_t result = ((gotpltAddr - pltBase) >> 6); 110f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines *dest |= ApplyMask<int32_t>(0xfff3fff, result); 111f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines dest = dest + 1; 112f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // Already calculated using pltBase 113f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines result = (gotpltAddr - pltBase); 114f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines *(dest) |= ApplyMask<int32_t>(0x1f80, result); 115f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 116f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines plt0->setValue(data); 117f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 118f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 119f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid HexagonPLT::applyPLT1() { 120f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t plt_base = m_Section.addr(); 121f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines assert(plt_base && ".plt base address is NULL!"); 122f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 123f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t got_base = m_GOTPLT.addr(); 124f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines assert(got_base && ".got base address is NULL!"); 125f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 126551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines HexagonPLT::iterator it = m_pSectionData->begin(); 127551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines HexagonPLT::iterator ie = m_pSectionData->end(); 128f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 129f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 130f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint32_t GOTEntrySize = HexagonGOTEntry::EntrySize; 13137b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint32_t GOTEntryAddress = got_base + GOTEntrySize * 4; 132f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 133f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t PLTEntryAddress = 13437b74a387bb3993387029859c2d9d051c41c724eStephen Hines plt_base + HexagonPLT0::EntrySize; // Offset of PLT0 135f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 13637b74a387bb3993387029859c2d9d051c41c724eStephen Hines ++it; // skip PLT0 137f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t PLT1EntrySize = HexagonPLT1::EntrySize; 138f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines HexagonPLT1* plt1 = NULL; 139f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 140f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint32_t* Out = NULL; 141f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines while (it != ie) { 142f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines plt1 = &(llvm::cast<HexagonPLT1>(*it)); 143f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines Out = static_cast<uint32_t*>(malloc(HexagonPLT1::EntrySize)); 144f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 145f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines if (!Out) 146f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines fatal(diag::fail_allocate_memory_plt); 147f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 148f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines memcpy(Out, hexagon_plt1, plt1->size()); 149f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 15037b74a387bb3993387029859c2d9d051c41c724eStephen Hines int32_t* dest = reinterpret_cast<int32_t*>(Out); 15137b74a387bb3993387029859c2d9d051c41c724eStephen Hines int32_t result = ((GOTEntryAddress - PLTEntryAddress) >> 6); 152f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines *dest |= ApplyMask<int32_t>(0xfff3fff, result); 153f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines dest = dest + 1; 154f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines result = (GOTEntryAddress - PLTEntryAddress); 155f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines *(dest) |= ApplyMask<int32_t>(0x1f80, result); 156f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 157f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // Address in the PLT entries point to the corresponding GOT entries 158f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // TODO: Fixup plt to point to the corresponding GOTEntryAddress 159f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines // We need to borrow the same relocation code to fix the relocation 160f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines plt1->setValue(reinterpret_cast<unsigned char*>(Out)); 161f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines ++it; 162f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 163f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines GOTEntryAddress += GOTEntrySize; 164f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines PLTEntryAddress += PLT1EntrySize; 165f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 166f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines} 167f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 16837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint64_t HexagonPLT::emit(MemoryRegion& pRegion) { 169f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines uint64_t result = 0x0; 170f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines iterator it = begin(); 171f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 17287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines unsigned char* buffer = pRegion.begin(); 17337b74a387bb3993387029859c2d9d051c41c724eStephen Hines memcpy(buffer, 17437b74a387bb3993387029859c2d9d051c41c724eStephen Hines llvm::cast<HexagonPLT0>((*it)).getValue(), 17537b74a387bb3993387029859c2d9d051c41c724eStephen Hines HexagonPLT0::EntrySize); 176f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines result += HexagonPLT0::EntrySize; 177f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines ++it; 178f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines 179f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines HexagonPLT1* plt1 = 0; 180f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines HexagonPLT::iterator ie = end(); 181f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines while (it != ie) { 182f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines plt1 = &(llvm::cast<HexagonPLT1>(*it)); 183f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines memcpy(buffer + result, plt1->getValue(), HexagonPLT1::EntrySize); 184f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines result += HexagonPLT1::EntrySize; 185f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines ++it; 186f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 187f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines return result; 1886f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 1896f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 19037b74a387bb3993387029859c2d9d051c41c724eStephen Hines} // namespace mcld 191