• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 using namespace mcld;
24 
25 //===----------------------------------------------------------------------===//
26 // ELFReaderIF
27 /// getLDSectionKind
28 LDFileFormat::Kind
getLDSectionKind(uint32_t pType,const char * pName) const29 ELFReaderIF::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
getSymType(uint8_t pInfo,uint16_t pShndx) const91 ResolveInfo::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
getSymDesc(uint16_t pShndx,const Input & pInput) const106 ResolveInfo::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
131 ResolveInfo::Binding
getSymBinding(uint8_t pBinding,uint16_t pShndx,uint8_t pVis) const132 ELFReaderIF::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
154 FragmentRef*
getSymFragmentRef(Input & pInput,MCLinker & pLinker,uint16_t pShndx,uint32_t pOffset) const155 ELFReaderIF::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
175 ResolveInfo::Visibility
getSymVisibility(uint8_t pVis) const176 ELFReaderIF::getSymVisibility(uint8_t pVis) const
177 {
178   return static_cast<ResolveInfo::Visibility>(pVis);
179 }
180 
181 /// getSymValue - get the section offset of the symbol.
getSymValue(uint64_t pValue,uint16_t pShndx,const Input & pInput) const182 uint64_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 
readEhFrame(Input & pInput,MCLinker & pLinker,LDSection & pInputSectHdr) const207 bool 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