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#include "mcld/LD/ELFReaderIf.h"
10
11#include "mcld/IRBuilder.h"
12#include "mcld/Fragment/FillFragment.h"
13#include "mcld/LD/EhFrame.h"
14#include "mcld/LD/LDContext.h"
15#include "mcld/LD/SectionData.h"
16#include "mcld/Target/GNULDBackend.h"
17
18#include <llvm/ADT/StringRef.h>
19#include <llvm/ADT/Twine.h>
20#include <llvm/Support/ELF.h>
21#include <llvm/Support/Host.h>
22
23#include <cstring>
24
25namespace mcld {
26
27//===----------------------------------------------------------------------===//
28// ELFReaderIF
29//===----------------------------------------------------------------------===//
30/// getSymType
31ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo,
32                                          uint16_t pShndx) const {
33  ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF);
34  if (pShndx == llvm::ELF::SHN_ABS && result == ResolveInfo::Section) {
35    // In Mips, __gp_disp is a special section symbol. Its name comes from
36    // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS
37    // symbol. So here is a tricky to identify __gp_disp and convert it to
38    // Object symbol.
39    return ResolveInfo::Object;
40  }
41
42  return result;
43}
44
45/// getSymDesc
46ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx,
47                                          const Input& pInput) const {
48  if (pShndx == llvm::ELF::SHN_UNDEF)
49    return ResolveInfo::Undefined;
50
51  if (pShndx < llvm::ELF::SHN_LORESERVE) {
52    // an ELF symbol defined in a section which we are not including
53    // must be treated as an Undefined.
54    if (pInput.context()->getSection(pShndx) == NULL ||
55        LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind())
56      return ResolveInfo::Undefined;
57    return ResolveInfo::Define;
58  }
59
60  if (pShndx == llvm::ELF::SHN_ABS)
61    return ResolveInfo::Define;
62
63  if (pShndx == llvm::ELF::SHN_COMMON)
64    return ResolveInfo::Common;
65
66  if (pShndx >= llvm::ELF::SHN_LOPROC && pShndx <= llvm::ELF::SHN_HIPROC)
67    return target().getSymDesc(pShndx);
68
69  // FIXME: ELF weak alias should be ResolveInfo::Indirect
70  return ResolveInfo::NoneDesc;
71}
72
73/// getSymBinding
74ResolveInfo::Binding ELFReaderIF::getSymBinding(uint8_t pBinding,
75                                                uint16_t pShndx,
76                                                uint8_t pVis) const {
77  // TODO:
78  // if --just-symbols option is enabled, the symbol must covert to Absolute
79
80  switch (pBinding) {
81    case llvm::ELF::STB_LOCAL:
82      return ResolveInfo::Local;
83    case llvm::ELF::STB_GLOBAL:
84      if (pShndx == llvm::ELF::SHN_ABS)
85        return ResolveInfo::Absolute;
86      return ResolveInfo::Global;
87    case llvm::ELF::STB_WEAK:
88      return ResolveInfo::Weak;
89  }
90
91  return ResolveInfo::NoneBinding;
92}
93
94/// getSymFragmentRef
95FragmentRef* ELFReaderIF::getSymFragmentRef(Input& pInput,
96                                            uint16_t pShndx,
97                                            uint32_t pOffset) const {
98  if (pInput.type() == Input::DynObj)
99    return FragmentRef::Null();
100
101  if (pShndx == llvm::ELF::SHN_UNDEF)
102    return FragmentRef::Null();
103
104  if (pShndx >= llvm::ELF::SHN_LORESERVE)  // including ABS and COMMON
105    return FragmentRef::Null();
106
107  LDSection* sect_hdr = pInput.context()->getSection(pShndx);
108
109  if (sect_hdr == NULL)
110    unreachable(diag::unreachable_invalid_section_idx)
111        << pShndx << pInput.path().native();
112
113  if (sect_hdr->kind() == LDFileFormat::Ignore)
114    return FragmentRef::Null();
115
116  if (sect_hdr->kind() == LDFileFormat::Group)
117    return FragmentRef::Null();
118
119  return FragmentRef::Create(*sect_hdr, pOffset);
120}
121
122/// getSymVisibility
123ResolveInfo::Visibility ELFReaderIF::getSymVisibility(uint8_t pVis) const {
124  return static_cast<ResolveInfo::Visibility>(pVis);
125}
126
127/// getSymValue - get the section offset of the symbol.
128uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
129                                  uint16_t pShndx,
130                                  const Input& pInput) const {
131  if (pInput.type() == Input::Object) {
132    // In relocatable files, st_value holds alignment constraints for a symbol
133    // whose section index is SHN_COMMON
134    if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
135      return pValue;
136    }
137
138    // In relocatable files, st_value holds a section offset for a defined
139    // symbol.
140    // TODO:
141    // if --just-symbols option are enabled, convert the value from section
142    // offset
143    // to virtual address by adding input section's virtual address.
144    // The section's virtual address in relocatable files is normally zero, but
145    // people can use link script to change it.
146    return pValue;
147  }
148
149  // In executable and shared object files, st_value holds a virtual address.
150  // the virtual address is needed for alias identification.
151  return pValue;
152}
153
154}  // namespace mcld
155