1 //===-- ELFSymbols.cpp - ELF Symbol look-up functionality -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ELFSymbols.h"
12 using namespace llvm::object
;
13 using namespace llvm::ELF
;
16 static Expected
<const typename
ELFT::Sym
*>
17 getSymbolFromGnuHashTable(StringRef Name
, const typename
ELFT::GnuHash
&HashTab
,
18 ArrayRef
<typename
ELFT::Sym
> SymTab
,
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
)
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))
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
)
57 static Expected
<const typename
ELFT::Sym
*>
58 getSymbolFromSysVHashTable(StringRef Name
, const typename
ELFT::Hash
&HashTab
,
59 ArrayRef
<typename
ELFT::Sym
> SymTab
,
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
;
67 if (I
>= SymTab
.size())
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
)
82 static Expected
<const typename
ELFT::Sym
*>
83 getHashTableSymbol(const ELFFile
<ELFT
> &Elf
, const typename
ELFT::Shdr
&Sec
,
85 if (Sec
.sh_type
!= ELF::SHT_HASH
&& Sec
.sh_type
!= ELF::SHT_GNU_HASH
)
87 "invalid sh_type for hash table, expected SHT_HASH or SHT_GNU_HASH");
88 Expected
<typename
ELFT::ShdrRange
> SectionsOrError
= Elf
.sections();
90 return SectionsOrError
.takeError();
92 auto SymTabOrErr
= getSection
<ELFT
>(*SectionsOrError
, Sec
.sh_link
);
94 return SymTabOrErr
.takeError();
97 Elf
.getStringTableForSymtab(**SymTabOrErr
, *SectionsOrError
);
99 return StrTabOrErr
.takeError();
100 StringRef StrTab
= *StrTabOrErr
;
102 auto SymsOrErr
= Elf
.symbols(*SymTabOrErr
);
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() +
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
) ||
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() +
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
);
147 template <class ELFT
>
148 static Expected
<const typename
ELFT::Sym
*>
149 getSymTableSymbol(const ELFFile
<ELFT
> &Elf
, const typename
ELFT::Shdr
&Sec
,
151 if (Sec
.sh_type
!= ELF::SHT_SYMTAB
&& Sec
.sh_type
!= ELF::SHT_DYNSYM
)
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
);
160 return StrTabOrErr
.takeError();
161 StringRef StrTab
= *StrTabOrErr
;
163 auto SymsOrErr
= Elf
.symbols(&Sec
);
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
)
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
)
182 auto HashTabOrErr
= ELFObj
.getELFFile().getSection(Sec
.getIndex());
184 return HashTabOrErr
.takeError();
185 return getHashTableSymbol
<ELF64LE
>(ELFObj
.getELFFile(), **HashTabOrErr
,
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
)
194 auto SymTabOrErr
= ELFObj
.getELFFile().getSection(Sec
.getIndex());
196 return SymTabOrErr
.takeError();
197 return getSymTableSymbol
<ELF64LE
>(ELFObj
.getELFFile(), **SymTabOrErr
, Name
);