Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -888,9 +888,25 @@ IO.mapOptional("Binding", Symbol.Binding, ELFYAML::ELF_STB(0)); IO.mapOptional("Value", Symbol.Value, Hex64(0)); IO.mapOptional("Size", Symbol.Size, Hex64(0)); - MappingNormalization Keys(IO, Symbol.Other); - IO.mapOptional("Visibility", Keys->Visibility, ELFYAML::ELF_STV(0)); - IO.mapOptional("Other", Keys->Other, ELFYAML::ELF_STO(0)); + + // Symbol's Other field is a bit special. It is a bit field that represents + // st_other and usually helds symbol visibility. When we write a YAML + // we split it into the two fields named "Visibility" and "Other". The last + // one usually holds no value, and so almost never printed. Though some + // targets (e.g. MIPS) may use it to specify the named bits to set (e.g. + // STO_MIPS_OPTIONAL). For producing the broken objects we want to allow + // writing any values to st_other. To do this we allow one more field + // called "StOther". If it is present in a YAML, we set st_other as an + // integer, ignoring the fact it is actually a bit field. + 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)); + } } StringRef MappingTraits::validate(IO &IO, Index: test/tools/llvm-readobj/elf-symbol-visibility.test =================================================================== --- test/tools/llvm-readobj/elf-symbol-visibility.test +++ test/tools/llvm-readobj/elf-symbol-visibility.test @@ -1,11 +1,9 @@ # Show that llvm-readobj prints the symbol visibility where recognised, or # something sensible when not, for both GNU and LLVM output. -# Use --dyn-symbols because it is only possible to hand-craft symbols with -# non-standard st_other values for .dynsym. # RUN: yaml2obj %s > %t -# RUN: llvm-readobj --symbols --dyn-symbols %t | FileCheck %s --check-prefix=LLVM -# RUN: llvm-readelf --symbols --dyn-symbols %t | FileCheck %s --check-prefix=GNU +# RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf --symbols %t | FileCheck %s --check-prefix=GNU # LLVM: Name: default # LLVM: Other: 0 @@ -27,11 +25,11 @@ # FIXME - the "other" symbol should print something indicating its non-zero st_other value. # See https://bugs.llvm.org/show_bug.cgi?id=40785. -# GNU: DEFAULT {{.*}} other # GNU: DEFAULT {{.*}} default # GNU-NEXT: INTERNAL {{.*}} internal # GNU-NEXT: HIDDEN {{.*}} hidden # GNU-NEXT: PROTECTED {{.*}} protected +# GNU-NEXT: DEFAULT {{.*}} other !ELF FileHeader: @@ -39,18 +37,6 @@ Data: ELFDATA2LSB Type: ET_REL Machine: EM_386 -Sections: - - Name: .dynstr - Type: SHT_STRTAB - #\0other\0 - Content: "006f7468657200" - - Name: .dynsym - Type: SHT_DYNSYM - Link: .dynstr - EntSize: 16 - # Null symbol - # Symbol with st_name = 1, st_other = 0x4 - Content: "0000000000000000000000000000000001000000000000000000000000040000" Symbols: - Name: default Visibility: STV_DEFAULT @@ -64,3 +50,6 @@ - Name: protected Visibility: STV_PROTECTED Binding: STB_GLOBAL + - Name: other + Binding: STB_GLOBAL + StOther: 4 Index: test/tools/yaml2obj/elf-symbol-stother.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/elf-symbol-stother.yaml @@ -0,0 +1,83 @@ +## Test how yaml2obj sets the values to symbol's st_other fields. + +## Show that yaml2obj report an error when STO_* flag that belongs to a different +## machine type is used in 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 ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Symbols: + - Name: foo + Other: [ STO_MIPS_OPTIONAL ] + +## Test there is no problem to use STO_* flag when a machine type is correct. +## We use the same YAML as above, but with a change of machine type. + +# RUN: yaml2obj --docnum=2 %s > %t2 +# RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=USE-OTHER + +# USE-OTHER: Name: foo +# USE-OTHER: Other [ (0x4) +# USE-OTHER-NEXT: STO_MIPS_OPTIONAL (0x4) +# USE-OTHER-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS +Symbols: + - Name: foo + Other: [ STO_MIPS_OPTIONAL ] + +## Test that instead of using the "Other" field we can use "StOther" field to +## set any arbitrary value to st_other. + +# RUN: yaml2obj --docnum=3 %s > %t3 +# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefixes=USE-STOTHER,MIPS +# RUN: yaml2obj --docnum=4 %s > %t4 +# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=USE-STOTHER + +# USE-STOTHER: Name: foo +# USE-STOTHER: Other [ (0x4) +# MIPS-NEXT: STO_MIPS_OPTIONAL (0x4) +# USE-STOTHER-NEXT: ] +# USE-STOTHER: Name: bar +# USE-STOTHER: Other [ (0xFF) +# MIPS-NEXT: STO_MIPS_MIPS16 (0xF0) +# MIPS-NEXT: STO_MIPS_OPTIONAL (0x4) +# MIPS-NEXT: STO_MIPS_PLT (0x8) +# USE-STOTHER-NEXT: STV_PROTECTED (0x3) +# USE-STOTHER-NEXT: ] + +--- !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