1 //===- AArch64LDBackend.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 "AArch64.h"
10 #include "AArch64ELFDynamic.h"
11 #include "AArch64GNUInfo.h"
12 #include "AArch64LDBackend.h"
13 #include "AArch64Relocator.h"
14 
15 #include "mcld/IRBuilder.h"
16 #include "mcld/LinkerConfig.h"
17 #include "mcld/Fragment/AlignFragment.h"
18 #include "mcld/Fragment/FillFragment.h"
19 #include "mcld/Fragment/NullFragment.h"
20 #include "mcld/Fragment/RegionFragment.h"
21 #include "mcld/Fragment/Stub.h"
22 #include "mcld/LD/BranchIslandFactory.h"
23 #include "mcld/LD/ELFFileFormat.h"
24 #include "mcld/LD/ELFSegment.h"
25 #include "mcld/LD/ELFSegmentFactory.h"
26 #include "mcld/LD/LDContext.h"
27 #include "mcld/LD/StubFactory.h"
28 #include "mcld/Support/MemoryRegion.h"
29 #include "mcld/Support/MemoryArea.h"
30 #include "mcld/Support/MsgHandling.h"
31 #include "mcld/Support/TargetRegistry.h"
32 #include "mcld/Target/ELFAttribute.h"
33 #include "mcld/Target/GNUInfo.h"
34 #include "mcld/Object/ObjectBuilder.h"
35 
36 #include <llvm/ADT/Triple.h>
37 #include <llvm/ADT/Twine.h>
38 #include <llvm/Support/Casting.h>
39 #include <llvm/Support/ELF.h>
40 
41 #include <cstring>
42 
43 namespace mcld {
44 
45 //===----------------------------------------------------------------------===//
46 // AArch64GNULDBackend
47 //===----------------------------------------------------------------------===//
AArch64GNULDBackend(const LinkerConfig & pConfig,GNUInfo * pInfo)48 AArch64GNULDBackend::AArch64GNULDBackend(const LinkerConfig& pConfig,
49                                          GNUInfo* pInfo)
50     : GNULDBackend(pConfig, pInfo),
51       m_pRelocator(NULL),
52       m_pGOT(NULL),
53       m_pGOTPLT(NULL),
54       m_pPLT(NULL),
55       m_pRelaDyn(NULL),
56       m_pRelaPLT(NULL),
57       m_pDynamic(NULL),
58       m_pGOTSymbol(NULL) {
59 }
60 
~AArch64GNULDBackend()61 AArch64GNULDBackend::~AArch64GNULDBackend() {
62   if (m_pRelocator != NULL)
63     delete m_pRelocator;
64   if (m_pGOT == m_pGOTPLT) {
65     if (m_pGOT != NULL)
66       delete m_pGOT;
67   } else {
68     if (m_pGOT != NULL)
69       delete m_pGOT;
70     if (m_pGOTPLT != NULL)
71       delete m_pGOTPLT;
72   }
73   if (m_pPLT != NULL)
74     delete m_pPLT;
75   if (m_pRelaDyn != NULL)
76     delete m_pRelaDyn;
77   if (m_pRelaPLT != NULL)
78     delete m_pRelaPLT;
79   if (m_pDynamic != NULL)
80     delete m_pDynamic;
81 }
82 
initTargetSections(Module & pModule,ObjectBuilder & pBuilder)83 void AArch64GNULDBackend::initTargetSections(Module& pModule,
84                                              ObjectBuilder& pBuilder) {
85   if (LinkerConfig::Object != config().codeGenType()) {
86     ELFFileFormat* file_format = getOutputFormat();
87 
88     // initialize .got
89     LDSection& got = file_format->getGOT();
90     m_pGOT = new AArch64GOT(got);
91     if (config().options().hasNow()) {
92       // when -z now is given, there will be only one .got section (contains
93       // both GOTPLT and normal GOT entries), create GOT0 for .got section and
94       // set m_pGOTPLT to the same .got
95       m_pGOT->createGOT0();
96       m_pGOTPLT = m_pGOT;
97     } else {
98       // Otherwise, got should be seperated to two sections, .got and .got.plt
99       // initialize .got.plt
100       LDSection& gotplt = file_format->getGOTPLT();
101       m_pGOTPLT = new AArch64GOT(gotplt);
102       m_pGOTPLT->createGOT0();
103     }
104 
105     // initialize .plt
106     LDSection& plt = file_format->getPLT();
107     m_pPLT = new AArch64PLT(plt, *m_pGOTPLT);
108 
109     // initialize .rela.plt
110     LDSection& relaplt = file_format->getRelaPlt();
111     relaplt.setLink(&plt);
112     m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
113 
114     // initialize .rela.dyn
115     LDSection& reladyn = file_format->getRelaDyn();
116     m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
117   }
118 }
119 
initTargetSymbols(IRBuilder & pBuilder,Module & pModule)120 void AArch64GNULDBackend::initTargetSymbols(IRBuilder& pBuilder,
121                                             Module& pModule) {
122   // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
123   // same name in input
124   if (LinkerConfig::Object != config().codeGenType()) {
125     m_pGOTSymbol =
126         pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
127             "_GLOBAL_OFFSET_TABLE_",
128             ResolveInfo::Object,
129             ResolveInfo::Define,
130             ResolveInfo::Local,
131             0x0,  // size
132             0x0,  // value
133             FragmentRef::Null(),
134             ResolveInfo::Hidden);
135   }
136 }
137 
initRelocator()138 bool AArch64GNULDBackend::initRelocator() {
139   if (m_pRelocator == NULL) {
140     m_pRelocator = new AArch64Relocator(*this, config());
141   }
142   return true;
143 }
144 
getRelocator() const145 const Relocator* AArch64GNULDBackend::getRelocator() const {
146   assert(m_pRelocator != NULL);
147   return m_pRelocator;
148 }
149 
getRelocator()150 Relocator* AArch64GNULDBackend::getRelocator() {
151   assert(m_pRelocator != NULL);
152   return m_pRelocator;
153 }
154 
defineGOTSymbol(IRBuilder & pBuilder)155 void AArch64GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) {
156   // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
157   if (m_pGOTSymbol != NULL) {
158     pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
159         "_GLOBAL_OFFSET_TABLE_",
160         ResolveInfo::Object,
161         ResolveInfo::Define,
162         ResolveInfo::Local,
163         0x0,  // size
164         0x0,  // value
165         FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
166         ResolveInfo::Hidden);
167   } else {
168     m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
169         "_GLOBAL_OFFSET_TABLE_",
170         ResolveInfo::Object,
171         ResolveInfo::Define,
172         ResolveInfo::Local,
173         0x0,  // size
174         0x0,  // value
175         FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
176         ResolveInfo::Hidden);
177   }
178 }
179 
doPreLayout(IRBuilder & pBuilder)180 void AArch64GNULDBackend::doPreLayout(IRBuilder& pBuilder) {
181   // initialize .dynamic data
182   if (!config().isCodeStatic() && m_pDynamic == NULL)
183     m_pDynamic = new AArch64ELFDynamic(*this, config());
184 
185   if (LinkerConfig::Object != config().codeGenType()) {
186     // set .got size
187     if (config().options().hasNow()) {
188       // when building shared object, the GOTPLT section is must
189       if (LinkerConfig::DynObj == config().codeGenType() || m_pGOT->hasGOT1() ||
190           m_pGOTSymbol != NULL) {
191         m_pGOT->finalizeSectionSize();
192         defineGOTSymbol(pBuilder);
193       }
194     } else {
195       // when building shared object, the GOTPLT section is must
196       if (LinkerConfig::DynObj == config().codeGenType() ||
197           m_pGOTPLT->hasGOT1() || m_pGOTSymbol != NULL) {
198         m_pGOTPLT->finalizeSectionSize();
199         defineGOTSymbol(pBuilder);
200       }
201       if (m_pGOT->hasGOT1())
202         m_pGOT->finalizeSectionSize();
203     }
204 
205     // set .plt size
206     if (m_pPLT->hasPLT1())
207       m_pPLT->finalizeSectionSize();
208 
209     ELFFileFormat* file_format = getOutputFormat();
210     // set .rela.dyn size
211     if (!m_pRelaDyn->empty()) {
212       assert(
213           !config().isCodeStatic() &&
214           "static linkage should not result in a dynamic relocation section");
215       file_format->getRelaDyn().setSize(m_pRelaDyn->numOfRelocs() *
216                                         getRelaEntrySize());
217     }
218 
219     // set .rela.plt size
220     if (!m_pRelaPLT->empty()) {
221       assert(
222           !config().isCodeStatic() &&
223           "static linkage should not result in a dynamic relocation section");
224       file_format->getRelaPlt().setSize(m_pRelaPLT->numOfRelocs() *
225                                         getRelaEntrySize());
226     }
227   }
228 }
229 
doPostLayout(Module & pModule,IRBuilder & pBuilder)230 void AArch64GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
231   const ELFFileFormat* file_format = getOutputFormat();
232 
233   // apply PLT
234   if (file_format->hasPLT()) {
235     assert(m_pPLT != NULL);
236     m_pPLT->applyPLT0();
237     m_pPLT->applyPLT1();
238   }
239 
240   // apply GOTPLT
241   if ((config().options().hasNow() && file_format->hasGOT()) ||
242       file_format->hasGOTPLT()) {
243     assert(m_pGOTPLT != NULL);
244     if (LinkerConfig::DynObj == config().codeGenType())
245       m_pGOTPLT->applyGOT0(file_format->getDynamic().addr());
246     else {
247       // executable file and object file? should fill with zero.
248       m_pGOTPLT->applyGOT0(0);
249     }
250   }
251 }
252 
dynamic()253 AArch64ELFDynamic& AArch64GNULDBackend::dynamic() {
254   assert(m_pDynamic != NULL);
255   return *m_pDynamic;
256 }
257 
dynamic() const258 const AArch64ELFDynamic& AArch64GNULDBackend::dynamic() const {
259   assert(m_pDynamic != NULL);
260   return *m_pDynamic;
261 }
262 
emitSectionData(const LDSection & pSection,MemoryRegion & pRegion) const263 uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection,
264                                               MemoryRegion& pRegion) const {
265   assert(pRegion.size() && "Size of MemoryRegion is zero!");
266 
267   const ELFFileFormat* file_format = getOutputFormat();
268 
269   if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
270     uint64_t result = m_pPLT->emit(pRegion);
271     return result;
272   }
273 
274   if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
275     uint64_t result = m_pGOT->emit(pRegion);
276     return result;
277   }
278 
279   if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
280     uint64_t result = m_pGOT->emit(pRegion);
281     return result;
282   }
283 
284   // TODO
285   return pRegion.size();
286 }
287 
getTargetSectionOrder(const LDSection & pSectHdr) const288 unsigned int AArch64GNULDBackend::getTargetSectionOrder(
289     const LDSection& pSectHdr) const {
290   const ELFFileFormat* file_format = getOutputFormat();
291 
292   if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
293     if (config().options().hasNow())
294       return SHO_RELRO;
295     return SHO_RELRO_LAST;
296   }
297 
298   if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
299     return SHO_NON_RELRO_FIRST;
300 
301   if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
302     return SHO_PLT;
303 
304   return SHO_UNDEFINED;
305 }
306 
doRelax(Module & pModule,IRBuilder & pBuilder,bool & pFinished)307 bool AArch64GNULDBackend::doRelax(Module& pModule,
308                                   IRBuilder& pBuilder,
309                                   bool& pFinished) {
310   // TODO
311   return false;
312 }
313 
initTargetStubs()314 bool AArch64GNULDBackend::initTargetStubs() {
315   // TODO
316   return true;
317 }
318 
doCreateProgramHdrs(Module & pModule)319 void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule) {
320   // TODO
321 }
322 
finalizeTargetSymbols()323 bool AArch64GNULDBackend::finalizeTargetSymbols() {
324   // TODO
325   return true;
326 }
327 
mergeSection(Module & pModule,const Input & pInput,LDSection & pSection)328 bool AArch64GNULDBackend::mergeSection(Module& pModule,
329                                        const Input& pInput,
330                                        LDSection& pSection) {
331   // TODO
332   return true;
333 }
334 
readSection(Input & pInput,SectionData & pSD)335 bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD) {
336   // TODO
337   return true;
338 }
339 
getGOT()340 AArch64GOT& AArch64GNULDBackend::getGOT() {
341   assert(m_pGOT != NULL && "GOT section not exist");
342   return *m_pGOT;
343 }
344 
getGOT() const345 const AArch64GOT& AArch64GNULDBackend::getGOT() const {
346   assert(m_pGOT != NULL && "GOT section not exist");
347   return *m_pGOT;
348 }
349 
getGOTPLT()350 AArch64GOT& AArch64GNULDBackend::getGOTPLT() {
351   assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
352   return *m_pGOTPLT;
353 }
354 
getGOTPLT() const355 const AArch64GOT& AArch64GNULDBackend::getGOTPLT() const {
356   assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
357   return *m_pGOTPLT;
358 }
359 
getPLT()360 AArch64PLT& AArch64GNULDBackend::getPLT() {
361   assert(m_pPLT != NULL && "PLT section not exist");
362   return *m_pPLT;
363 }
364 
getPLT() const365 const AArch64PLT& AArch64GNULDBackend::getPLT() const {
366   assert(m_pPLT != NULL && "PLT section not exist");
367   return *m_pPLT;
368 }
369 
getRelaDyn()370 OutputRelocSection& AArch64GNULDBackend::getRelaDyn() {
371   assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
372   return *m_pRelaDyn;
373 }
374 
getRelaDyn() const375 const OutputRelocSection& AArch64GNULDBackend::getRelaDyn() const {
376   assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
377   return *m_pRelaDyn;
378 }
379 
getRelaPLT()380 OutputRelocSection& AArch64GNULDBackend::getRelaPLT() {
381   assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
382   return *m_pRelaPLT;
383 }
384 
getRelaPLT() const385 const OutputRelocSection& AArch64GNULDBackend::getRelaPLT() const {
386   assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
387   return *m_pRelaPLT;
388 }
389 
390 //===----------------------------------------------------------------------===//
391 //  createAArch64LDBackend - the help funtion to create corresponding
392 //  AArch64LDBackend
393 //===----------------------------------------------------------------------===//
createAArch64LDBackend(const LinkerConfig & pConfig)394 TargetLDBackend* createAArch64LDBackend(const LinkerConfig& pConfig) {
395   if (pConfig.targets().triple().isOSDarwin()) {
396     assert(0 && "MachO linker is not supported yet");
397     /**
398     return new AArch64MachOLDBackend(createAArch64MachOArchiveReader,
399                                      createAArch64MachOObjectReader,
400                                      createAArch64MachOObjectWriter);
401     **/
402   }
403   if (pConfig.targets().triple().isOSWindows()) {
404     assert(0 && "COFF linker is not supported yet");
405     /**
406     return new AArch64COFFLDBackend(createAArch64COFFArchiveReader,
407                                     createAArch64COFFObjectReader,
408                                     createAArch64COFFObjectWriter);
409     **/
410   }
411   return new AArch64GNULDBackend(
412       pConfig, new AArch64GNUInfo(pConfig.targets().triple()));
413 }
414 
415 }  // namespace mcld
416 
417 //===----------------------------------------------------------------------===//
418 // Force static initialization.
419 //===----------------------------------------------------------------------===//
MCLDInitializeAArch64LDBackend()420 extern "C" void MCLDInitializeAArch64LDBackend() {
421   // Register the linker backend
422   mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheAArch64Target,
423                                                 mcld::createAArch64LDBackend);
424 }
425