1 //===- HexagonPLT.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 "HexagonPLT.h"
10 #include "HexagonRelocationFunctions.h"
11 
12 #include "mcld/LD/LDSection.h"
13 #include "mcld/LinkerConfig.h"
14 #include "mcld/Support/MsgHandling.h"
15 
16 #include <llvm/Support/ELF.h>
17 #include <llvm/Support/Casting.h>
18 
19 namespace mcld {
20 
21 //===----------------------------------------------------------------------===//
22 // PLT entry data
23 //===----------------------------------------------------------------------===//
HexagonPLT0(SectionData & pParent)24 HexagonPLT0::HexagonPLT0(SectionData& pParent)
25     : PLT::Entry<sizeof(hexagon_plt0)>(pParent) {
26 }
27 
HexagonPLT1(SectionData & pParent)28 HexagonPLT1::HexagonPLT1(SectionData& pParent)
29     : PLT::Entry<sizeof(hexagon_plt1)>(pParent) {
30 }
31 
32 //===----------------------------------------------------------------------===//
33 // HexagonPLT
34 //===----------------------------------------------------------------------===//
HexagonPLT(LDSection & pSection,HexagonGOTPLT & pGOTPLT,const LinkerConfig & pConfig)35 HexagonPLT::HexagonPLT(LDSection& pSection,
36                        HexagonGOTPLT& pGOTPLT,
37                        const LinkerConfig& pConfig)
38     : PLT(pSection), m_GOTPLT(pGOTPLT) {
39   assert(LinkerConfig::DynObj == pConfig.codeGenType() ||
40          LinkerConfig::Exec == pConfig.codeGenType() ||
41          LinkerConfig::Binary == pConfig.codeGenType());
42 
43   m_PLT0 = hexagon_plt0;
44   m_PLT0Size = sizeof(hexagon_plt0);
45   // create PLT0
46   new HexagonPLT0(*m_pSectionData);
47   pSection.setAlign(16);
48 }
49 
~HexagonPLT()50 HexagonPLT::~HexagonPLT() {
51 }
52 
getPLT0() const53 PLTEntryBase* HexagonPLT::getPLT0() const {
54   iterator first = m_pSectionData->getFragmentList().begin();
55 
56   assert(first != m_pSectionData->getFragmentList().end() &&
57          "FragmentList is empty, getPLT0 failed!");
58 
59   PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first));
60 
61   return plt0;
62 }
63 
finalizeSectionSize()64 void HexagonPLT::finalizeSectionSize() {
65   uint64_t size = 0;
66   // plt0 size
67   size = getPLT0()->size();
68 
69   // get first plt1 entry
70   HexagonPLT::iterator it = begin();
71   ++it;
72   if (end() != it) {
73     // plt1 size
74     PLTEntryBase* plt1 = &(llvm::cast<PLTEntryBase>(*it));
75     size += (m_pSectionData->size() - 1) * plt1->size();
76   }
77   m_Section.setSize(size);
78 
79   uint32_t offset = 0;
80   SectionData::iterator frag, fragEnd = m_pSectionData->end();
81   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
82     frag->setOffset(offset);
83     offset += frag->size();
84   }
85 }
86 
hasPLT1() const87 bool HexagonPLT::hasPLT1() const {
88   return (m_pSectionData->size() > 1);
89 }
90 
create()91 HexagonPLT1* HexagonPLT::create() {
92   return new HexagonPLT1(*m_pSectionData);
93 }
94 
applyPLT0()95 void HexagonPLT::applyPLT0() {
96   PLTEntryBase* plt0 = getPLT0();
97   uint64_t pltBase = m_Section.addr();
98 
99   unsigned char* data = 0;
100   data = static_cast<unsigned char*>(malloc(plt0->size()));
101 
102   if (!data)
103     fatal(diag::fail_allocate_memory_plt);
104 
105   memcpy(data, m_PLT0, plt0->size());
106   uint32_t gotpltAddr = m_GOTPLT.addr();
107 
108   int32_t* dest = reinterpret_cast<int32_t*>(data);
109   int32_t result = ((gotpltAddr - pltBase) >> 6);
110   *dest |= ApplyMask<int32_t>(0xfff3fff, result);
111   dest = dest + 1;
112   // Already calculated using pltBase
113   result = (gotpltAddr - pltBase);
114   *(dest) |= ApplyMask<int32_t>(0x1f80, result);
115 
116   plt0->setValue(data);
117 }
118 
applyPLT1()119 void HexagonPLT::applyPLT1() {
120   uint64_t plt_base = m_Section.addr();
121   assert(plt_base && ".plt base address is NULL!");
122 
123   uint64_t got_base = m_GOTPLT.addr();
124   assert(got_base && ".got base address is NULL!");
125 
126   HexagonPLT::iterator it = m_pSectionData->begin();
127   HexagonPLT::iterator ie = m_pSectionData->end();
128   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
129 
130   uint32_t GOTEntrySize = HexagonGOTEntry::EntrySize;
131   uint32_t GOTEntryAddress = got_base + GOTEntrySize * 4;
132 
133   uint64_t PLTEntryAddress =
134       plt_base + HexagonPLT0::EntrySize;  // Offset of PLT0
135 
136   ++it;  // skip PLT0
137   uint64_t PLT1EntrySize = HexagonPLT1::EntrySize;
138   HexagonPLT1* plt1 = NULL;
139 
140   uint32_t* Out = NULL;
141   while (it != ie) {
142     plt1 = &(llvm::cast<HexagonPLT1>(*it));
143     Out = static_cast<uint32_t*>(malloc(HexagonPLT1::EntrySize));
144 
145     if (!Out)
146       fatal(diag::fail_allocate_memory_plt);
147 
148     memcpy(Out, hexagon_plt1, plt1->size());
149 
150     int32_t* dest = reinterpret_cast<int32_t*>(Out);
151     int32_t result = ((GOTEntryAddress - PLTEntryAddress) >> 6);
152     *dest |= ApplyMask<int32_t>(0xfff3fff, result);
153     dest = dest + 1;
154     result = (GOTEntryAddress - PLTEntryAddress);
155     *(dest) |= ApplyMask<int32_t>(0x1f80, result);
156 
157     // Address in the PLT entries point to the corresponding GOT entries
158     // TODO: Fixup plt to point to the corresponding GOTEntryAddress
159     // We need to borrow the same relocation code to fix the relocation
160     plt1->setValue(reinterpret_cast<unsigned char*>(Out));
161     ++it;
162 
163     GOTEntryAddress += GOTEntrySize;
164     PLTEntryAddress += PLT1EntrySize;
165   }
166 }
167 
emit(MemoryRegion & pRegion)168 uint64_t HexagonPLT::emit(MemoryRegion& pRegion) {
169   uint64_t result = 0x0;
170   iterator it = begin();
171 
172   unsigned char* buffer = pRegion.begin();
173   memcpy(buffer,
174          llvm::cast<HexagonPLT0>((*it)).getValue(),
175          HexagonPLT0::EntrySize);
176   result += HexagonPLT0::EntrySize;
177   ++it;
178 
179   HexagonPLT1* plt1 = 0;
180   HexagonPLT::iterator ie = end();
181   while (it != ie) {
182     plt1 = &(llvm::cast<HexagonPLT1>(*it));
183     memcpy(buffer + result, plt1->getValue(), HexagonPLT1::EntrySize);
184     result += HexagonPLT1::EntrySize;
185     ++it;
186   }
187   return result;
188 }
189 
190 }  // namespace mcld
191