diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1042,6 +1042,9 @@ SHF_MASKOS = 0x0ff00000, + // Solaris equivalent of SHF_GNU_RETAIN. + SHF_SUNW_NODISCARD = 0x00100000, + // Bits indicating processor-specific flags. SHF_MASKPROC = 0xf0000000, diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -720,6 +720,7 @@ llvm_unreachable("the section header table chunk must always be present"); } + ELF_ELFOSABI getOSAbi() const; unsigned getMachine() const; }; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -29,6 +29,8 @@ ELFYAML::Chunk::~Chunk() = default; namespace ELFYAML { +ELF_ELFOSABI Object::getOSAbi() const { return Header.OSABI; } + unsigned Object::getMachine() const { if (Header.Machine) return *Header.Machine; @@ -707,6 +709,14 @@ BCase(SHF_TLS); BCase(SHF_COMPRESSED); BCase(SHF_GNU_RETAIN); + switch (Object->getOSAbi()) { + case ELF::ELFOSABI_SOLARIS: + BCase(SHF_SUNW_NODISCARD); + break; + default: + // Nothing to do. + break; + } switch (Object->getMachine()) { case ELF::EM_ARM: BCase(SHF_ARM_PURECODE); diff --git a/llvm/test/tools/llvm-readobj/ELF/section-flags-solaris.test b/llvm/test/tools/llvm-readobj/ELF/section-flags-solaris.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/section-flags-solaris.test @@ -0,0 +1,36 @@ +## Here we test how Solaris specific flags are dumped. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readobj -S %t.o | FileCheck %s + +# CHECK: Name: .os.flags.low +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ (0x100000) +# CHECK-NEXT: SHF_SUNW_NODISCARD (0x100000) +# CHECK-NEXT: ] +# CHECK: Name: .os.flags.high +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ (0xFE00000) +# CHECK-NEXT: ] +# CHECK: Name: .os.flags.mask +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ (0xFF00000) +# CHECK-NEXT: SHF_SUNW_NODISCARD (0x100000) +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_SOLARIS + Type: ET_REL +Sections: + - Name: .os.flags.low + Type: SHT_PROGBITS + ShFlags: 0x00100000 + - Name: .os.flags.high + Type: SHT_PROGBITS + ShFlags: 0x0FE00000 + - Name: .os.flags.mask + Type: SHT_PROGBITS + ShFlags: 0x0FF00000 diff --git a/llvm/test/tools/obj2yaml/ELF/retain-section.yaml b/llvm/test/tools/obj2yaml/ELF/retain-section.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/retain-section.yaml @@ -0,0 +1,36 @@ +## Check handling of SHF_GNU_RETAIN and SHF_SUNW_NODISCARD section flags. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=GNU + +# GNU: Name: .gnu.retain +# GNU-NEXT: Type: SHT_PROGBITS +# GNU-NEXT: Flags: [ SHF_GNU_RETAIN ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .gnu.retain + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=SOLARIS + +# SOLARIS: Name: .sunw.nodiscard +# SOLARIS-NEXT: Type: SHT_PROGBITS +# SOLARIS-NEXT: Flags: [ SHF_SUNW_NODISCARD ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_SOLARIS + Type: ET_REL +Sections: + - Name: .sunw.nodiscard + Type: SHT_PROGBITS + Flags: [ SHF_SUNW_NODISCARD ] diff --git a/llvm/test/tools/yaml2obj/ELF/retain-section.yaml b/llvm/test/tools/yaml2obj/ELF/retain-section.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/retain-section.yaml @@ -0,0 +1,41 @@ +## Check how yaml2obj handles retain (SHF_GNU_RETAIN and +## SHF_SUNW_NODISCARD) section flags. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj --sections %t1 | FileCheck %s --check-prefix=GNU + +# GNU: Name: .gnu.retain +# GNU-NEXT: Type: SHT_PROGBITS (0x1) +# GNU-NEXT: Flags [ (0x200000) +# GNU-NEXT: SHF_GNU_RETAIN (0x200000) +# GNU-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .gnu.retain + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj --sections %t2 | FileCheck %s --check-prefix=SOLARIS + +# SOLARIS: Name: .sunw.nodiscard +# SOLARIS-NEXT: Type: SHT_PROGBITS (0x1) +# SOLARIS-NEXT: Flags [ (0x100000) +# SOLARIS-NEXT: SHF_SUNW_NODISCARD (0x100000) +# SOLARIS-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_SOLARIS + Type: ET_REL +Sections: + - Name: .sunw.nodiscard + Type: SHT_PROGBITS + Flags: [ SHF_SUNW_NODISCARD ] diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1242,10 +1242,16 @@ ENUM_ENT(SHF_GROUP, "G"), ENUM_ENT(SHF_TLS, "T"), ENUM_ENT(SHF_COMPRESSED, "C"), - ENUM_ENT(SHF_GNU_RETAIN, "R"), ENUM_ENT(SHF_EXCLUDE, "E"), }; +const EnumEntry ElfGNUSectionFlags[] = { + ENUM_ENT(SHF_GNU_RETAIN, "R"), +}; + +const EnumEntry ElfSolarisSectionFlags[] = { + ENUM_ENT(SHF_SUNW_NODISCARD, "R")}; + const EnumEntry ElfXCoreSectionFlags[] = { ENUM_ENT(XCORE_SHF_CP_SECTION, ""), ENUM_ENT(XCORE_SHF_DP_SECTION, "") @@ -1275,9 +1281,19 @@ }; static std::vector> -getSectionFlagsForTarget(unsigned EMachine) { +getSectionFlagsForTarget(unsigned EOSAbi, unsigned EMachine) { std::vector> Ret(std::begin(ElfSectionFlags), std::end(ElfSectionFlags)); + switch (EOSAbi) { + case ELFOSABI_SOLARIS: + Ret.insert(Ret.end(), std::begin(ElfSolarisSectionFlags), + std::end(ElfSolarisSectionFlags)); + break; + default: + Ret.insert(Ret.end(), std::begin(ElfGNUSectionFlags), + std::end(ElfGNUSectionFlags)); + break; + } switch (EMachine) { case EM_ARM: Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), @@ -1305,7 +1321,8 @@ return Ret; } -static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { +static std::string getGNUFlags(unsigned EOSAbi, unsigned EMachine, + uint64_t Flags) { // Here we are trying to build the flags string in the same way as GNU does. // It is not that straightforward. Imagine we have sh_flags == 0x90000000. // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. @@ -1316,7 +1333,7 @@ bool HasOSFlag = false; bool HasProcFlag = false; std::vector> FlagsList = - getSectionFlagsForTarget(EMachine); + getSectionFlagsForTarget(EOSAbi, EMachine); while (Flags) { // Take the least significant bit as a flag. uint64_t Flag = Flags & -Flags; @@ -3681,7 +3698,8 @@ Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6)); Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6)); Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2)); - Fields[7].Str = getGNUFlags(this->Obj.getHeader().e_machine, Sec.sh_flags); + Fields[7].Str = getGNUFlags(this->Obj.getHeader().e_ident[ELF::EI_OSABI], + this->Obj.getHeader().e_machine, Sec.sh_flags); Fields[8].Str = to_string(Sec.sh_link); Fields[9].Str = to_string(Sec.sh_info); Fields[10].Str = to_string(Sec.sh_addralign); @@ -6502,7 +6520,8 @@ int SectionIndex = -1; std::vector> FlagsList = - getSectionFlagsForTarget(this->Obj.getHeader().e_machine); + getSectionFlagsForTarget(this->Obj.getHeader().e_ident[ELF::EI_OSABI], + this->Obj.getHeader().e_machine); for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { DictScope SectionD(W, "Section"); W.printNumber("Index", ++SectionIndex);