MipsPLT.cpp revision 37b74a387bb3993387029859c2d9d051c41c724e
187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===- MipsPLT.cpp --------------------------------------------------------===// 287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// 387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// The MCLinker Project 487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// 587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// This file is distributed under the University of Illinois Open Source 687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// License. See LICENSE.TXT for details. 787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// 887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines#include <llvm/Support/Casting.h> 1087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines#include <llvm/Support/ELF.h> 1137b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/MsgHandling.h" 1287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines#include "MipsGOTPLT.h" 1387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines#include "MipsPLT.h" 1487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 1587f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesnamespace { 1687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 1787f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesconst uint32_t PLT0[] = { 1837b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x3c1c0000, // lui $28, %hi(&GOTPLT[0]) 1937b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x8f990000, // lw $25, %lo(&GOTPLT[0])($28) 2037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x279c0000, // addiu $28, $28, %lo(&GOTPLT[0]) 2137b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x031cc023, // subu $24, $24, $28 2237b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x03e07821, // move $15, $31 2337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x0018c082, // srl $24, $24, 2 2437b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x0320f809, // jalr $25 2537b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x2718fffe // subu $24, $24, 2 2687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 2787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 2887f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesconst uint32_t PLTA[] = { 2937b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x3c0f0000, // lui $15, %hi(.got.plt entry) 3037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x8df90000, // l[wd] $25, %lo(.got.plt entry)($15) 3137b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x03200008, // jr $25 3237b74a387bb3993387029859c2d9d051c41c724eStephen Hines 0x25f80000 // addiu $24, $15, %lo(.got.plt entry) 3387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 3487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3537b74a387bb3993387029859c2d9d051c41c724eStephen Hines} // anonymous namespace 3687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3787f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesnamespace mcld { 3887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 4087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLT0 Entry 4187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 4237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesclass MipsPLT0 : public PLT::Entry<sizeof(PLT0)> { 4337b74a387bb3993387029859c2d9d051c41c724eStephen Hines public: 4437b74a387bb3993387029859c2d9d051c41c724eStephen Hines MipsPLT0(SectionData& pParent) : PLT::Entry<sizeof(PLT0)>(pParent) {} 4587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 4687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 4787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 4887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLTA Entry 4987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 5037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesclass MipsPLTA : public PLT::Entry<sizeof(PLTA)> { 5137b74a387bb3993387029859c2d9d051c41c724eStephen Hines public: 5237b74a387bb3993387029859c2d9d051c41c724eStephen Hines MipsPLTA(SectionData& pParent) : PLT::Entry<sizeof(PLTA)>(pParent) {} 5387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 5487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 5587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 5687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLT 5787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 5837b74a387bb3993387029859c2d9d051c41c724eStephen HinesMipsPLT::MipsPLT(LDSection& pSection) : PLT(pSection) { 59551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines new MipsPLT0(*m_pSectionData); 60551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_Last = m_pSectionData->begin(); 6187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 6287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 6337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid MipsPLT::finalizeSectionSize() { 6437b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA); 6587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines m_Section.setSize(size); 6687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 6787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t offset = 0; 68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines SectionData::iterator frag, fragEnd = m_pSectionData->end(); 69551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 7087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines frag->setOffset(offset); 7187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines offset += frag->size(); 7287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 7387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 7487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 7537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool MipsPLT::hasPLT1() const { 76551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return m_pSectionData->size() > 1; 7787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 7887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 7937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint64_t MipsPLT::emit(MemoryRegion& pRegion) { 8087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t result = 0x0; 8187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines iterator it = begin(); 8287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 8387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines unsigned char* buffer = pRegion.begin(); 8487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize); 8587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines result += MipsPLT0::EntrySize; 8687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines ++it; 8787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 8887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines MipsPLTA* plta = 0; 8987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines for (iterator ie = end(); it != ie; ++it) { 9087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plta = &(llvm::cast<MipsPLTA>(*it)); 9187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize); 9287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines result += MipsPLTA::EntrySize; 9387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 9487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines return result; 9587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 9687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 9737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid MipsPLT::reserveEntry(size_t pNum) { 9887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines for (size_t i = 0; i < pNum; ++i) { 99551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData); 10087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 10137b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (entry == NULL) 10287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 10387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 10487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 10587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 10637b74a387bb3993387029859c2d9d051c41c724eStephen HinesFragment* MipsPLT::consume() { 10787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines ++m_Last; 108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(m_Last != m_pSectionData->end() && 10987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines "The number of PLT Entries and ResolveInfo doesn't match"); 11087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines return &(*m_Last); 11187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 11287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 11337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) { 11487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines assert(m_Section.addr() && ".plt base address is NULL!"); 11587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 11687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines size_t count = 0; 11737b74a387bb3993387029859c2d9d051c41c724eStephen Hines for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); 11837b74a387bb3993387029859c2d9d051c41c724eStephen Hines ++it) { 11987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it)); 12087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 121551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (it == m_pSectionData->begin()) { 12287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 12387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 12487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (!data) 12587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 12687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 12787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(data, PLT0, plt->size()); 12887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 12987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t gotAddr = pGOTPLT.addr(); 13087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 13187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff; 13287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[1] |= gotAddr & 0xffff; 13387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[2] |= gotAddr & 0xffff; 13487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 13587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plt->setValue(reinterpret_cast<unsigned char*>(data)); 13687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } else { 13787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 13887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 13987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (!data) 14087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 14187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(data, PLTA, plt->size()); 14387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++); 14587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff; 14787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[1] |= gotEntryAddr & 0xffff; 14887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[3] |= gotEntryAddr & 0xffff; 14987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 15087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plt->setValue(reinterpret_cast<unsigned char*>(data)); 15187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 15287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 15387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 15487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 15537b74a387bb3993387029859c2d9d051c41c724eStephen Hines} // namespace mcld 156