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