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