1//===- ELFDynamic.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 <llvm/Support/Host.h>
10#include <llvm/Support/ErrorHandling.h>
11#include <mcld/Target/ELFDynamic.h>
12#include <mcld/Target/GNULDBackend.h>
13#include <mcld/LD/ELFFileFormat.h>
14#include <mcld/MC/MCLDInfo.h>
15#include <mcld/Support/MemoryRegion.h>
16
17using namespace mcld;
18using namespace elf_dynamic;
19
20//===----------------------------------------------------------------------===//
21// elf_dynamic::EntryIF
22EntryIF::EntryIF()
23{
24}
25
26EntryIF::~EntryIF()
27{
28}
29
30//===----------------------------------------------------------------------===//
31// ELFDynamic
32ELFDynamic::ELFDynamic(const GNULDBackend& pParent)
33  : m_pEntryFactory(NULL), m_Idx(0) {
34  if (32 == pParent.bitclass() && pParent.isLittleEndian()) {
35    m_pEntryFactory = new Entry<32, true>();
36  }
37  // FIXME: support big-endian and 64-bit machine.
38}
39
40
41ELFDynamic::~ELFDynamic()
42{
43  if (NULL != m_pEntryFactory)
44    delete m_pEntryFactory;
45
46  EntryListType::iterator entry, entryEnd = m_EntryList.end();
47  for (entry = m_EntryList.begin(); entry != entryEnd; ++entry) {
48    if (NULL != *entry)
49      delete (*entry);
50  }
51
52  entryEnd = m_NeedList.end();
53  for (entry = m_NeedList.begin(); entry != entryEnd; ++entry) {
54    if (NULL != *entry)
55      delete (*entry);
56  }
57}
58
59size_t ELFDynamic::size() const
60{
61  return (m_NeedList.size() + m_EntryList.size());
62}
63
64size_t ELFDynamic::numOfBytes() const
65{
66  return size()*entrySize();
67}
68
69size_t ELFDynamic::entrySize() const
70{
71  return m_pEntryFactory->size();
72}
73
74void ELFDynamic::reserveOne(uint64_t pTag)
75{
76  assert(NULL != m_pEntryFactory);
77  m_EntryList.push_back(new elf_dynamic::Entry<32, true>());
78}
79
80void ELFDynamic::applyOne(uint64_t pTag, uint64_t pValue)
81{
82  assert(m_Idx < m_EntryList.size());
83  m_EntryList[m_Idx]->setValue(pTag, pValue);
84  ++m_Idx;
85}
86
87/// reserveEntries - reserve entries
88void ELFDynamic::reserveEntries(const MCLDInfo& pLDInfo,
89                                const ELFFileFormat& pFormat)
90{
91  if (pLDInfo.output().type() == Output::DynObj) {
92    reserveOne(llvm::ELF::DT_SONAME); // DT_SONAME
93
94    if (pLDInfo.options().Bsymbolic())
95      reserveOne(llvm::ELF::DT_SYMBOLIC); // DT_SYMBOLIC
96  }
97
98  if (pFormat.hasInit())
99    reserveOne(llvm::ELF::DT_INIT); // DT_INIT
100
101  if (pFormat.hasFini())
102    reserveOne(llvm::ELF::DT_FINI); // DT_FINI
103
104  if (pFormat.hasInitArray()) {
105    reserveOne(llvm::ELF::DT_INIT_ARRAY); // DT_INIT_ARRAY
106    reserveOne(llvm::ELF::DT_INIT_ARRAYSZ); // DT_INIT_ARRAYSZ
107  }
108
109  if (pFormat.hasFiniArray()) {
110    reserveOne(llvm::ELF::DT_FINI_ARRAY); // DT_FINI_ARRAY
111    reserveOne(llvm::ELF::DT_FINI_ARRAYSZ); // DT_FINI_ARRAYSZ
112  }
113
114  if (pFormat.hasHashTab())
115    reserveOne(llvm::ELF::DT_HASH); // DT_HASH
116
117  if (pFormat.hasDynSymTab()) {
118    reserveOne(llvm::ELF::DT_SYMTAB); // DT_SYMTAB
119    reserveOne(llvm::ELF::DT_SYMENT); // DT_SYMENT
120  }
121
122  if (pFormat.hasDynStrTab()) {
123    reserveOne(llvm::ELF::DT_STRTAB); // DT_STRTAB
124    reserveOne(llvm::ELF::DT_STRSZ); // DT_STRSZ
125  }
126
127  reserveTargetEntries(pFormat); // DT_PLTGOT
128
129  if (pFormat.hasRelPlt() || pFormat.hasRelaPlt())
130    reserveOne(llvm::ELF::DT_PLTREL); // DT_PLTREL
131
132  if (pFormat.hasPLT()) {
133    reserveOne(llvm::ELF::DT_JMPREL); // DT_JMPREL
134    reserveOne(llvm::ELF::DT_PLTRELSZ); // DT_PLTRELSZ
135  }
136
137  if (pFormat.hasRelDyn()) {
138    reserveOne(llvm::ELF::DT_REL); // DT_REL
139    reserveOne(llvm::ELF::DT_RELSZ); // DT_RELSZ
140    reserveOne(llvm::ELF::DT_RELENT); // DT_RELENT
141  }
142
143  if (pFormat.hasRelaDyn()) {
144    reserveOne(llvm::ELF::DT_RELA); // DT_RELA
145    reserveOne(llvm::ELF::DT_RELASZ); // DT_RELASZ
146    reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
147  }
148
149  if (pLDInfo.options().hasOrigin() ||
150      pLDInfo.options().Bsymbolic() ||
151      pLDInfo.options().hasNow()) {
152    // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
153    reserveOne(llvm::ELF::DT_FLAGS); // DT_FLAGS
154  }
155
156  if (pLDInfo.options().hasNow()          ||
157      pLDInfo.options().hasLoadFltr()     ||
158      pLDInfo.options().hasOrigin()       ||
159      pLDInfo.options().hasInterPose()    ||
160      pLDInfo.options().hasNoDefaultLib() ||
161      pLDInfo.options().hasNoDump()       ||
162      pLDInfo.options().Bgroup()          ||
163      ((pLDInfo.output().type() == Output::DynObj) &&
164       (pLDInfo.options().hasNoDelete()  ||
165        pLDInfo.options().hasInitFirst() ||
166        pLDInfo.options().hasNoDLOpen()))) {
167    reserveOne(llvm::ELF::DT_FLAGS_1); // DT_FLAGS_1
168  }
169
170  reserveOne(llvm::ELF::DT_NULL); // for DT_NULL
171}
172
173/// applyEntries - apply entries
174void ELFDynamic::applyEntries(const MCLDInfo& pInfo,
175                              const ELFFileFormat& pFormat)
176{
177  if (pInfo.output().type() == Output::DynObj &&
178      pInfo.options().Bsymbolic()) {
179      applyOne(llvm::ELF::DT_SYMBOLIC, 0x0); // DT_SYMBOLIC
180  }
181
182  if (pFormat.hasInit())
183    applyOne(llvm::ELF::DT_INIT, pFormat.getInit().addr()); // DT_INIT
184
185  if (pFormat.hasFini())
186    applyOne(llvm::ELF::DT_FINI, pFormat.getFini().addr()); // DT_FINI
187
188  if (pFormat.hasInitArray()) {
189    // DT_INIT_ARRAY
190    applyOne(llvm::ELF::DT_INIT_ARRAY, pFormat.getInitArray().addr());
191
192    // DT_INIT_ARRAYSZ
193    applyOne(llvm::ELF::DT_INIT_ARRAYSZ, pFormat.getInitArray().size());
194  }
195
196  if (pFormat.hasFiniArray()) {
197    // DT_FINI_ARRAY
198    applyOne(llvm::ELF::DT_FINI_ARRAY, pFormat.getFiniArray().addr());
199
200    // DT_FINI_ARRAYSZ
201    applyOne(llvm::ELF::DT_FINI_ARRAYSZ, pFormat.getFiniArray().size());
202  }
203
204  if (pFormat.hasHashTab())
205    applyOne(llvm::ELF::DT_HASH, pFormat.getHashTab().addr()); // DT_HASH
206
207  if (pFormat.hasDynSymTab()) {
208    applyOne(llvm::ELF::DT_SYMTAB, pFormat.getDynSymTab().addr()); // DT_SYMTAB
209    applyOne(llvm::ELF::DT_SYMENT, symbolSize()); // DT_SYMENT
210  }
211
212  if (pFormat.hasDynStrTab()) {
213    applyOne(llvm::ELF::DT_STRTAB, pFormat.getDynStrTab().addr()); // DT_STRTAB
214    applyOne(llvm::ELF::DT_STRSZ, pFormat.getDynStrTab().size()); // DT_STRSZ
215  }
216
217  applyTargetEntries(pFormat); // DT_PLTGOT
218
219  if (pFormat.hasRelPlt())
220    applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL
221  else if (pFormat.hasRelaPlt())
222    applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL
223
224  if (pFormat.hasRelPlt()) {
225    applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelPlt().addr()); // DT_JMPREL
226    applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelPlt().size()); // DT_PLTRELSZ
227  }
228
229  if (pFormat.hasRelDyn()) {
230    applyOne(llvm::ELF::DT_REL, pFormat.getRelDyn().addr()); // DT_REL
231    applyOne(llvm::ELF::DT_RELSZ, pFormat.getRelDyn().size()); // DT_RELSZ
232    applyOne(llvm::ELF::DT_RELENT, m_pEntryFactory->relSize()); // DT_RELENT
233  }
234
235  if (pFormat.hasRelaDyn()) {
236    applyOne(llvm::ELF::DT_RELA, pFormat.getRelaDyn().addr()); // DT_RELA
237    applyOne(llvm::ELF::DT_RELASZ, pFormat.getRelaDyn().size()); // DT_RELASZ
238    applyOne(llvm::ELF::DT_RELAENT, m_pEntryFactory->relaSize()); // DT_RELAENT
239  }
240
241  uint64_t dt_flags = 0x0;
242  if (pInfo.options().hasOrigin())
243    dt_flags |= llvm::ELF::DF_ORIGIN;
244  if (pInfo.options().Bsymbolic())
245    dt_flags |= llvm::ELF::DF_SYMBOLIC;
246  if (pInfo.options().hasNow())
247    dt_flags |= llvm::ELF::DF_BIND_NOW;
248  // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
249  if (0x0 != dt_flags) {
250    applyOne(llvm::ELF::DT_FLAGS, dt_flags); // DT_FLAGS
251  }
252
253  uint64_t dt_flags_1 = 0x0;
254  if (pInfo.options().hasNow())
255    dt_flags_1 |= llvm::ELF::DF_1_NOW;
256  if (pInfo.options().hasLoadFltr())
257    dt_flags_1 |= llvm::ELF::DF_1_LOADFLTR;
258  if (pInfo.options().hasOrigin())
259    dt_flags_1 |= llvm::ELF::DF_1_ORIGIN;
260  if (pInfo.options().hasInterPose())
261    dt_flags_1 |= llvm::ELF::DF_1_INTERPOSE;
262  if (pInfo.options().hasNoDefaultLib())
263    dt_flags_1 |= llvm::ELF::DF_1_NODEFLIB;
264  if (pInfo.options().hasNoDump())
265    dt_flags_1 |= llvm::ELF::DF_1_NODUMP;
266  if (pInfo.options().Bgroup())
267    dt_flags_1 |= llvm::ELF::DF_1_GROUP;
268  if (pInfo.output().type() == Output::DynObj) {
269    if (pInfo.options().hasNoDelete())
270      dt_flags_1 |= llvm::ELF::DF_1_NODELETE;
271    if (pInfo.options().hasInitFirst())
272      dt_flags_1 |= llvm::ELF::DF_1_INITFIRST;
273    if (pInfo.options().hasNoDLOpen())
274      dt_flags_1 |= llvm::ELF::DF_1_NOOPEN;
275  }
276  if (0x0 != dt_flags_1)
277    applyOne(llvm::ELF::DT_FLAGS_1, dt_flags_1); // DT_FLAGS_1
278
279  applyOne(llvm::ELF::DT_NULL, 0x0); // for DT_NULL
280}
281
282/// symbolSize
283size_t ELFDynamic::symbolSize() const
284{
285  return m_pEntryFactory->symbolSize();
286}
287
288/// reserveNeedEntry - reserve on DT_NEED entry.
289void ELFDynamic::reserveNeedEntry()
290{
291  m_NeedList.push_back(m_pEntryFactory->clone());
292}
293
294/// emit
295void ELFDynamic::emit(const LDSection& pSection, MemoryRegion& pRegion) const
296{
297  if (pRegion.size() < pSection.size()) {
298    llvm::report_fatal_error(llvm::Twine("the given memory is smaller") +
299                             llvm::Twine(" than the section's demaind.\n"));
300  }
301
302  uint8_t* address = (uint8_t*)pRegion.start();
303  EntryListType::const_iterator entry, entryEnd = m_NeedList.end();
304  for (entry = m_NeedList.begin(); entry != entryEnd; ++entry)
305    address += (*entry)->emit(address);
306
307  entryEnd = m_EntryList.end();
308  for (entry = m_EntryList.begin(); entry != entryEnd; ++entry)
309    address += (*entry)->emit(address);
310}
311
312void ELFDynamic::applySoname(uint64_t pStrTabIdx)
313{
314  applyOne(llvm::ELF::DT_SONAME, pStrTabIdx); // DT_SONAME
315}
316
317