From b9f3ea3e1c7d5e1ddc0f187b3772527f98af3143 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Wed, 18 Jul 2018 08:44:38 +0000 Subject: [PATCH] [ELF] - Do not produce broken output when amount of sections is > ~65k This is a part of ttps://bugs.llvm.org//show_bug.cgi?id=38119 We produce broken ELF header now when the number of output sections is >= SHN_LORESERVE (0xff00). ELF spec says (http://www.sco.com/developers/gabi/2003-12-17/ch4.eheader.html): e_shnum: If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), this member has the value zero and the actual number of section header table entries is contained in the sh_size field of the section header at index 0. (Otherwise, the sh_size member of the initial entry contains 0.) e_shstrndx If the section name string table section index is greater than or equal to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff) and the actual index of the section name string table section is contained in the sh_link field of the section header at index 0. (Otherwise, the sh_link member of the initial entry contains 0.) We did not set these fields correctly earlier. The patch fixes the issue. Differential revision: https://reviews.llvm.org/D49371 llvm-svn: 337363 --- lld/ELF/Writer.cpp | 26 ++++++++-- lld/test/ELF/relocatable-many-sections.s | 85 ++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 lld/test/ELF/relocatable-many-sections.s diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index f3ddb4c..f141eae 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2242,8 +2242,6 @@ template void Writer::writeHeader() { EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = OutputSections.size() + 1; - EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); @@ -2264,8 +2262,30 @@ template void Writer::writeHeader() { ++HBuf; } - // Write the section header table. Note that the first table entry is null. + // Write the section header table. + // + // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum + // and e_shstrndx fields. When the value of one of these fields exceeds + // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and + // use fields in the section header at index 0 to store + // the value. The sentinel values and fields are: + // e_shnum = 0, SHdrs[0].sh_size = number of sections. + // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); + size_t Num = OutputSections.size() + 1; + if (Num >= SHN_LORESERVE) + SHdrs->sh_size = Num; + else + EHdr->e_shnum = Num; + + uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex; + if (StrTabIndex >= SHN_LORESERVE) { + SHdrs->sh_link = StrTabIndex; + EHdr->e_shstrndx = SHN_XINDEX; + } else { + EHdr->e_shstrndx = StrTabIndex; + } + for (OutputSection *Sec : OutputSections) Sec->writeHeaderTo(++SHdrs); } diff --git a/lld/test/ELF/relocatable-many-sections.s b/lld/test/ELF/relocatable-many-sections.s new file mode 100644 index 0000000..d98c75b --- /dev/null +++ b/lld/test/ELF/relocatable-many-sections.s @@ -0,0 +1,85 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o +# RUN: ld.lld -r %t.o -o %t +# RUN: llvm-readobj -file-headers %t | FileCheck %s + +## Check we are able to emit a valid ELF header when +## sections amount is greater than SHN_LORESERVE. +# CHECK: ElfHeader { +# CHECK: SectionHeaderCount: 0 (65541) +# CHECK-NEXT: StringTableSectionIndex: 65535 (65539) + +.macro gen_sections4 x + .section a\x + .section b\x + .section c\x + .section d\x +.endm + +.macro gen_sections8 x + gen_sections4 a\x + gen_sections4 b\x +.endm + +.macro gen_sections16 x + gen_sections8 a\x + gen_sections8 b\x +.endm + +.macro gen_sections32 x + gen_sections16 a\x + gen_sections16 b\x +.endm + +.macro gen_sections64 x + gen_sections32 a\x + gen_sections32 b\x +.endm + +.macro gen_sections128 x + gen_sections64 a\x + gen_sections64 b\x +.endm + +.macro gen_sections256 x + gen_sections128 a\x + gen_sections128 b\x +.endm + +.macro gen_sections512 x + gen_sections256 a\x + gen_sections256 b\x +.endm + +.macro gen_sections1024 x + gen_sections512 a\x + gen_sections512 b\x +.endm + +.macro gen_sections2048 x + gen_sections1024 a\x + gen_sections1024 b\x +.endm + +.macro gen_sections4096 x + gen_sections2048 a\x + gen_sections2048 b\x +.endm + +.macro gen_sections8192 x + gen_sections4096 a\x + gen_sections4096 b\x +.endm + +.macro gen_sections16384 x + gen_sections8192 a\x + gen_sections8192 b\x +.endm + +gen_sections16384 a +gen_sections16384 b +gen_sections16384 c +gen_sections16384 d + +.global _start +_start: -- 2.7.4