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 
25 namespace mcld {
26 
27 //===----------------------------------------------------------------------===//
28 // ELFReaderIF
29 //===----------------------------------------------------------------------===//
30 /// getSymType
getSymType(uint8_t pInfo,uint16_t pShndx) const31 ResolveInfo::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
getSymDesc(uint16_t pShndx,const Input & pInput) const46 ResolveInfo::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
getSymBinding(uint8_t pBinding,uint16_t pShndx,uint8_t pVis) const74 ResolveInfo::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
getSymFragmentRef(Input & pInput,uint16_t pShndx,uint32_t pOffset) const95 FragmentRef* 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
getSymVisibility(uint8_t pVis) const123 ResolveInfo::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.
getSymValue(uint64_t pValue,uint16_t pShndx,const Input & pInput) const128 uint64_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