1551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===- AArch64PLT.cpp -----------------------------------------------------===//
2551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//
3551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//                     The MCLinker Project
4551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//
5551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// This file is distributed under the University of Illinois Open Source
6551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// License. See LICENSE.TXT for details.
7551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//
8551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===//
9551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64GOT.h"
10551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64PLT.h"
11551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64RelocationHelpers.h"
12551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
13551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <new>
14551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
15551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <llvm/Support/Casting.h>
16551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
17551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <mcld/LD/LDSection.h>
18551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <mcld/Support/MsgHandling.h>
19551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
20551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesusing namespace mcld;
21551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
22551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT0::AArch64PLT0(SectionData& pParent)
23551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {}
24551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
25551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT1::AArch64PLT1(SectionData& pParent)
26551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {}
27551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
28551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===//
29551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// AArch64PLT
30551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
31551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT &pGOTPLT)
32551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  : PLT(pSection), m_GOT(pGOTPLT) {
33551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  new AArch64PLT0(*m_pSectionData);
34551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
35551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
36551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT::~AArch64PLT()
37551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
38551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
39551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
40551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesbool AArch64PLT::hasPLT1() const
41551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
42551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return (m_pSectionData->size() > 1);
43551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
44551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
45551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::finalizeSectionSize()
46551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
47551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
48551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines                  sizeof(aarch64_plt0);
49551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  m_Section.setSize(size);
50551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
51551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t offset = 0;
52551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  SectionData::iterator frag, fragEnd = m_pSectionData->end();
53551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
54551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    frag->setOffset(offset);
55551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    offset += frag->size();
56551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  }
57551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
58551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
59551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT1* AArch64PLT::create()
60551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
61551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
62551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  if (!plt1_entry)
63551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    fatal(diag::fail_allocate_memory_plt);
64551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return plt1_entry;
65551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
66551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::applyPLT0()
68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
69551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // malloc plt0
70551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  iterator first = m_pSectionData->getFragmentList().begin();
71551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(first != m_pSectionData->getFragmentList().end() &&
72551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines         "FragmentList is empty, applyPLT0 failed!");
73551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
74551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t* data = NULL;
75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
76551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  if (data == NULL)
77551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    fatal(diag::fail_allocate_memory_plt);
78551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
79551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
80551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // apply plt0
81551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t plt_base = m_Section.addr();
82551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(plt_base && ".plt base address is NULL!");
83551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t got_base = m_GOT.addr();
84551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(got_base && ".got base address is NULL!");
85551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
86551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // apply 2nd instruction
87551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // get the address of got entry 2
88551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
89551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // compute the immediate
90551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64Relocator::DWord imm = helper_get_page_address(got_ent2_base) -
91551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines       helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
92551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
93551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // apply 3rd instruction
94551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  data[2] = helper_reencode_add_imm(data[2],
95551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines                                    helper_get_page_offset(got_ent2_base) >> 3);
96551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // apply 4th instruction
97551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  data[3] = helper_reencode_add_imm(data[3],
98551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines                                    helper_get_page_offset(got_ent2_base));
99551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  plt0->setValue(reinterpret_cast<unsigned char*>(data));
100551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
101551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
102551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::applyPLT1()
103551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
104551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t plt_base = m_Section.addr();
105551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(plt_base && ".plt base address is NULL!");
106551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
107551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t got_base = m_GOT.addr();
108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(got_base && ".got base address is NULL!");
109551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
110551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT::iterator it = m_pSectionData->begin();
111551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT::iterator ie = m_pSectionData->end();
112551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
113551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
114551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
115551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // first gotplt1 address
116551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
117551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  // first plt1 address
118551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
119551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
120551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  ++it; //skip PLT0
121551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
122551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT1* plt1 = NULL;
123551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
124551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint32_t* Out = NULL;
125551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  while (it != ie) {
126551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    plt1 = &(llvm::cast<AArch64PLT1>(*it));
127551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
128551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
129551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    // apply 1st instruction
130551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
131551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines                                  helper_get_page_address(PLTEntryAddress);
132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
133551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    // apply 2nd instruction
134551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    Out[1] = helper_reencode_add_imm(
135551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines        Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
136551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    // apply 3rd instruction
137551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    Out[2] = helper_reencode_add_imm(
138551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines        Out[2], helper_get_page_offset(GOTEntryAddress));
139551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
140551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    plt1->setValue(reinterpret_cast<unsigned char*>(Out));
141551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    ++it;
142551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
143551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    GOTEntryAddress += GOTEntrySize;
144551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    PLTEntryAddress += PLT1EntrySize;
145551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  }
146551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
147551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  m_GOT.applyGOTPLT(plt_base);
148551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
149551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
150551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesuint64_t AArch64PLT::emit(MemoryRegion& pRegion)
151551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{
152551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  uint64_t result = 0x0;
153551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  iterator it = begin();
154551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
155551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  unsigned char* buffer = pRegion.begin();
156551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  memcpy(buffer, llvm::cast<AArch64PLT0>((*it)).getValue(),
157551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines                                                        AArch64PLT0::EntrySize);
158551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  result += AArch64PLT0::EntrySize;
159551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  ++it;
160551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
161551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT1* plt1 = NULL;
162551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  AArch64PLT::iterator ie = end();
163551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  while (it != ie) {
164551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    plt1 = &(llvm::cast<AArch64PLT1>(*it));
165551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
166551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    result += AArch64PLT1::EntrySize;
167551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    ++it;
168551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  }
169551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return result;
170551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines}
171551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines
172