• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- AArch64PLT.cpp -----------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "AArch64GOT.h"
10 #include "AArch64PLT.h"
11 #include "AArch64RelocationHelpers.h"
12 
13 #include <new>
14 
15 #include <llvm/Support/Casting.h>
16 
17 #include <mcld/LD/LDSection.h>
18 #include <mcld/Support/MsgHandling.h>
19 
20 using namespace mcld;
21 
AArch64PLT0(SectionData & pParent)22 AArch64PLT0::AArch64PLT0(SectionData& pParent)
23   : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {}
24 
AArch64PLT1(SectionData & pParent)25 AArch64PLT1::AArch64PLT1(SectionData& pParent)
26   : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {}
27 
28 //===----------------------------------------------------------------------===//
29 // AArch64PLT
30 
AArch64PLT(LDSection & pSection,AArch64GOT & pGOTPLT)31 AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT &pGOTPLT)
32   : PLT(pSection), m_GOT(pGOTPLT) {
33   new AArch64PLT0(*m_pSectionData);
34 }
35 
~AArch64PLT()36 AArch64PLT::~AArch64PLT()
37 {
38 }
39 
hasPLT1() const40 bool AArch64PLT::hasPLT1() const
41 {
42   return (m_pSectionData->size() > 1);
43 }
44 
finalizeSectionSize()45 void AArch64PLT::finalizeSectionSize()
46 {
47   uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
48                   sizeof(aarch64_plt0);
49   m_Section.setSize(size);
50 
51   uint32_t offset = 0;
52   SectionData::iterator frag, fragEnd = m_pSectionData->end();
53   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
54     frag->setOffset(offset);
55     offset += frag->size();
56   }
57 }
58 
create()59 AArch64PLT1* AArch64PLT::create()
60 {
61   AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
62   if (!plt1_entry)
63     fatal(diag::fail_allocate_memory_plt);
64   return plt1_entry;
65 }
66 
applyPLT0()67 void AArch64PLT::applyPLT0()
68 {
69   // malloc plt0
70   iterator first = m_pSectionData->getFragmentList().begin();
71   assert(first != m_pSectionData->getFragmentList().end() &&
72          "FragmentList is empty, applyPLT0 failed!");
73   AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
74   uint32_t* data = NULL;
75   data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
76   if (data == NULL)
77     fatal(diag::fail_allocate_memory_plt);
78   memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
79 
80   // apply plt0
81   uint64_t plt_base = m_Section.addr();
82   assert(plt_base && ".plt base address is NULL!");
83   uint64_t got_base = m_GOT.addr();
84   assert(got_base && ".got base address is NULL!");
85 
86   // apply 2nd instruction
87   // get the address of got entry 2
88   uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
89   // compute the immediate
90   AArch64Relocator::DWord imm = helper_get_page_address(got_ent2_base) -
91        helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
92   data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
93   // apply 3rd instruction
94   data[2] = helper_reencode_add_imm(data[2],
95                                     helper_get_page_offset(got_ent2_base) >> 3);
96   // apply 4th instruction
97   data[3] = helper_reencode_add_imm(data[3],
98                                     helper_get_page_offset(got_ent2_base));
99   plt0->setValue(reinterpret_cast<unsigned char*>(data));
100 }
101 
applyPLT1()102 void AArch64PLT::applyPLT1()
103 {
104   uint64_t plt_base = m_Section.addr();
105   assert(plt_base && ".plt base address is NULL!");
106 
107   uint64_t got_base = m_GOT.addr();
108   assert(got_base && ".got base address is NULL!");
109 
110   AArch64PLT::iterator it = m_pSectionData->begin();
111   AArch64PLT::iterator ie = m_pSectionData->end();
112   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
113 
114   uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
115   // first gotplt1 address
116   uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
117   // first plt1 address
118   uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
119 
120   ++it; //skip PLT0
121   uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
122   AArch64PLT1* plt1 = NULL;
123 
124   uint32_t* Out = NULL;
125   while (it != ie) {
126     plt1 = &(llvm::cast<AArch64PLT1>(*it));
127     Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
128     memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
129     // apply 1st instruction
130     AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
131                                   helper_get_page_address(PLTEntryAddress);
132     Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
133     // apply 2nd instruction
134     Out[1] = helper_reencode_add_imm(
135         Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
136     // apply 3rd instruction
137     Out[2] = helper_reencode_add_imm(
138         Out[2], helper_get_page_offset(GOTEntryAddress));
139 
140     plt1->setValue(reinterpret_cast<unsigned char*>(Out));
141     ++it;
142 
143     GOTEntryAddress += GOTEntrySize;
144     PLTEntryAddress += PLT1EntrySize;
145   }
146 
147   m_GOT.applyGOTPLT(plt_base);
148 }
149 
emit(MemoryRegion & pRegion)150 uint64_t AArch64PLT::emit(MemoryRegion& pRegion)
151 {
152   uint64_t result = 0x0;
153   iterator it = begin();
154 
155   unsigned char* buffer = pRegion.begin();
156   memcpy(buffer, llvm::cast<AArch64PLT0>((*it)).getValue(),
157                                                         AArch64PLT0::EntrySize);
158   result += AArch64PLT0::EntrySize;
159   ++it;
160 
161   AArch64PLT1* plt1 = NULL;
162   AArch64PLT::iterator ie = end();
163   while (it != ie) {
164     plt1 = &(llvm::cast<AArch64PLT1>(*it));
165     memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
166     result += AArch64PLT1::EntrySize;
167     ++it;
168   }
169   return result;
170 }
171 
172