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