This is an archive of the discontinued LLVM Phabricator instance.

[yaml2obj][obj2yaml] - Use a single "Other" field instead of "Other", "Visibility" and "StOther".
ClosedPublic

Authored by grimar on Aug 28 2019, 8:10 AM.

Details

Summary

Currenly we can encode the 'st_other' field of symbol using 3 fields.
'Visibility' is used to encode STV_* values.
'Other' is used to encode everything except the visibility, but it can't handle arbitrary values.
'StOther' is used to encode arbitrary values when 'Visibility'/'Other' are not helpfull enough.

'st_other' field is used to encode symbol visibility and platform-dependent
flags and values. Problem to encode it is that it consists of Visibility part (STV_* values)
which are enumeration values and the Other part, which is different and inconsistent.

For MIPS the Other part contains flags for all STO_MIPS_* values except STO_MIPS_MIPS16.
(Like comment in ELFDumper says: "Someones in their infinite wisdom decided to make
STO_MIPS_MIPS16 flag overlapped with other ST_MIPS_xxx flags."...)

And for PPC64 the Other part might actually encode any value.

This patch implements custom logic for handling the st_other and removes
'Visibility' and 'StOther' fields.

Here is an example of a new YAML style this patch allows:

- Name:  foo
  Other: [ 0x4 ]
- Name:  bar
  Other: [ STV_PROTECTED, 4 ]
- Name:  zed
  Other: [ STV_PROTECTED, STO_MIPS_OPTIONAL, 0xf8 ]

Diff Detail

Repository
rL LLVM

Event Timeline

grimar created this revision.Aug 28 2019, 8:10 AM
jhenderson added inline comments.Aug 28 2019, 9:16 AM
lib/ObjectYAML/ELFYAML.cpp
850 ↗(On Diff #217655)

I'm a bit confused with seeing an Optional being passed in without any check to see if it is None... but I see that was the case before.

857 ↗(On Diff #217655)

llvm::to_string I think is preferred.

877–880 ↗(On Diff #217655)

Do other yaml2obj/obj2yaml error messages end with a full stop?

Also, this error reporting method here makes me uncomfortable, since we're in the middle of a library. Is there any sensible way to propagate the error back up the stack?

897–899 ↗(On Diff #217655)

converting -> convert

I'm not sure what's "reversed" about the order, or what the bits have to do with anything?

910–911 ↗(On Diff #217655)

Why does MIPS16 need checking first? This comment should explain this point.

939–943 ↗(On Diff #217655)

Calling st_other/Other a bit field is incorrect, even for regular ELFs, since symbol visibility isn't a bit field (STV_PROTECTED is 0x3 for example).

I'd change the first sentence to say "It is usually a field that represents st_other and holds the symbol visibility."

Then I'd make the next sentence say "However, on some platforms, it can contain bit field and regular values, or even ..."

And the last sentence "Because of this, we need special handling."

test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

Is there any way straightforward way of forcing obj2yaml to produce output in the form Other: [ STV_HIDDEN ] etc?

test/tools/yaml2obj/elf-symbol-stother.yaml
72 ↗(On Diff #217655)

but the -> but a

Does this alternative syntax just come out automatically? Otherwise, I don't think we need to support both forms.

MaskRay added inline comments.Aug 28 2019, 9:27 PM
lib/ObjectYAML/ELFYAML.cpp
877–880 ↗(On Diff #217655)

In ELFYAML.h

  template <>
  struct MappingTraits<ELFYAML::Symbol> {
  ...
+   std::string Err;

In ELFYAML.cpp,

  StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
                                                   ELFYAML::Symbol &Symbol) {
+  if (!Err.empty())
+    return Err;
...
  }

-   NormalizedOther(IO &IO, Optional<uint8_t> Original) : YamlIO(IO) {
+  NormalizedOther(IO &IO, ELFYAML::Symbol &Sym) : YamlIO(IO) {

-  MappingNormalization<NormalizedOther, Optional<uint8_t>> Keys(IO, Symbol.Other);
+  MappingNormalization<NormalizedOther, ELFYAML::Symbol> Keys(IO, Symbol);

I haven't verified if this approach works, if it does, the error can be propagated back via validate().

MaskRay added inline comments.Aug 28 2019, 10:05 PM
lib/ObjectYAML/ELFYAML.cpp
857 ↗(On Diff #217655)

to_string returns an allocated string => Other's type can't be Optional<std::vector<StringRef>>

See below.

test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

Not straightforward but I managed to find an approach..

 struct NormalizedOther {
+  struct Piece {
+    std::string Str;
+  };
 ...
-  Optional<std::vector<StringRef>> Other;
+  Optional<std::vector<Piece>> Other;
   std::string UnknownFlagsHolder;
 };
 } // namespace
 
+template<>
+struct ScalarTraits<NormalizedOther::Piece> {
+  static void output(const NormalizedOther::Piece &Val, void *, raw_ostream &Out) {
+    Out << Val.Str;
+  }
+  static StringRef input(StringRef Scalar, void *, NormalizedOther::Piece &Val) {
+    Val.Str = Scalar.str();
+    return {};
+  }
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+template<> struct SequenceElementTraits<NormalizedOther::Piece> {
+  static const bool flow = true;
+};

This way obj2yaml will dump: Other: [ STV_HIDDEN ]

MaskRay added inline comments.Aug 28 2019, 10:08 PM
test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

Oh, I think StringRef should be fine.

+  struct Piece {
+    StringRef Str;
+  };
grimar marked an inline comment as done.Aug 29 2019, 2:53 AM
grimar added inline comments.
test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

Thanks a lot for this! I was wondering yesterday how to achieve it, but did not have chance to experiment with it.

My question is: do we want it? I.e it adds a bit of complexity to the code, but makes the output better.
I really like it the Other: [ STV_HIDDEN ] output style more, just want to check this point before addressing.

(I'll try to address this and all other comments today.)

jhenderson added inline comments.Aug 29 2019, 3:00 AM
test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

I'm happy either way. I think it's a little confusing that obj2yaml might produce different output to what looks good and would be written in all the tests, so I think the extra complexity is probably worth it. It's not too bad, I think?

MaskRay added inline comments.Aug 29 2019, 3:16 AM
test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

I also think the extra complexity is worth it.

grimar updated this revision to Diff 217855.Aug 29 2019, 6:01 AM
grimar marked 13 inline comments as done.
  • Addressed review comments.
lib/ObjectYAML/ELFYAML.cpp
850 ↗(On Diff #217655)

Yes. This constructor is only used by MappingNormalization for outputing, i.e. for obj2yaml.
So we always have a value here. I wasn't sure if it worth to add a comment or not, since it is by design of MappingNormalization class.
I added an assert with a comment.

857 ↗(On Diff #217655)

llvm::to_string I think is preferred.

I can't use it because it wants me to include the 'ScopedPrinter.h'. I do not think it worth doing for a single place?

to_string returns an allocated string => Other's type can't be Optional<std::vector<StringRef>>

That is why I had to use UnknownFlagsHolder, it holds the string allocated until 'NormalizedOther' is destroyed.

877–880 ↗(On Diff #217655)

Do other yaml2obj/obj2yaml error messages end with a full stop?

Yes.

Also, this error reporting method here makes me uncomfortable, since we're in the middle of a library. Is there any sensible way to propagate the error back up the stack?

This is a common problem, exit(1) is already used in a 3 more places in lib\ObjectYAML. Having that, what about if I suggest a follow-up refactoring(s) for all those places and this one?

897–899 ↗(On Diff #217655)

STV_*s have the following values:

STV_DEFAULT = 0,  // Visibility is specified by binding type
STV_INTERNAL = 1, // Defined by processor supplements
STV_HIDDEN = 2,   // Not visible to other components
STV_PROTECTED = 3 // Visible in other components but not preemptable

If we have, for example st_other == 3. We want to dump it as STV_PROTECTED and not as STV_INTERNAL + STV_HIDDEN.
So we need to handle the STV_PROTECTED first and because of that I had to list them as 3, 2, 1, i.e. in inversed order.

I updated the comment.

910–911 ↗(On Diff #217655)

I updated the comment.

939–943 ↗(On Diff #217655)

Thanks!

test/tools/obj2yaml/elf-symbol-visibility.yaml
14 ↗(On Diff #217655)

I was able to get rid of using struct (used LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece) declaration instead).
Seems it is a little bit simpler.

test/tools/yaml2obj/elf-symbol-stother.yaml
72 ↗(On Diff #217655)

Yes it is supported automatically. I added it to show we can use the syntax produced by obj2yaml, which was different before this diff.
Since now they have a similar syntax, I removed this test case completely.

MaskRay added inline comments.Aug 29 2019, 9:49 AM
lib/ObjectYAML/ELFYAML.cpp
877–880 ↗(On Diff #217655)

This is a common problem, exit(1) is already used in a 3 more places in lib\ObjectYAML.

Yes. I think obj2yaml functions have better error handling than yaml2obj function. It should be fine to fix the error propagating problem later.

962 ↗(On Diff #217855)

bit field -> bit fields

grimar updated this revision to Diff 218038.Aug 30 2019, 1:54 AM
grimar marked an inline comment as done.
  • Addressed review comment.
jhenderson added inline comments.Aug 30 2019, 2:55 AM
lib/ObjectYAML/ELFYAML.cpp
861 ↗(On Diff #218038)

outputting the YAML -> outputting YAML

862 ↗(On Diff #218038)

assumes a

932 ↗(On Diff #218038)

another -> any other
Delete the "So we add it first": you already talk about it being consumed first earlier.

grimar updated this revision to Diff 218059.Aug 30 2019, 3:06 AM
grimar marked 3 inline comments as done.
  • Addressed review comments.
MaskRay accepted this revision.Aug 30 2019, 3:19 AM
This revision is now accepted and ready to land.Aug 30 2019, 3:19 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptAug 30 2019, 6:39 AM
Herald added a subscriber: kristina. · View Herald Transcript