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 @@ -107,7 +107,12 @@ ELF_STB Binding; llvm::yaml::Hex64 Value; llvm::yaml::Hex64 Size; - uint8_t Other; + 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 { diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -464,7 +464,12 @@ } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. Symbol.st_value = Sym.Value; - Symbol.st_other = Sym.Other; + + if (Sym.Other) + Symbol.st_other = *Sym.Other; + else if (Sym.StOther) + Symbol.st_other = *Sym.StOther; + Symbol.st_size = Sym.Size; } 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 @@ -866,15 +866,28 @@ namespace { struct NormalizedOther { - NormalizedOther(IO &) - : Visibility(ELFYAML::ELF_STV(0)), Other(ELFYAML::ELF_STO(0)) {} - NormalizedOther(IO &, uint8_t Original) - : Visibility(Original & 0x3), Other(Original & ~0x3) {} + NormalizedOther(IO &) {} + NormalizedOther(IO &, Optional Original) { + if (uint8_t Val = *Original & 0x3) + Visibility = Val; + if (uint8_t Val = *Original & ~0x3) + Other = Val; + } + + Optional denormalize(IO &) { + if (!Visibility && !Other) + return None; - uint8_t denormalize(IO &) { return Visibility | Other; } + uint8_t Ret = 0; + if (Visibility) + Ret |= *Visibility; + if (Other) + Ret |= *Other; + return Ret; + } - ELFYAML::ELF_STV Visibility; - ELFYAML::ELF_STO Other; + Optional Visibility; + Optional Other; }; } // end anonymous namespace @@ -896,17 +909,16 @@ // 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 that integer, - // ignoring the other fields. - Optional Other; - IO.mapOptional("StOther", Other); - if (Other) { - Symbol.Other = *Other; - } else { - MappingNormalization Keys(IO, Symbol.Other); - IO.mapOptional("Visibility", Keys->Visibility, ELFYAML::ELF_STV(0)); - IO.mapOptional("Other", Keys->Other, ELFYAML::ELF_STO(0)); - } + // 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); + MappingNormalization> Keys(IO, + Symbol.Other); + IO.mapOptional("Visibility", Keys->Visibility); + IO.mapOptional("Other", Keys->Other); } StringRef MappingTraits::validate(IO &IO, @@ -915,6 +927,8 @@ 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(); } diff --git a/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml b/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml --- a/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml +++ b/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml @@ -77,3 +77,32 @@ 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 ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS +Symbols: + - Name: foo + StOther: 0 + Visibility: STV_DEFAULT