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> 1187f34658dec9097d987d254a990ea7f311bfc95fStephen 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[] = { 1887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x3c1c0000, // lui $28, %hi(&GOTPLT[0]) 1987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x8f990000, // lw $25, %lo(&GOTPLT[0])($28) 2087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x279c0000, // addiu $28, $28, %lo(&GOTPLT[0]) 2187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x031cc023, // subu $24, $24, $28 2287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x03e07821, // move $15, $31 2387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x0018c082, // srl $24, $24, 2 2487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x0320f809, // jalr $25 2587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x2718fffe // subu $24, $24, 2 2687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 2787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 2887f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesconst uint32_t PLTA[] = { 2987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x3c0f0000, // lui $15, %hi(.got.plt entry) 3087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x8df90000, // l[wd] $25, %lo(.got.plt entry)($15) 3187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x03200008, // jr $25 3287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 0x25f80000 // addiu $24, $15, %lo(.got.plt entry) 3387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 3487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 3687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3787f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesnamespace mcld { 3887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 3987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 4087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLT0 Entry 4187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 4287f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesclass MipsPLT0 : public PLT::Entry<sizeof(PLT0)> 4387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 4487f34658dec9097d987d254a990ea7f311bfc95fStephen Hinespublic: 4587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines MipsPLT0(SectionData& pParent) 4687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines : PLT::Entry<sizeof(PLT0)>(pParent) 4787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines {} 4887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 4987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 5087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 5187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLTA Entry 5287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 5387f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesclass MipsPLTA : public PLT::Entry<sizeof(PLTA)> 5487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 5587f34658dec9097d987d254a990ea7f311bfc95fStephen Hinespublic: 5687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines MipsPLTA(SectionData& pParent) 5787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines : PLT::Entry<sizeof(PLTA)>(pParent) 5887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines {} 5987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}; 6087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 6187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 6287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// MipsPLT 6387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//===----------------------------------------------------------------------===// 6487f34658dec9097d987d254a990ea7f311bfc95fStephen HinesMipsPLT::MipsPLT(LDSection& pSection) 6587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines : PLT(pSection) 6687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines new MipsPLT0(*m_pSectionData); 68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_Last = m_pSectionData->begin(); 6987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 7087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 7187f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesvoid MipsPLT::finalizeSectionSize() 7287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 7387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t size = sizeof(PLT0) + 74551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines (m_pSectionData->size() - 1) * sizeof(PLTA); 7587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines m_Section.setSize(size); 7687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 7787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t offset = 0; 78551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines SectionData::iterator frag, fragEnd = m_pSectionData->end(); 79551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 8087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines frag->setOffset(offset); 8187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines offset += frag->size(); 8287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 8387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 8487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 8587f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesbool MipsPLT::hasPLT1() const 8687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 87551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return m_pSectionData->size() > 1; 8887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 8987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 9087f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesuint64_t MipsPLT::emit(MemoryRegion& pRegion) 9187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 9287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t result = 0x0; 9387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines iterator it = begin(); 9487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 9587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines unsigned char* buffer = pRegion.begin(); 9687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize); 9787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines result += MipsPLT0::EntrySize; 9887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines ++it; 9987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 10087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines MipsPLTA* plta = 0; 10187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines for (iterator ie = end(); it != ie; ++it) { 10287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plta = &(llvm::cast<MipsPLTA>(*it)); 10387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize); 10487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines result += MipsPLTA::EntrySize; 10587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 10687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines return result; 10787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 10887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 10987f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesvoid MipsPLT::reserveEntry(size_t pNum) 11087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 11187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines for (size_t i = 0; i < pNum; ++i) { 112551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData); 11387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 11487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (NULL == entry) 11587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 11687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 11787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 11887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 11987f34658dec9097d987d254a990ea7f311bfc95fStephen HinesFragment* MipsPLT::consume() 12087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 12187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines ++m_Last; 122551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(m_Last != m_pSectionData->end() && 12387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines "The number of PLT Entries and ResolveInfo doesn't match"); 12487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines return &(*m_Last); 12587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 12687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 12787f34658dec9097d987d254a990ea7f311bfc95fStephen Hinesvoid MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) 12887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines{ 12987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines assert(m_Section.addr() && ".plt base address is NULL!"); 13087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 13187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines size_t count = 0; 132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); ++it) { 13387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it)); 13487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 135551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (it == m_pSectionData->begin()) { 13687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 13787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 13887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (!data) 13987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 14087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(data, PLT0, plt->size()); 14287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t gotAddr = pGOTPLT.addr(); 14487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff; 14687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[1] |= gotAddr & 0xffff; 14787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[2] |= gotAddr & 0xffff; 14887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 14987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plt->setValue(reinterpret_cast<unsigned char*>(data)); 15087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } else { 15187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint32_t* data = static_cast<uint32_t*>(malloc(plt->size())); 15287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 15387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (!data) 15487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines fatal(diag::fail_allocate_memory_plt); 15587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 15687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines memcpy(data, PLTA, plt->size()); 15787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 15887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++); 15987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 16087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff; 16187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[1] |= gotEntryAddr & 0xffff; 16287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines data[3] |= gotEntryAddr & 0xffff; 16387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 16487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines plt->setValue(reinterpret_cast<unsigned char*>(data)); 16587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 16687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 16787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} 16887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 16987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines} //end mcld namespace 170