diff --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test --- a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test +++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test @@ -77,7 +77,6 @@ # MIPS-NEXT: Flags [ # MIPS-NEXT: SHF_ALLOC (0x2) # MIPS-NEXT: SHF_EXCLUDE (0x80000000) -# MIPS-NEXT: SHF_MASKPROC (0xF0000000) # MIPS-NEXT: SHF_MIPS_ADDR (0x40000000) # MIPS-NEXT: SHF_MIPS_GPREL (0x10000000) # MIPS-NEXT: SHF_MIPS_LOCAL (0x4000000) diff --git a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test --- a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test +++ b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test @@ -27,12 +27,10 @@ # RUN: llvm-readelf -S %t-mips.o | FileCheck --check-prefix=MIPS-GNU %s # MIPS-GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al -# MIPS-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00 Eop 0 0 0 +# MIPS-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00 op 0 0 0 # MIPS-LLVM: Flags [ (0xFF000000) # MIPS-LLVM-NEXT: SHF_EXCLUDE (0x80000000) -## FIXME: we should not print SHF_MASKPROC, because it is a mask value. -# MIPS-LLVM-NEXT: SHF_MASKPROC (0xF0000000) # MIPS-LLVM-NEXT: SHF_MIPS_ADDR (0x40000000) # MIPS-LLVM-NEXT: SHF_MIPS_GPREL (0x10000000) # MIPS-LLVM-NEXT: SHF_MIPS_LOCAL (0x4000000) @@ -55,7 +53,35 @@ Flags: [ SHF_MIPS_NODUPES, SHF_MIPS_NAMES, SHF_MIPS_LOCAL, SHF_MIPS_NOSTRIP, SHF_MIPS_GPREL, SHF_MIPS_MERGE, SHF_MIPS_ADDR, SHF_MIPS_STRING ] -# RUN: yaml2obj --docnum 3 %s -o %t-x86_64.o +## Test what we print when a MIPS object has the SHF_MIPS_STRING flag. +## SHF_MIPS_STRING has a value of 0x80000000, which matches the value of SHF_EXCLUDE. + +# RUN: yaml2obj --docnum 3 %s -o %t-mips-exclude.o +# RUN: llvm-readobj -S %t-mips-exclude.o | FileCheck --check-prefix=MIPS-EXCLUDE-LLVM %s +# RUN: llvm-readelf -S %t-mips-exclude.o | FileCheck --check-prefix=MIPS-EXCLUDE-GNU %s + +# MIPS-EXCLUDE-LLVM: Name: .mips +# MIPS-EXCLUDE-LLVM-NEXT: Type: SHT_PROGBITS +# MIPS-EXCLUDE-LLVM-NEXT: Flags [ (0x80000000) +# MIPS-EXCLUDE-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# MIPS-EXCLUDE-LLVM-NEXT: SHF_MIPS_STRING (0x80000000) +# MIPS-EXCLUDE-LLVM-NEXT: ] + +# MIPS-EXCLUDE-GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# MIPS-EXCLUDE-GNU: [ 1] .mips PROGBITS 00000000 000034 000000 00 E 0 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS +Sections: + - Name: .mips + Type: SHT_PROGBITS + Flags: [ SHF_MIPS_STRING ] + +# RUN: yaml2obj --docnum 4 %s -o %t-x86_64.o # RUN: llvm-readobj -S %t-x86_64.o | FileCheck --check-prefix=X86_64-LLVM %s # RUN: llvm-readelf -S %t-x86_64.o | FileCheck --check-prefix=X86_64-GNU %s @@ -77,7 +103,7 @@ Type: SHT_PROGBITS Flags: [ SHF_X86_64_LARGE ] -# RUN: yaml2obj --docnum 4 %s -o %t-arm.o +# RUN: yaml2obj --docnum 5 %s -o %t-arm.o # RUN: llvm-readobj -S %t-arm.o | FileCheck --check-prefix=ARM-LLVM %s # RUN: llvm-readelf -S %t-arm.o | FileCheck --check-prefix=ARM-GNU %s diff --git a/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test b/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/section-flags-os-proc.test @@ -0,0 +1,132 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readobj -S %t.o | FileCheck --check-prefix=OS-PROC-LLVM %s +# RUN: llvm-readelf -S %t.o | FileCheck --check-prefix=OS-PROC-GNU %s + +## Here we test how OS and processor specific flags are dumped. + +# OS-PROC-LLVM: Name: .os.flags.low +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0x100000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .os.flags.high +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xFE00000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .os.flags.mask +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xFF00000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .proc.flags.low +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0x10000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .proc.flags.high +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xE0000000) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .proc.flags.mask +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xF0000000) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .both.flags.low +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0x10100000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .both.flags.high +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xEFE00000) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .both.flags.mask +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xFFF00000) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .exclude +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0x80000000) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: ] +# OS-PROC-LLVM: Name: .all.possible +# OS-PROC-LLVM-NEXT: Type: SHT_PROGBITS +# OS-PROC-LLVM-NEXT: Flags [ (0xFFFFFFFF) +# OS-PROC-LLVM-NEXT: SHF_ALLOC (0x2) +# OS-PROC-LLVM-NEXT: SHF_COMPRESSED (0x800) +# OS-PROC-LLVM-NEXT: SHF_EXCLUDE (0x80000000) +# OS-PROC-LLVM-NEXT: SHF_EXECINSTR (0x4) +# OS-PROC-LLVM-NEXT: SHF_GROUP (0x200) +# OS-PROC-LLVM-NEXT: SHF_INFO_LINK (0x40) +# OS-PROC-LLVM-NEXT: SHF_LINK_ORDER (0x80) +# OS-PROC-LLVM-NEXT: SHF_MERGE (0x10) +# OS-PROC-LLVM-NEXT: SHF_OS_NONCONFORMING (0x100) +# OS-PROC-LLVM-NEXT: SHF_STRINGS (0x20) +# OS-PROC-LLVM-NEXT: SHF_TLS (0x400) +# OS-PROC-LLVM-NEXT: SHF_WRITE (0x1) +# OS-PROC-LLVM-NEXT: ] + +# OS-PROC-GNU: Section Headers: +# OS-PROC-GNU-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# OS-PROC-GNU-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# OS-PROC-GNU-NEXT: [ 1] .os.flags.low PROGBITS 0000000000000000 000040 000000 00 o 0 0 0 +# OS-PROC-GNU-NEXT: [ 2] .os.flags.high PROGBITS 0000000000000000 000040 000000 00 o 0 0 0 +# OS-PROC-GNU-NEXT: [ 3] .os.flags.mask PROGBITS 0000000000000000 000040 000000 00 o 0 0 0 +# OS-PROC-GNU-NEXT: [ 4] .proc.flags.low PROGBITS 0000000000000000 000040 000000 00 p 0 0 0 +# OS-PROC-GNU-NEXT: [ 5] .proc.flags.high PROGBITS 0000000000000000 000040 000000 00 p 0 0 0 +# OS-PROC-GNU-NEXT: [ 6] .proc.flags.mask PROGBITS 0000000000000000 000040 000000 00 p 0 0 0 +# OS-PROC-GNU-NEXT: [ 7] .both.flags.low PROGBITS 0000000000000000 000040 000000 00 op 0 0 0 +# OS-PROC-GNU-NEXT: [ 8] .both.flags.high PROGBITS 0000000000000000 000040 000000 00 op 0 0 0 +# OS-PROC-GNU-NEXT: [ 9] .both.flags.mask PROGBITS 0000000000000000 000040 000000 00 op 0 0 0 +# OS-PROC-GNU-NEXT: [10] .exclude PROGBITS 0000000000000000 000040 000000 00 E 0 0 0 +# OS-PROC-GNU-NEXT: [11] .all.possible PROGBITS 0000000000000000 000040 000000 00 WAXMSILOGTCopx 0 0 0 + +## Use an arbitrary EM_* machine type that does not have specific SHF_* OS/Processor +## flags to test what we dump when bits in the OS and processor specific ranges are set. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_NONE +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 + - Name: .proc.flags.low + Type: SHT_PROGBITS + ShFlags: 0x10000000 + - Name: .proc.flags.high + Type: SHT_PROGBITS + ShFlags: 0xE0000000 + - Name: .proc.flags.mask + Type: SHT_PROGBITS + ShFlags: 0xF0000000 + - Name: .both.flags.low + Type: SHT_PROGBITS + ShFlags: 0x10100000 + - Name: .both.flags.high + Type: SHT_PROGBITS + ShFlags: 0xEFE00000 + - Name: .both.flags.mask + Type: SHT_PROGBITS + ShFlags: 0xFFF00000 +## SHF_MASKPROC has a value of 0xf0000000, SHF_EXCLUDE has a value of +## 0x80000000. When SHF_EXCLUDE is mixed with other processor specific +## flags, GNU readelf does not necessarily print "E", because it handles +## the SHF_MASKPROC mask first. It only prints "E" when there are no other +## processor flags set. Check llvm-readelf output matches GNU. + - Name: .exclude + Type: SHT_PROGBITS + ShFlags: 0x80000000 +## Set all possible flags to test where we print 'o' and 'p' letters. + - Name: .all.possible + Type: SHT_PROGBITS + ShFlags: 0xFFFFFFFF diff --git a/llvm/test/tools/llvm-readobj/ELF/section-flags.test b/llvm/test/tools/llvm-readobj/ELF/section-flags.test --- a/llvm/test/tools/llvm-readobj/ELF/section-flags.test +++ b/llvm/test/tools/llvm-readobj/ELF/section-flags.test @@ -98,6 +98,11 @@ # LLVM-NEXT: SHF_EXCLUDE (0x80000000) # LLVM-NEXT: ] +# LLVM: Name: unknown +# LLVM-NEXT: Type: SHT_PROGBITS +# LLVM-NEXT: Flags [ (0xF0000) +# LLVM-NEXT: ] + # GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al # GNU: [ 1] allflags PROGBITS 0000000000000000 000040 000000 00 WAXMSILOGTCE 0 0 0 # GNU: [ 2] noflags PROGBITS 0000000000000000 000040 000000 00 0 0 0 @@ -113,6 +118,7 @@ # GNU: [12] tls PROGBITS 0000000000000000 000040 000000 00 T 0 0 0 # GNU: [13] compressed PROGBITS 0000000000000000 000040 000000 00 C 0 0 0 # GNU: [14] exclude PROGBITS 0000000000000000 000040 000000 00 E 0 0 0 +# GNU: [15] unknown PROGBITS 0000000000000000 000040 000000 00 x 0 0 0 --- !ELF FileHeader: @@ -166,3 +172,6 @@ - Name: exclude Type: SHT_PROGBITS Flags: [ SHF_EXCLUDE ] + - Name: unknown + Type: SHT_PROGBITS + ShFlags: 0x000f0000 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 @@ -1444,8 +1444,6 @@ ENUM_ENT(SHF_TLS, "T"), ENUM_ENT(SHF_COMPRESSED, "C"), ENUM_ENT(SHF_EXCLUDE, "E"), - ENUM_ENT(SHF_MASKOS, "o"), - ENUM_ENT(SHF_MASKPROC, "p"), }; static const EnumEntry ElfXCoreSectionFlags[] = { @@ -1477,34 +1475,51 @@ }; static std::string getGNUFlags(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. + // GNU readelf will not print "E" or "Ep" in this case, but will print just + // "p". It only will print "E" when no other processor flag is set. std::string Str; - for (auto Entry : ElfSectionFlags) { - uint64_t Flag = Entry.Value & Flags; - Flags &= ~Entry.Value; - switch (Flag) { - case ELF::SHF_WRITE: - case ELF::SHF_ALLOC: - case ELF::SHF_EXECINSTR: - case ELF::SHF_MERGE: - case ELF::SHF_STRINGS: - case ELF::SHF_INFO_LINK: - case ELF::SHF_LINK_ORDER: - case ELF::SHF_OS_NONCONFORMING: - case ELF::SHF_GROUP: - case ELF::SHF_TLS: - case ELF::SHF_COMPRESSED: - case ELF::SHF_EXCLUDE: - Str += Entry.AltName; - break; - default: - if (Flag & ELF::SHF_MASKOS) - Str += "o"; - else if (Flag & ELF::SHF_MASKPROC) - Str += "p"; - else if (Flag) - Str += "x"; + bool HasUnknownFlag = false; + bool HasOSFlag = false; + bool HasProcFlag = false; + while (Flags) { + // Take the least significant bit as a flag. + uint64_t Flag = Flags & -Flags; + Flags -= Flag; + + // Find the flag in the known flags list. + auto I = llvm::find_if(ElfSectionFlags, [=](const EnumEntry &E) { + return E.Value == Flag; + }); + if (I != std::end(ElfSectionFlags)) { + Str += I->AltName; + continue; + } + + // If we did not find a matching regular flag, then we deal with an OS + // specific flag, processor specific flag or an unknown flag. + if (Flag & ELF::SHF_MASKOS) { + HasOSFlag = true; + Flags &= ~ELF::SHF_MASKOS; + } else if (Flag & ELF::SHF_MASKPROC) { + HasProcFlag = true; + // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE + // bit if set so that it doesn't also get printed. + Flags &= ~ELF::SHF_MASKPROC; + } else { + HasUnknownFlag = true; } } + + // "o", "p" and "x" are printed last. + if (HasOSFlag) + Str += "o"; + if (HasProcFlag) + Str += "p"; + if (HasUnknownFlag) + Str += "x"; return Str; }