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);
6087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
6187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
6237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid MipsPLT::finalizeSectionSize() {
6337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  uint64_t size = sizeof(PLT0) + (m_pSectionData->size() - 1) * sizeof(PLTA);
6487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  m_Section.setSize(size);
6587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
6687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t offset = 0;
67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  SectionData::iterator frag, fragEnd = m_pSectionData->end();
68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
6987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    frag->setOffset(offset);
7087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    offset += frag->size();
7187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
7287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
7387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
7437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool MipsPLT::hasPLT1() const {
75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return m_pSectionData->size() > 1;
7687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
7787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
7837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint64_t MipsPLT::emit(MemoryRegion& pRegion) {
7987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint64_t result = 0x0;
8087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  iterator it = begin();
8187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
8287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  unsigned char* buffer = pRegion.begin();
8387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
8487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  result += MipsPLT0::EntrySize;
8587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ++it;
8687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
8787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  MipsPLTA* plta = 0;
8887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  for (iterator ie = end(); it != ie; ++it) {
8987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    plta = &(llvm::cast<MipsPLTA>(*it));
9087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
9187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    result += MipsPLTA::EntrySize;
9287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
9387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return result;
9487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
9587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
96b0d0eb206527b43c771933602e147bbd7b471082Stephen HinesPLTEntryBase* MipsPLT::create() {
97b0d0eb206527b43c771933602e147bbd7b471082Stephen Hines  return new MipsPLTA(*m_pSectionData);
9887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
9987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
10037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT) {
10187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  assert(m_Section.addr() && ".plt base address is NULL!");
10287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
10387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  size_t count = 0;
10437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end();
10537b74a387bb3993387029859c2d9d051c41c724eStephen Hines       ++it) {
10687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
10787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    if (it == m_pSectionData->begin()) {
10987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
11087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (!data)
11287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        fatal(diag::fail_allocate_memory_plt);
11387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      memcpy(data, PLT0, plt->size());
11587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      uint64_t gotAddr = pGOTPLT.addr();
11787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
11987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[1] |= gotAddr & 0xffff;
12087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[2] |= gotAddr & 0xffff;
12187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
12287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      plt->setValue(reinterpret_cast<unsigned char*>(data));
12387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    } else {
12487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
12587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
12687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (!data)
12787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        fatal(diag::fail_allocate_memory_plt);
12887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
12987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      memcpy(data, PLTA, plt->size());
13087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
13187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
13287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
13387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
13487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[1] |= gotEntryAddr & 0xffff;
13587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      data[3] |= gotEntryAddr & 0xffff;
13687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
13787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      plt->setValue(reinterpret_cast<unsigned char*>(data));
13887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    }
13987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
14087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
14187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
14237b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace mcld
143