1//===- ELFReader.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
10#include <llvm/ADT/StringRef.h>
11#include <llvm/ADT/Twine.h>
12#include <llvm/Support/ELF.h>
13#include <llvm/Support/Host.h>
14
15#include <mcld/MC/MCLinker.h>
16#include <mcld/LD/ELFReader.h>
17#include <mcld/Target/GNULDBackend.h>
18#include <mcld/Support/MemoryArea.h>
19#include <mcld/Support/MemoryRegion.h>
20#include <mcld/Support/MsgHandling.h>
21#include <cstring>
22
23using namespace mcld;
24
25//===----------------------------------------------------------------------===//
26// ELFReaderIF
27/// getLDSectionKind
28LDFileFormat::Kind
29ELFReaderIF::getLDSectionKind(uint32_t pType, const char* pName) const
30{
31  // name rules
32  llvm::StringRef name(pName);
33  if (name.startswith(".debug") ||
34      name.startswith(".zdebug") ||
35      name.startswith(".gnu.linkonce.wi.") ||
36      name.startswith(".line") ||
37      name.startswith(".stab"))
38    return LDFileFormat::Debug;
39  if (name.startswith(".comment"))
40    return LDFileFormat::MetaData;
41  if (name.startswith(".interp") || name.startswith(".dynamic"))
42    return LDFileFormat::Note;
43  if (name.startswith(".eh_frame"))
44    return LDFileFormat::EhFrame;
45  if (name.startswith(".eh_frame_hdr"))
46    return LDFileFormat::EhFrameHdr;
47  if (name.startswith(".gcc_except_table"))
48    return LDFileFormat::GCCExceptTable;
49
50  // type rules
51  switch(pType) {
52  case llvm::ELF::SHT_NULL:
53    return LDFileFormat::Null;
54  case llvm::ELF::SHT_INIT_ARRAY:
55  case llvm::ELF::SHT_FINI_ARRAY:
56  case llvm::ELF::SHT_PREINIT_ARRAY:
57  case llvm::ELF::SHT_PROGBITS:
58    return LDFileFormat::Regular;
59  case llvm::ELF::SHT_SYMTAB:
60  case llvm::ELF::SHT_DYNSYM:
61  case llvm::ELF::SHT_STRTAB:
62    return LDFileFormat::NamePool;
63  case llvm::ELF::SHT_RELA:
64  case llvm::ELF::SHT_REL:
65    return LDFileFormat::Relocation;
66  case llvm::ELF::SHT_NOBITS:
67    return LDFileFormat::BSS;
68  case llvm::ELF::SHT_DYNAMIC:
69  case llvm::ELF::SHT_NOTE:
70    return LDFileFormat::Note;
71  case llvm::ELF::SHT_HASH:
72  case llvm::ELF::SHT_SHLIB:
73    return LDFileFormat::MetaData;
74  case llvm::ELF::SHT_GROUP:
75    return LDFileFormat::Group;
76  case llvm::ELF::SHT_GNU_versym:
77  case llvm::ELF::SHT_GNU_verdef:
78  case llvm::ELF::SHT_GNU_verneed:
79    return LDFileFormat::Version;
80  default:
81    if ((pType >= llvm::ELF::SHT_LOPROC && pType <= llvm::ELF::SHT_HIPROC) ||
82        (pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
83        (pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
84      return LDFileFormat::Target;
85    fatal(diag::err_unsupported_section) << pName << pType;
86  }
87  return LDFileFormat::MetaData;
88}
89
90/// getSymType
91ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const
92{
93  ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF);
94  if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) {
95    // In Mips, __gp_disp is a special section symbol. Its name comes from
96    // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS
97    // symbol. So here is a tricky to identify __gp_disp and convert it to
98    // Object symbol.
99    return ResolveInfo::Object;
100  }
101
102  return result;
103}
104
105/// getSymDesc
106ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const
107{
108  if (pShndx == llvm::ELF::SHN_UNDEF)
109    return ResolveInfo::Undefined;
110
111  if (pShndx < llvm::ELF::SHN_LORESERVE) {
112    // an ELF symbol defined in a section which we are not including
113    // must be treated as an Undefined.
114    // @ref Google gold linker: symtab.cc: 1086
115    if (NULL == pInput.context()->getSection(pShndx))
116      return ResolveInfo::Undefined;
117    return ResolveInfo::Define;
118  }
119
120  if (pShndx == llvm::ELF::SHN_ABS)
121    return ResolveInfo::Define;
122
123  if (pShndx == llvm::ELF::SHN_COMMON)
124    return ResolveInfo::Common;
125
126  // FIXME: ELF weak alias should be ResolveInfo::Indirect
127  return ResolveInfo::NoneDesc;
128}
129
130/// getSymBinding
131ResolveInfo::Binding
132ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const
133{
134
135  // TODO:
136  // if --just-symbols option is enabled, the symbol must covert to Absolute
137
138  switch(pBinding) {
139  case llvm::ELF::STB_LOCAL:
140    return ResolveInfo::Local;
141  case llvm::ELF::STB_GLOBAL:
142    return ResolveInfo::Global;
143  case llvm::ELF::STB_WEAK:
144    return ResolveInfo::Weak;
145  }
146
147  if (pShndx == llvm::ELF::SHN_ABS)
148    return ResolveInfo::Absolute;
149
150  return ResolveInfo::NoneBinding;
151}
152
153/// getSymFragmentRef
154FragmentRef*
155ELFReaderIF::getSymFragmentRef(Input& pInput,
156                               MCLinker& pLinker,
157                               uint16_t pShndx,
158                               uint32_t pOffset) const
159{
160
161  if (pShndx == llvm::ELF::SHN_UNDEF || pShndx >= llvm::ELF::SHN_LORESERVE)
162    return NULL;
163
164  LDSection* sect_hdr = pInput.context()->getSection(pShndx);
165
166  if (NULL == sect_hdr)
167    unreachable(diag::unreachable_invalid_section_idx) << pShndx
168                                                       << pInput.path().native();
169
170  FragmentRef* result = pLinker.getLayout().getFragmentRef(*sect_hdr, pOffset);
171  return result;
172}
173
174/// getSymVisibility
175ResolveInfo::Visibility
176ELFReaderIF::getSymVisibility(uint8_t pVis) const
177{
178  return static_cast<ResolveInfo::Visibility>(pVis);
179}
180
181/// getSymValue - get the section offset of the symbol.
182uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
183                                  uint16_t pShndx,
184                                  const Input& pInput) const
185{
186  if (Input::Object == pInput.type()) {
187    // In relocatable files, st_value holds alignment constraints for a symbol
188    // whose section index is SHN_COMMON
189    if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
190      return pValue;
191    }
192
193    // In relocatable files, st_value holds a section offset for a defined symbol.
194    // TODO:
195    // if --just-symbols option are enabled, convert the value from section offset
196    // to virtual address by adding input section's virtual address.
197    // The section's virtual address in relocatable files is normally zero, but
198    // people can use link script to change it.
199    return pValue;
200  }
201
202  // In executable and shared object files, st_value holds a virtual address.
203  // the virtual address is useless during linking.
204  return 0x0;
205}
206
207bool ELFReaderIF::readEhFrame(Input& pInput,
208                              MCLinker& pLinker,
209                              LDSection& pInputSectHdr) const
210{
211  LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
212                                                         pInputSectHdr.kind(),
213                                                         pInputSectHdr.type(),
214                                                         pInputSectHdr.flag());
215
216  size_t size = pLinker.addEhFrame(pInput, pInputSectHdr, *pInput.memArea());
217
218  out_sect.setSize(out_sect.size() + size);
219  return true;
220}
221