• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ARMPLT.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 "ARMGOT.h"
10 #include "ARMPLT.h"
11 
12 #include <new>
13 
14 #include <llvm/Support/Casting.h>
15 
16 #include <mcld/LD/LDSection.h>
17 #include <mcld/Support/MsgHandling.h>
18 
19 using namespace mcld;
20 
ARMPLT0(SectionData & pParent)21 ARMPLT0::ARMPLT0(SectionData& pParent)
22   : PLT::Entry<sizeof(arm_plt0)>(pParent) {}
23 
ARMPLT1(SectionData & pParent)24 ARMPLT1::ARMPLT1(SectionData& pParent)
25   : PLT::Entry<sizeof(arm_plt1)>(pParent) {}
26 
27 //===----------------------------------------------------------------------===//
28 // ARMPLT
29 
ARMPLT(LDSection & pSection,ARMGOT & pGOTPLT)30 ARMPLT::ARMPLT(LDSection& pSection, ARMGOT &pGOTPLT)
31   : PLT(pSection), m_GOT(pGOTPLT) {
32   new ARMPLT0(*m_pSectionData);
33 }
34 
~ARMPLT()35 ARMPLT::~ARMPLT()
36 {
37 }
38 
hasPLT1() const39 bool ARMPLT::hasPLT1() const
40 {
41   return (m_pSectionData->size() > 1);
42 }
43 
finalizeSectionSize()44 void ARMPLT::finalizeSectionSize()
45 {
46   uint64_t size = (m_pSectionData->size() - 1) * sizeof(arm_plt1) +
47                      sizeof(arm_plt0);
48   m_Section.setSize(size);
49 
50   uint32_t offset = 0;
51   SectionData::iterator frag, fragEnd = m_pSectionData->end();
52   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
53     frag->setOffset(offset);
54     offset += frag->size();
55   }
56 }
57 
create()58 ARMPLT1* ARMPLT::create()
59 {
60   ARMPLT1* plt1_entry = new (std::nothrow) ARMPLT1(*m_pSectionData);
61   if (!plt1_entry)
62     fatal(diag::fail_allocate_memory_plt);
63   return plt1_entry;
64 }
65 
applyPLT0()66 void ARMPLT::applyPLT0()
67 {
68   uint64_t plt_base = m_Section.addr();
69   assert(plt_base && ".plt base address is NULL!");
70 
71   uint64_t got_base = m_GOT.addr();
72   assert(got_base && ".got base address is NULL!");
73 
74   uint32_t offset = 0;
75 
76   if (got_base > plt_base)
77     offset = got_base - (plt_base + 16);
78   else
79     offset = (plt_base + 16) - got_base;
80 
81   iterator first = m_pSectionData->getFragmentList().begin();
82 
83   assert(first != m_pSectionData->getFragmentList().end() &&
84          "FragmentList is empty, applyPLT0 failed!");
85 
86   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
87 
88   uint32_t* data = 0;
89   data = static_cast<uint32_t*>(malloc(ARMPLT0::EntrySize));
90 
91   if (!data)
92     fatal(diag::fail_allocate_memory_plt);
93 
94   memcpy(data, arm_plt0, ARMPLT0::EntrySize);
95   data[4] = offset;
96 
97   plt0->setValue(reinterpret_cast<unsigned char*>(data));
98 }
99 
applyPLT1()100 void ARMPLT::applyPLT1()
101 {
102   uint64_t plt_base = m_Section.addr();
103   assert(plt_base && ".plt base address is NULL!");
104 
105   uint64_t got_base = m_GOT.addr();
106   assert(got_base && ".got base address is NULL!");
107 
108   ARMPLT::iterator it = m_pSectionData->begin();
109   ARMPLT::iterator ie = m_pSectionData->end();
110   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
111 
112   uint32_t GOTEntrySize = ARMGOTEntry::EntrySize;
113   uint32_t GOTEntryAddress =
114     got_base +  GOTEntrySize * 3;
115 
116   uint64_t PLTEntryAddress =
117     plt_base + ARMPLT0::EntrySize; //Offset of PLT0
118 
119   ++it; //skip PLT0
120   uint64_t PLT1EntrySize = ARMPLT1::EntrySize;
121   ARMPLT1* plt1 = NULL;
122 
123   uint32_t* Out = NULL;
124   while (it != ie) {
125     plt1 = &(llvm::cast<ARMPLT1>(*it));
126     Out = static_cast<uint32_t*>(malloc(ARMPLT1::EntrySize));
127 
128     if (!Out)
129       fatal(diag::fail_allocate_memory_plt);
130 
131     // Offset is the distance between the last PLT entry and the associated
132     // GOT entry.
133     int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
134 
135     Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
136     Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
137     Out[2] = arm_plt1[2] | (Offset & 0xFFF);
138 
139     plt1->setValue(reinterpret_cast<unsigned char*>(Out));
140     ++it;
141 
142     GOTEntryAddress += GOTEntrySize;
143     PLTEntryAddress += PLT1EntrySize;
144   }
145 
146   m_GOT.applyGOTPLT(plt_base);
147 }
148 
emit(MemoryRegion & pRegion)149 uint64_t ARMPLT::emit(MemoryRegion& pRegion)
150 {
151   uint64_t result = 0x0;
152   iterator it = begin();
153 
154   unsigned char* buffer = pRegion.begin();
155   memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getValue(), ARMPLT0::EntrySize);
156   result += ARMPLT0::EntrySize;
157   ++it;
158 
159   ARMPLT1* plt1 = 0;
160   ARMPLT::iterator ie = end();
161   while (it != ie) {
162     plt1 = &(llvm::cast<ARMPLT1>(*it));
163     memcpy(buffer + result, plt1->getValue(), ARMPLT1::EntrySize);
164     result += ARMPLT1::EntrySize;
165     ++it;
166   }
167   return result;
168 }
169 
170