@@ -278,9 +278,46 @@ class ELFFile {
278278 std::vector<Elf_Shdr> FakeSections;
279279 SmallString<0 > FakeSectionStrings;
280280
281+ // When the number of program headers is >= PN_XNUM, the actual number is
282+ // contained in the sh_info field of the section header at index 0.
283+ std::optional<uint32_t > RealPhNum;
284+ // When the number of section headers is >= SHN_LORESERVE, the actual number
285+ // is contained in the sh_size field of the section header at index 0.
286+ std::optional<uint64_t > RealShNum;
287+ // When the section index of the section name table is >= SHN_LORESERVE, the
288+ // actual number is contained in the sh_link field of the section header at
289+ // index 0.
290+ std::optional<uint32_t > RealShStrNdx;
291+
281292 ELFFile (StringRef Object);
282293
294+ Error readShdrZero ();
295+
283296public:
297+ Expected<uint32_t > getPhNum () const {
298+ if (!RealPhNum) {
299+ if (Error E = const_cast <ELFFile<ELFT> *>(this )->readShdrZero ())
300+ return std::move (E);
301+ }
302+ return *RealPhNum;
303+ }
304+
305+ Expected<uint64_t > getShNum () const {
306+ if (!RealShNum) {
307+ if (Error E = const_cast <ELFFile<ELFT> *>(this )->readShdrZero ())
308+ return std::move (E);
309+ }
310+ return *RealShNum;
311+ }
312+
313+ Expected<uint32_t > getShStrNdx () const {
314+ if (!RealShStrNdx) {
315+ if (Error E = const_cast <ELFFile<ELFT> *>(this )->readShdrZero ())
316+ return std::move (E);
317+ }
318+ return *RealShStrNdx;
319+ }
320+
284321 const Elf_Ehdr &getHeader () const {
285322 return *reinterpret_cast <const Elf_Ehdr *>(base ());
286323 }
@@ -379,22 +416,26 @@ class ELFFile {
379416
380417 // / Iterate over program header table.
381418 Expected<Elf_Phdr_Range> program_headers () const {
382- if (getHeader ().e_phnum && getHeader ().e_phentsize != sizeof (Elf_Phdr))
419+ uint32_t NumPh;
420+ if (Expected<uint32_t > PhNumOrErr = getPhNum ())
421+ NumPh = *PhNumOrErr;
422+ else
423+ return PhNumOrErr.takeError ();
424+ if (NumPh && getHeader ().e_phentsize != sizeof (Elf_Phdr))
383425 return createError (" invalid e_phentsize: " +
384426 Twine (getHeader ().e_phentsize ));
385427
386- uint64_t HeadersSize =
387- (uint64_t )getHeader ().e_phnum * getHeader ().e_phentsize ;
428+ uint64_t HeadersSize = (uint64_t )NumPh * getHeader ().e_phentsize ;
388429 uint64_t PhOff = getHeader ().e_phoff ;
389430 if (PhOff + HeadersSize < PhOff || PhOff + HeadersSize > getBufSize ())
390431 return createError (" program headers are longer than binary of size " +
391432 Twine (getBufSize ()) + " : e_phoff = 0x" +
392433 Twine::utohexstr (getHeader ().e_phoff ) +
393- " , e_phnum = " + Twine (getHeader (). e_phnum ) +
434+ " , e_phnum = " + Twine (NumPh ) +
394435 " , e_phentsize = " + Twine (getHeader ().e_phentsize ));
395436
396437 auto *Begin = reinterpret_cast <const Elf_Phdr *>(base () + PhOff);
397- return ArrayRef (Begin, Begin + getHeader (). e_phnum );
438+ return ArrayRef (Begin, Begin + NumPh );
398439 }
399440
400441 // / Get an iterator over notes in a program header.
@@ -772,19 +813,15 @@ template <class ELFT>
772813Expected<StringRef>
773814ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
774815 WarningHandler WarnHandler) const {
775- uint32_t Index = getHeader ().e_shstrndx ;
776- if (Index == ELF::SHN_XINDEX) {
777- // If the section name string table section index is greater than
778- // or equal to SHN_LORESERVE, then the actual index of the section name
779- // string table section is contained in the sh_link field of the section
780- // header at index 0.
781- if (Sections.empty ())
782- return createError (
783- " e_shstrndx == SHN_XINDEX, but the section header table is empty" );
816+ Expected<uint32_t > ShStrNdxOrErr = getShStrNdx ();
817+ if (!ShStrNdxOrErr)
818+ return ShStrNdxOrErr.takeError ();
784819
785- Index = Sections[0 ].sh_link ;
786- }
820+ if (*ShStrNdxOrErr == ELF::SHN_XINDEX && Sections.empty ())
821+ return createError (
822+ " e_shstrndx == SHN_XINDEX, but the section header table is empty" );
787823
824+ uint32_t Index = *ShStrNdxOrErr;
788825 // There is no section name string table. Return FakeSectionStrings which
789826 // is non-empty if we have created fake sections.
790827 if (!Index)
@@ -891,6 +928,35 @@ Expected<uint64_t> ELFFile<ELFT>::getDynSymtabSize() const {
891928
892929template <class ELFT > ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
893930
931+ template <class ELFT > Error ELFFile<ELFT>::readShdrZero() {
932+ const Elf_Ehdr &Header = getHeader ();
933+
934+ if ((Header.e_phnum == ELF::PN_XNUM || Header.e_shnum == 0 ||
935+ Header.e_shstrndx == ELF::SHN_XINDEX) &&
936+ Header.e_shoff != 0 ) {
937+ // Pretend we have section 0 or sections() would call getShNum and thus
938+ // become an infinite recursion.
939+ RealShNum = 1 ;
940+ auto SecOrErr = getSection (0 );
941+ if (!SecOrErr) {
942+ RealShNum = std::nullopt ;
943+ return SecOrErr.takeError ();
944+ }
945+
946+ RealPhNum =
947+ Header.e_phnum == ELF::PN_XNUM ? (*SecOrErr)->sh_info : Header.e_phnum ;
948+ RealShNum = Header.e_shnum == 0 ? (*SecOrErr)->sh_size : Header.e_shnum ;
949+ RealShStrNdx = Header.e_shstrndx == ELF::SHN_XINDEX ? (*SecOrErr)->sh_link
950+ : Header.e_shstrndx ;
951+ } else {
952+ RealPhNum = Header.e_phnum ;
953+ RealShNum = Header.e_shnum ;
954+ RealShStrNdx = Header.e_shstrndx ;
955+ }
956+
957+ return Error::success ();
958+ }
959+
894960template <class ELFT >
895961Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) {
896962 if (sizeof (Elf_Ehdr) > Object.size ())
@@ -956,9 +1022,11 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const {
9561022 const Elf_Shdr *First =
9571023 reinterpret_cast <const Elf_Shdr *>(base () + SectionTableOffset);
9581024
959- uintX_t NumSections = getHeader ().e_shnum ;
960- if (NumSections == 0 )
961- NumSections = First->sh_size ;
1025+ uintX_t NumSections = 0 ;
1026+ if (Expected<uint64_t > ShNumOrErr = getShNum ())
1027+ NumSections = *ShNumOrErr;
1028+ else
1029+ return ShNumOrErr.takeError ();
9621030
9631031 if (NumSections > UINT64_MAX / sizeof (Elf_Shdr))
9641032 return createError (" invalid number of sections specified in the NULL "
0 commit comments