Index: llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/trunk/include/llvm/ObjectYAML/ELFYAML.h @@ -54,8 +54,6 @@ LLVM_YAML_STRONG_TYPEDEF(uint16_t, ELF_SHN) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STB) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STT) -LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STV) -LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STO) LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG) LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP) @@ -108,11 +106,6 @@ llvm::yaml::Hex64 Value; llvm::yaml::Hex64 Size; Optional Other; - - // This can be used to set any custom value for the st_other field - // when it is not possible to do so using the "Other" field, which only takes - // specific named constants. - Optional StOther; }; struct SectionOrType { @@ -402,16 +395,6 @@ }; template <> -struct ScalarEnumerationTraits { - static void enumeration(IO &IO, ELFYAML::ELF_STV &Value); -}; - -template <> -struct ScalarBitSetTraits { - static void bitset(IO &IO, ELFYAML::ELF_STO &Value); -}; - -template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFYAML::ELF_REL &Value); }; Index: llvm/trunk/include/llvm/Support/YAMLTraits.h =================================================================== --- llvm/trunk/include/llvm/Support/YAMLTraits.h +++ llvm/trunk/include/llvm/Support/YAMLTraits.h @@ -748,7 +748,7 @@ IO(void *Ctxt = nullptr); virtual ~IO(); - virtual bool outputting() = 0; + virtual bool outputting() const = 0; virtual unsigned beginSequence() = 0; virtual bool preflightElement(unsigned, void *&) = 0; @@ -842,7 +842,7 @@ Val = Val | ConstVal; } - void *getContext(); + void *getContext() const; void setContext(void *); template void mapRequired(const char *Key, T &Val) { @@ -1402,7 +1402,7 @@ std::error_code error(); private: - bool outputting() override; + bool outputting() const override; bool mapTag(StringRef, bool) override; void beginMapping() override; void endMapping() override; @@ -1549,7 +1549,7 @@ /// anyway. void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } - bool outputting() override; + bool outputting() const override; bool mapTag(StringRef, bool) override; void beginMapping() override; void endMapping() override; Index: llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/trunk/lib/ObjectYAML/ELFEmitter.cpp @@ -464,12 +464,7 @@ } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. Symbol.st_value = Sym.Value; - - if (Sym.Other) - Symbol.st_other = *Sym.Other; - else if (Sym.StOther) - Symbol.st_other = *Sym.StOther; - + Symbol.st_other = Sym.Other ? *Sym.Other : 0; Symbol.st_size = Sym.Size; } Index: llvm/trunk/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/ELFYAML.cpp +++ llvm/trunk/lib/ObjectYAML/ELFYAML.cpp @@ -11,12 +11,14 @@ //===----------------------------------------------------------------------===// #include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/WithColor.h" #include #include @@ -592,34 +594,6 @@ IO.enumFallback(Value); } -void ScalarEnumerationTraits::enumeration( - IO &IO, ELFYAML::ELF_STV &Value) { -#define ECase(X) IO.enumCase(Value, #X, ELF::X) - ECase(STV_DEFAULT); - ECase(STV_INTERNAL); - ECase(STV_HIDDEN); - ECase(STV_PROTECTED); -#undef ECase -} - -void ScalarBitSetTraits::bitset(IO &IO, - ELFYAML::ELF_STO &Value) { - const auto *Object = static_cast(IO.getContext()); - assert(Object && "The IO context is not initialized"); -#define BCase(X) IO.bitSetCase(Value, #X, ELF::X) - switch (Object->Header.Machine) { - case ELF::EM_MIPS: - BCase(STO_MIPS_OPTIONAL); - BCase(STO_MIPS_PLT); - BCase(STO_MIPS_PIC); - BCase(STO_MIPS_MICROMIPS); - break; - default: - break; // Nothing to do - } -#undef BCase -#undef BCaseMask -} void ScalarEnumerationTraits::enumeration( IO &IO, ELFYAML::ELF_RSS &Value) { @@ -863,31 +837,112 @@ IO.mapOptional("Offset", Phdr.Offset); } +LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece) + +template <> struct ScalarTraits { + static void output(const StOtherPiece &Val, void *, raw_ostream &Out) { + Out << Val; + } + static StringRef input(StringRef Scalar, void *, StOtherPiece &Val) { + Val = Scalar; + return {}; + } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; +template <> struct SequenceElementTraits { + static const bool flow = true; +}; + namespace { struct NormalizedOther { - NormalizedOther(IO &) {} - NormalizedOther(IO &, Optional Original) { - if (uint8_t Val = *Original & 0x3) - Visibility = Val; - if (uint8_t Val = *Original & ~0x3) - Other = Val; + NormalizedOther(IO &IO) : YamlIO(IO) {} + NormalizedOther(IO &IO, Optional Original) : YamlIO(IO) { + assert(Original && "This constructor is only used for outputting YAML and " + "assumes a non-empty Original"); + std::vector Ret; + const auto *Object = static_cast(YamlIO.getContext()); + for (std::pair &P : + getFlags(Object->Header.Machine).takeVector()) { + uint8_t FlagValue = P.second; + if ((*Original & FlagValue) != FlagValue) + continue; + *Original &= ~FlagValue; + Ret.push_back({P.first}); + } + + if (*Original != 0) { + UnknownFlagsHolder = std::to_string(*Original); + Ret.push_back({UnknownFlagsHolder}); + } + + if (!Ret.empty()) + Other = std::move(Ret); + } + + uint8_t toValue(StringRef Name) { + const auto *Object = static_cast(YamlIO.getContext()); + MapVector Flags = getFlags(Object->Header.Machine); + + auto It = Flags.find(Name); + if (It != Flags.end()) + return It->second; + + uint8_t Val; + if (to_integer(Name, Val)) + return Val; + + llvm::WithColor::error() + << "an unknown value is used for symbol's 'Other' field: " << Name + << ".\n"; + exit(1); } Optional denormalize(IO &) { - if (!Visibility && !Other) + if (!Other) return None; - uint8_t Ret = 0; - if (Visibility) - Ret |= *Visibility; - if (Other) - Ret |= *Other; + for (StOtherPiece &Val : *Other) + Ret |= toValue(Val); return Ret; } - Optional Visibility; - Optional Other; + // st_other field is used to encode symbol visibility and platform-dependent + // flags and values. This method returns a name to value map that is used for + // parsing and encoding this field. + MapVector getFlags(unsigned EMachine) { + MapVector Map; + // STV_* values are just enumeration values. We add them in a reversed order + // because when we convert the st_other to named constants when printing + // YAML we want to use a maximum number of bits on each step: + // when we have st_other == 3, we want to print it as STV_PROTECTED (3), but + // not as STV_HIDDEN (2) + STV_INTERNAL (1). + Map["STV_PROTECTED"] = ELF::STV_PROTECTED; + Map["STV_HIDDEN"] = ELF::STV_HIDDEN; + Map["STV_INTERNAL"] = ELF::STV_INTERNAL; + // STV_DEFAULT is used to represent the default visibility and has a value + // 0. We want to be able to read it from YAML documents, but there is no + // reason to print it. + if (!YamlIO.outputting()) + Map["STV_DEFAULT"] = ELF::STV_DEFAULT; + + // MIPS is not consistent. All of the STO_MIPS_* values are bit flags, + // except STO_MIPS_MIPS16 which overlaps them. It should be checked and + // consumed first when we print the output, because we do not want to print + // any other flags that have the same bits instead. + if (EMachine == ELF::EM_MIPS) { + Map["STO_MIPS_MIPS16"] = ELF::STO_MIPS_MIPS16; + Map["STO_MIPS_MICROMIPS"] = ELF::STO_MIPS_MICROMIPS; + Map["STO_MIPS_PIC"] = ELF::STO_MIPS_PIC; + Map["STO_MIPS_PLT"] = ELF::STO_MIPS_PLT; + Map["STO_MIPS_OPTIONAL"] = ELF::STO_MIPS_OPTIONAL; + } + return Map; + } + + const IO &YamlIO; + Optional> Other; + std::string UnknownFlagsHolder; }; } // end anonymous namespace @@ -902,22 +957,13 @@ IO.mapOptional("Value", Symbol.Value, Hex64(0)); IO.mapOptional("Size", Symbol.Size, Hex64(0)); - // Symbol's Other field is a bit special. It is a bit field that represents - // st_other and usually holds symbol visibility. When we write a YAML document - // we split it into two fields named "Visibility" and "Other". The latter one - // usually holds no value, and so is almost never printed, although some - // targets (e.g. MIPS) may use it to specify the named bits to set (e.g. - // STO_MIPS_OPTIONAL). For producing broken objects we want to allow writing - // any value to st_other. To do this we allow one more field called "StOther". - // If it is present in a YAML document, we set st_other to its integer value - // whatever it is. - // obj2yaml should not print 'StOther', it should print 'Visibility' and - // 'Other' fields instead. - assert(!IO.outputting() || !Symbol.StOther.hasValue()); - IO.mapOptional("StOther", Symbol.StOther); + // Symbol's Other field is a bit special. It is usually a field that + // represents st_other and holds the symbol visibility. However, on some + // platforms, it can contain bit fields and regular values, or even sometimes a + // crazy mix of them (see comments for NormalizedOther). Because of this, we + // need special handling. MappingNormalization> Keys(IO, Symbol.Other); - IO.mapOptional("Visibility", Keys->Visibility); IO.mapOptional("Other", Keys->Other); } @@ -927,8 +973,6 @@ return "Index and Section cannot both be specified for Symbol"; if (Symbol.NameIndex && !Symbol.Name.empty()) return "Name and NameIndex cannot both be specified for Symbol"; - if (Symbol.StOther && Symbol.Other) - return "StOther cannot be specified for Symbol with either Visibility or Other"; return StringRef(); } Index: llvm/trunk/lib/Support/YAMLTraits.cpp =================================================================== --- llvm/trunk/lib/Support/YAMLTraits.cpp +++ llvm/trunk/lib/Support/YAMLTraits.cpp @@ -40,7 +40,7 @@ IO::~IO() = default; -void *IO::getContext() { +void *IO::getContext() const { return Ctxt; } @@ -79,7 +79,7 @@ void Input::MapHNode::anchor() {} void Input::SequenceHNode::anchor() {} -bool Input::outputting() { +bool Input::outputting() const { return false; } @@ -440,7 +440,7 @@ Output::~Output() = default; -bool Output::outputting() { +bool Output::outputting() const { return true; } Index: llvm/trunk/test/tools/llvm-objcopy/ELF/localize-hidden.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/localize-hidden.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/localize-hidden.test @@ -34,7 +34,7 @@ Section: .text Value: 0x1008 Size: 8 - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] - Name: defaultGlobal Type: STT_FUNC Size: 8 @@ -46,14 +46,14 @@ Section: .data Value: 0x2006 Size: 2 - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Binding: STB_GLOBAL - Name: hiddenGlobalCommon Type: STT_OBJECT Index: SHN_COMMON Value: 0x2006 Size: 2 - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Binding: STB_GLOBAL - Name: undefGlobal Type: STT_FUNC @@ -64,21 +64,21 @@ Section: .data Value: 0x2002 Size: 2 - Visibility: STV_INTERNAL + Other: [ STV_INTERNAL ] Binding: STB_GLOBAL - Name: protectedGlobal Type: STT_OBJECT Section: .data Value: 0x2000 Size: 4 - Visibility: STV_PROTECTED + Other: [ STV_PROTECTED ] Binding: STB_GLOBAL - Name: hiddenWeak Type: STT_FUNC Section: .text Value: 0x1010 Size: 8 - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Binding: STB_WEAK #CHECK: Relocations [ Index: llvm/trunk/test/tools/llvm-objcopy/ELF/symbol-copy.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/symbol-copy.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/symbol-copy.test @@ -33,7 +33,7 @@ Section: .text Value: 0x1001 Size: 4 - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Binding: STB_GLOBAL - Name: foo Type: STT_FUNC @@ -45,7 +45,7 @@ Section: .data Value: 0x2002 Size: 2 - Visibility: STV_INTERNAL + Other: [ STV_INTERNAL ] Binding: STB_GLOBAL - Name: bar Type: STT_OBJECT Index: llvm/trunk/test/tools/llvm-objdump/elf-symbol-visibility.test =================================================================== --- llvm/trunk/test/tools/llvm-objdump/elf-symbol-visibility.test +++ llvm/trunk/test/tools/llvm-objdump/elf-symbol-visibility.test @@ -23,13 +23,13 @@ - Name: default Section: .text - Name: internal - Visibility: STV_INTERNAL + Other: [ STV_INTERNAL ] Section: .text - Name: hidden - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Section: .text - Name: protected - Visibility: STV_PROTECTED + Other: [ STV_PROTECTED ] Section: .text - Name: mips_pic Other: [ STO_MIPS_PIC ] Index: llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test +++ llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test @@ -39,17 +39,17 @@ Machine: EM_386 Symbols: - Name: default - Visibility: STV_DEFAULT + Other: [ STV_DEFAULT ] Binding: STB_GLOBAL - Name: internal - Visibility: STV_INTERNAL + Other: [ STV_INTERNAL ] Binding: STB_GLOBAL - Name: hidden - Visibility: STV_HIDDEN + Other: [ STV_HIDDEN ] Binding: STB_GLOBAL - Name: protected - Visibility: STV_PROTECTED + Other: [ STV_PROTECTED ] Binding: STB_GLOBAL - Name: other Binding: STB_GLOBAL - StOther: 4 + Other: [ 4 ] Index: llvm/trunk/test/tools/obj2yaml/elf-symbol-visibility.yaml =================================================================== --- llvm/trunk/test/tools/obj2yaml/elf-symbol-visibility.yaml +++ llvm/trunk/test/tools/obj2yaml/elf-symbol-visibility.yaml @@ -10,12 +10,12 @@ # CHECK-NEXT: Machine: EM_X86_64 # CHECK-NEXT: Symbols: # CHECK-NEXT: - Name: default -# CHECK-NEXT: - Name: internal -# CHECK-NEXT: Visibility: STV_INTERNAL -# CHECK-NEXT: - Name: hidden -# CHECK-NEXT: Visibility: STV_HIDDEN -# CHECK-NEXT: - Name: protected -# CHECK-NEXT: Visibility: STV_PROTECTED +# CHECK-NEXT: - Name: internal +# CHECK-NEXT: Other: [ STV_INTERNAL ] +# CHECK-NEXT: - Name: hidden +# CHECK-NEXT: Other: [ STV_HIDDEN ] +# CHECK-NEXT: - Name: protected +# CHECK-NEXT: Other: [ STV_PROTECTED ] # CHECK-NEXT: ... --- !ELF @@ -25,11 +25,11 @@ Type: ET_REL Machine: EM_X86_64 Symbols: - - Name: default - Visibility: STV_DEFAULT - - Name: internal - Visibility: STV_INTERNAL - - Name: hidden - Visibility: STV_HIDDEN - - Name: protected - Visibility: STV_PROTECTED + - Name: default + Other: [ STV_DEFAULT ] + - Name: internal + Other: [ STV_INTERNAL ] + - Name: hidden + Other: [ STV_HIDDEN ] + - Name: protected + Other: [ STV_PROTECTED ] Index: llvm/trunk/test/tools/yaml2obj/elf-symbol-stother.yaml =================================================================== --- llvm/trunk/test/tools/yaml2obj/elf-symbol-stother.yaml +++ llvm/trunk/test/tools/yaml2obj/elf-symbol-stother.yaml @@ -4,8 +4,7 @@ ## to a different machine type to what is specified by the YAML. # RUN: not yaml2obj --docnum=1 2>&1 %s | FileCheck %s --check-prefix=ERR -# ERR: error: unknown bit value -# ERR-NEXT: Other: [ STO_MIPS_OPTIONAL ] +# ERR: error: an unknown value is used for symbol's 'Other' field: STO_MIPS_OPTIONAL. --- !ELF FileHeader: @@ -38,63 +37,23 @@ - Name: foo Other: [ STO_MIPS_OPTIONAL ] -## Test that instead of using the "Other" field we can use the "StOther" field -## to set st_other to any arbitrary value. +## Test that we can mix named and unnamed constants and set +## st_other to any arbitrary value. # RUN: yaml2obj --docnum=3 %s > %t3 -# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=USE-STOTHER -# RUN: yaml2obj --docnum=4 %s > %t4 -# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=USE-STOTHER - -# USE-STOTHER: Name: foo -# USE-STOTHER: Other [ -# USE-STOTHER-SAME: (0x4) - -# USE-STOTHER: Name: bar -# USE-STOTHER: Other [ -# USE-STOTHER-SAME: (0xFF) +# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=VALUE ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_MIPS -Symbols: - - Name: foo - StOther: 4 - - Name: bar - StOther: 0xff - ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_386 -Symbols: - - Name: foo - StOther: 4 - - Name: bar - StOther: 0xff - -## Check we can't set StOther for a symbol if Visibility or Other is also specified. - -# RUN: not yaml2obj --docnum=5 2>&1 %s | FileCheck %s --check-prefix=ERR2 -# RUN: not yaml2obj --docnum=6 2>&1 %s | FileCheck %s --check-prefix=ERR2 - -# ERR2: error: StOther cannot be specified for Symbol with either Visibility or Other - ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_MIPS -Symbols: - - Name: foo - StOther: 0 - Other: [ STO_MIPS_OPTIONAL ] +# VALUE: Name: foo +# VALUE: Other [ +# VALUE-SAME: (0x4) + +# VALUE: Name: bar +# VALUE: Other [ +# VALUE-SAME: (0x7) + +# VALUE: Name: zed +# VALUE: Other [ +# VALUE-SAME: (0xFF) --- !ELF FileHeader: @@ -103,6 +62,9 @@ Type: ET_REL Machine: EM_MIPS Symbols: - - Name: foo - StOther: 0 - Visibility: STV_DEFAULT + - Name: foo + Other: [ 0x4 ] + - Name: bar + Other: [ STV_PROTECTED, 4 ] + - Name: zed + Other: [ STV_PROTECTED, STO_MIPS_OPTIONAL, 0xf8 ] Index: llvm/trunk/test/tools/yaml2obj/elf-symbol-visibility.yaml =================================================================== --- llvm/trunk/test/tools/yaml2obj/elf-symbol-visibility.yaml +++ llvm/trunk/test/tools/yaml2obj/elf-symbol-visibility.yaml @@ -3,7 +3,7 @@ # RUN: yaml2obj %s | llvm-readobj --symbols - | FileCheck --check-prefix OBJ %s # OBJ: Symbol { -# OBJ: Name: default (1) +# OBJ: Name: default1 # OBJ-NEXT: Value: 0x0 # OBJ-NEXT: Size: 0 # OBJ-NEXT: Binding: Local (0x0) @@ -12,7 +12,16 @@ # OBJ-NEXT: Section: Undefined (0x0) # OBJ-NEXT: } # OBJ-NEXT: Symbol { -# OBJ-NEXT: Name: internal (16) +# OBJ-NEXT: Name: default2 +# OBJ-NEXT: Value: 0x0 +# OBJ-NEXT: Size: 0 +# OBJ-NEXT: Binding: Local (0x0) +# OBJ-NEXT: Type: None (0x0) +# OBJ-NEXT: Other: 0 +# OBJ-NEXT: Section: Undefined (0x0) +# OBJ-NEXT: } +# OBJ-NEXT: Symbol { +# OBJ-NEXT: Name: internal # OBJ-NEXT: Value: 0x0 # OBJ-NEXT: Size: 0 # OBJ-NEXT: Binding: Local (0x0) @@ -23,7 +32,7 @@ # OBJ-NEXT: Section: Undefined (0x0) # OBJ-NEXT: } # OBJ-NEXT: Symbol { -# OBJ-NEXT: Name: hidden (9) +# OBJ-NEXT: Name: hidden # OBJ-NEXT: Value: 0x0 # OBJ-NEXT: Size: 0 # OBJ-NEXT: Binding: Local (0x0) @@ -34,7 +43,7 @@ # OBJ-NEXT: Section: Undefined (0x0) # OBJ-NEXT: } # OBJ-NEXT: Symbol { -# OBJ-NEXT: Name: protected (25) +# OBJ-NEXT: Name: protected # OBJ-NEXT: Value: 0x0 # OBJ-NEXT: Size: 0 # OBJ-NEXT: Binding: Local (0x0) @@ -52,11 +61,12 @@ Type: ET_REL Machine: EM_X86_64 Symbols: - - Name: default - Visibility: STV_DEFAULT - - Name: internal - Visibility: STV_INTERNAL - - Name: hidden - Visibility: STV_HIDDEN - - Name: protected - Visibility: STV_PROTECTED + - Name: default1 + - Name: default2 + Other: [ STV_DEFAULT ] + - Name: internal + Other: [ STV_INTERNAL ] + - Name: hidden + Other: [ STV_HIDDEN ] + - Name: protected + Other: [ STV_PROTECTED ]