[ELF] Use SHF_SUNW_NODISCARD instead of SHF_GNU_RETAIN on Solaris

Instead of the GNU extension `SHF_GNU_RETAIN`, Solaris provides equivalent
functionality with `SHF_SUNW_NODISCARD`. This patch implements the necessary
support.

Tested on `sparcv9-sun-solaris2.11`, `amd64-pc-solaris2.11`, and
`x86_64-pc-linux-gnu`.

Differential Revision: https://reviews.llvm.org/D107955
This commit is contained in:
Rainer Orth 2022-02-23 15:41:43 +01:00
parent 03e6efb8c2
commit 42e391e4ca
7 changed files with 186 additions and 7 deletions

View File

@ -1042,6 +1042,9 @@ enum : unsigned {
SHF_MASKOS = 0x0ff00000,
// Solaris equivalent of SHF_GNU_RETAIN.
SHF_SUNW_NODISCARD = 0x00100000,
// Bits indicating processor-specific flags.
SHF_MASKPROC = 0xf0000000,

View File

@ -720,6 +720,7 @@ struct Object {
llvm_unreachable("the section header table chunk must always be present");
}
ELF_ELFOSABI getOSAbi() const;
unsigned getMachine() const;
};

View File

@ -29,6 +29,8 @@ namespace llvm {
ELFYAML::Chunk::~Chunk() = default;
namespace ELFYAML {
ELF_ELFOSABI Object::getOSAbi() const { return Header.OSABI; }
unsigned Object::getMachine() const {
if (Header.Machine)
return *Header.Machine;
@ -706,7 +708,14 @@ void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
BCase(SHF_GROUP);
BCase(SHF_TLS);
BCase(SHF_COMPRESSED);
BCase(SHF_GNU_RETAIN);
switch (Object->getOSAbi()) {
case ELF::ELFOSABI_SOLARIS:
BCase(SHF_SUNW_NODISCARD);
break;
default:
BCase(SHF_GNU_RETAIN);
break;
}
switch (Object->getMachine()) {
case ELF::EM_ARM:
BCase(SHF_ARM_PURECODE);

View File

@ -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

View File

@ -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 ]

View File

@ -0,0 +1,74 @@
## 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 ]
# RUN: not yaml2obj --docnum=3 %s 2>&1 | \
# RUN: FileCheck %s --check-prefix=SOLARIS-GNU-ERR
# SOLARIS-GNU-ERR: error: unknown bit value
# SOLARIS-GNU-ERR-NEXT: Flags: [ SHF_GNU_RETAIN ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
OSABI: ELFOSABI_SOLARIS
Type: ET_REL
Sections:
- Name: .sunw.retain
Type: SHT_PROGBITS
Flags: [ SHF_GNU_RETAIN ]
# RUN: not yaml2obj --docnum=4 %s 2>&1 | \
# RUN: FileCheck %s --check-prefix=GNU-SOLARIS-ERR
# GNU-SOLARIS-ERR: error: unknown bit value
# GNU-SOLARIS-ERR-NEXT: Flags: [ SHF_SUNW_NODISCARD ]
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Sections:
- Name: .gnu.nodiscard
Type: SHT_PROGBITS
Flags: [ SHF_SUNW_NODISCARD ]

View File

@ -1242,10 +1242,17 @@ const EnumEntry<unsigned> ElfSectionFlags[] = {
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<unsigned> ElfGNUSectionFlags[] = {
ENUM_ENT(SHF_GNU_RETAIN, "R")
};
const EnumEntry<unsigned> ElfSolarisSectionFlags[] = {
ENUM_ENT(SHF_SUNW_NODISCARD, "R")
};
const EnumEntry<unsigned> ElfXCoreSectionFlags[] = {
ENUM_ENT(XCORE_SHF_CP_SECTION, ""),
ENUM_ENT(XCORE_SHF_DP_SECTION, "")
@ -1275,9 +1282,19 @@ const EnumEntry<unsigned> ElfX86_64SectionFlags[] = {
};
static std::vector<EnumEntry<unsigned>>
getSectionFlagsForTarget(unsigned EMachine) {
getSectionFlagsForTarget(unsigned EOSAbi, unsigned EMachine) {
std::vector<EnumEntry<unsigned>> 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 +1322,8 @@ getSectionFlagsForTarget(unsigned EMachine) {
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 +1334,7 @@ static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) {
bool HasOSFlag = false;
bool HasProcFlag = false;
std::vector<EnumEntry<unsigned>> FlagsList =
getSectionFlagsForTarget(EMachine);
getSectionFlagsForTarget(EOSAbi, EMachine);
while (Flags) {
// Take the least significant bit as a flag.
uint64_t Flag = Flags & -Flags;
@ -3682,7 +3700,8 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionHeaders() {
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);
@ -6503,7 +6522,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
int SectionIndex = -1;
std::vector<EnumEntry<unsigned>> 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);