Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / openmp / libomptarget / plugins-nextgen / common / elf_common / ELFSymbols.cpp
blob36ed9aef3a7e4f224e4d5e7c7323e8191846acf4
1 //===-- ELFSymbols.cpp - ELF Symbol look-up functionality -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "ELFSymbols.h"
11 using namespace llvm;
12 using namespace llvm::object;
13 using namespace llvm::ELF;
15 template <class ELFT>
16 static Expected<const typename ELFT::Sym *>
17 getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab,
18 ArrayRef<typename ELFT::Sym> SymTab,
19 StringRef StrTab) {
20 const uint32_t NameHash = hashGnu(Name);
21 const typename ELFT::Word NBucket = HashTab.nbuckets;
22 const typename ELFT::Word SymOffset = HashTab.symndx;
23 ArrayRef<typename ELFT::Off> Filter = HashTab.filter();
24 ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets();
25 ArrayRef<typename ELFT::Word> Chain = HashTab.values(SymTab.size());
27 // Check the bloom filter and exit early if the symbol is not present.
28 uint64_t ElfClassBits = ELFT::Is64Bits ? 64 : 32;
29 typename ELFT::Off Word =
30 Filter[(NameHash / ElfClassBits) % HashTab.maskwords];
31 uint64_t Mask = (0x1ull << (NameHash % ElfClassBits)) |
32 (0x1ull << ((NameHash >> HashTab.shift2) % ElfClassBits));
33 if ((Word & Mask) != Mask)
34 return nullptr;
36 // The symbol may or may not be present, check the hash values.
37 for (typename ELFT::Word I = Bucket[NameHash % NBucket];
38 I >= SymOffset && I < SymTab.size(); I = I + 1) {
39 const uint32_t ChainHash = Chain[I - SymOffset];
41 if ((NameHash | 0x1) != (ChainHash | 0x1))
42 continue;
44 if (SymTab[I].st_name >= StrTab.size())
45 return createError("symbol [index " + Twine(I) +
46 "] has invalid st_name: " + Twine(SymTab[I].st_name));
47 if (StrTab.drop_front(SymTab[I].st_name).data() == Name)
48 return &SymTab[I];
50 if (ChainHash & 0x1)
51 return nullptr;
53 return nullptr;
56 template <class ELFT>
57 static Expected<const typename ELFT::Sym *>
58 getSymbolFromSysVHashTable(StringRef Name, const typename ELFT::Hash &HashTab,
59 ArrayRef<typename ELFT::Sym> SymTab,
60 StringRef StrTab) {
61 const uint32_t Hash = hashSysV(Name);
62 const typename ELFT::Word NBucket = HashTab.nbucket;
63 ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets();
64 ArrayRef<typename ELFT::Word> Chain = HashTab.chains();
65 for (typename ELFT::Word I = Bucket[Hash % NBucket]; I != ELF::STN_UNDEF;
66 I = Chain[I]) {
67 if (I >= SymTab.size())
68 return createError(
69 "symbol [index " + Twine(I) +
70 "] is greater than the number of symbols: " + Twine(SymTab.size()));
71 if (SymTab[I].st_name >= StrTab.size())
72 return createError("symbol [index " + Twine(I) +
73 "] has invalid st_name: " + Twine(SymTab[I].st_name));
75 if (StrTab.drop_front(SymTab[I].st_name).data() == Name)
76 return &SymTab[I];
78 return nullptr;
81 template <class ELFT>
82 static Expected<const typename ELFT::Sym *>
83 getHashTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
84 StringRef Name) {
85 if (Sec.sh_type != ELF::SHT_HASH && Sec.sh_type != ELF::SHT_GNU_HASH)
86 return createError(
87 "invalid sh_type for hash table, expected SHT_HASH or SHT_GNU_HASH");
88 Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections();
89 if (!SectionsOrError)
90 return SectionsOrError.takeError();
92 auto SymTabOrErr = getSection<ELFT>(*SectionsOrError, Sec.sh_link);
93 if (!SymTabOrErr)
94 return SymTabOrErr.takeError();
96 auto StrTabOrErr =
97 Elf.getStringTableForSymtab(**SymTabOrErr, *SectionsOrError);
98 if (!StrTabOrErr)
99 return StrTabOrErr.takeError();
100 StringRef StrTab = *StrTabOrErr;
102 auto SymsOrErr = Elf.symbols(*SymTabOrErr);
103 if (!SymsOrErr)
104 return SymsOrErr.takeError();
105 ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr;
107 // If this is a GNU hash table we verify its size and search the symbol
108 // table using the GNU hash table format.
109 if (Sec.sh_type == ELF::SHT_GNU_HASH) {
110 const typename ELFT::GnuHash *HashTab =
111 reinterpret_cast<const typename ELFT::GnuHash *>(Elf.base() +
112 Sec.sh_offset);
113 if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize())
114 return createError("section has invalid sh_offset: " +
115 Twine(Sec.sh_offset));
116 if (Sec.sh_size < sizeof(typename ELFT::GnuHash) ||
117 Sec.sh_size <
118 sizeof(typename ELFT::GnuHash) +
119 sizeof(typename ELFT::Word) * HashTab->maskwords +
120 sizeof(typename ELFT::Word) * HashTab->nbuckets +
121 sizeof(typename ELFT::Word) * (SymTab.size() - HashTab->symndx))
122 return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
123 return getSymbolFromGnuHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
126 // If this is a Sys-V hash table we verify its size and search the symbol
127 // table using the Sys-V hash table format.
128 if (Sec.sh_type == ELF::SHT_HASH) {
129 const typename ELFT::Hash *HashTab =
130 reinterpret_cast<const typename ELFT::Hash *>(Elf.base() +
131 Sec.sh_offset);
132 if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize())
133 return createError("section has invalid sh_offset: " +
134 Twine(Sec.sh_offset));
135 if (Sec.sh_size < sizeof(typename ELFT::Hash) ||
136 Sec.sh_size < sizeof(typename ELFT::Hash) +
137 sizeof(typename ELFT::Word) * HashTab->nbucket +
138 sizeof(typename ELFT::Word) * HashTab->nchain)
139 return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
141 return getSymbolFromSysVHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
144 return nullptr;
147 template <class ELFT>
148 static Expected<const typename ELFT::Sym *>
149 getSymTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
150 StringRef Name) {
151 if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
152 return createError(
153 "invalid sh_type for hash table, expected SHT_SYMTAB or SHT_DYNSYM");
154 Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections();
155 if (!SectionsOrError)
156 return SectionsOrError.takeError();
158 auto StrTabOrErr = Elf.getStringTableForSymtab(Sec, *SectionsOrError);
159 if (!StrTabOrErr)
160 return StrTabOrErr.takeError();
161 StringRef StrTab = *StrTabOrErr;
163 auto SymsOrErr = Elf.symbols(&Sec);
164 if (!SymsOrErr)
165 return SymsOrErr.takeError();
166 ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr;
168 for (const typename ELFT::Sym &Sym : SymTab)
169 if (StrTab.drop_front(Sym.st_name).data() == Name)
170 return &Sym;
172 return nullptr;
175 Expected<const typename ELF64LE::Sym *>
176 getELFSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
177 // First try to look up the symbol via the hash table.
178 for (ELFSectionRef Sec : ELFObj.sections()) {
179 if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH)
180 continue;
182 auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
183 if (!HashTabOrErr)
184 return HashTabOrErr.takeError();
185 return getHashTableSymbol<ELF64LE>(ELFObj.getELFFile(), **HashTabOrErr,
186 Name);
189 // If this is an executable file check the entire standard symbol table.
190 for (ELFSectionRef Sec : ELFObj.sections()) {
191 if (Sec.getType() != SHT_SYMTAB)
192 continue;
194 auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
195 if (!SymTabOrErr)
196 return SymTabOrErr.takeError();
197 return getSymTableSymbol<ELF64LE>(ELFObj.getELFFile(), **SymTabOrErr, Name);
200 return nullptr;