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 @@ -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 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 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)); + } } StringRef MappingTraits::validate(IO &IO, diff --git a/llvm/test/tools/llvm-readobj/elf-symbol-visibility.test b/llvm/test/tools/llvm-readobj/elf-symbol-visibility.test --- a/llvm/test/tools/llvm-readobj/elf-symbol-visibility.test +++ b/llvm/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 diff --git a/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml b/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/elf-symbol-stother.yaml @@ -0,0 +1,79 @@ +## Test how yaml2obj sets the value of a symbol's st_other fields. + +## Show that yaml2obj reports an error when using an STO_* flag that belongs +## 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 ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Symbols: + - Name: foo + Other: [ STO_MIPS_OPTIONAL ] + +## Test that STO_* can be used with their correct machine type. +## 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 the "StOther" field +## to 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) + +--- !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