This is an archive of the discontinued LLVM Phabricator instance.

[LLD][ELF]{ARM][AArch64] Add missing classof to patch sections.
ClosedPublic

Authored by peter.smith on Dec 10 2019, 1:42 AM.

Details

Summary

The code to insert patch section merges them with a comparison function that uses logic of the form:

return (isa<PatchSection>(a) && !isa<PatchSection>(b));

The PatchSections don't implement classof so this check fails if a is a PatchSection and b (is not a PatchSection, but is a SyntheticSection). This can result in relocations in the patches being out of range if the SyntheticSection is big, for example a ThunkSection with lots of thunks.

fixes part of pr44071 https://bugs.llvm.org/show_bug.cgi?id=44071 . Namely the relocation out of range errors. The convergence failures in pr44071 are a separate problem that will be addressed in a follow up patch.

The test case is a simulation of the Chromium build reported in pr44071 . It will fail with relocation out of range errors without classof implemented. It isn't easy to replicate the out of range errors, it needs large thunk sections and a large number of patches. These won't be seen in the vast majority of AArch64 programs. The Chromium build in pr44071 is fully instrumented.

I've not got a real world example of the Arm Cortex-A8 patch failing, but it has the same code sequence so I've implemented the classof function. It is possible to write a test case, but it is difficult to find the right conditions to actually make it fail, I've erred on submitting the fix without one to unblock the Chromium team running into the problem.

Diff Detail

Event Timeline

peter.smith created this revision.Dec 10 2019, 1:42 AM
grimar accepted this revision.Dec 10 2019, 2:02 AM

LGTM. Please wait for another approval(s) too.

This revision is now accepted and ready to land.Dec 10 2019, 2:02 AM
hans accepted this revision.Dec 10 2019, 3:43 AM
hans added a subscriber: hans.

lgtm

nit (patch title): "[LLD][ELF]{ARM]" -> ""[LLD][ELF][ARM]

MaskRay accepted this revision.Dec 10 2019, 9:18 AM

[LLD][ELF]{ARM][AArch64] Add missing classof to patch sections.

{ -> [

lld/ELF/ARMErrataFix.cpp
86

A C function named patch will reside in .text.patch when compiled with -ffunction-sections. This does not matter, because it is only used to break a tie:

auto mergeCmp = [](const InputSection *a, const InputSection *b) {
  if (a->outSecOff != b->outSecOff)
    return a->outSecOff < b->outSecOff;
  return isa<Patch657417Section>(a) && !isa<Patch657417Section>(b);
};
MaskRay added inline comments.Dec 10 2019, 5:29 PM
lld/test/ELF/aarch64-cortex-a53-843419-thunk-range.s
7

%t2 -> /dev/null

ruiu added a comment.Dec 10 2019, 5:47 PM

classof is an LLVM's way of implementing a dynamic casting, and the code is idiomatic -- we almost always dispatch only by an enum field. So this could be a bit confusing to those who are expecting that idiomatic mechanism? I wonder if it is better to define a new function instead of overloading classof.

classof is an LLVM's way of implementing a dynamic casting, and the code is idiomatic -- we almost always dispatch only by an enum field. So this could be a bit confusing to those who are expecting that idiomatic mechanism? I wonder if it is better to define a new function instead of overloading classof.

We already have such a code pattern

class EhFrameSection final : public SyntheticSection {
public:
  EhFrameSection();
  void writeTo(uint8_t *buf) override;
  void finalizeContents() override;
  bool isNeeded() const override { return !sections.empty(); }
  size_t getSize() const override { return size; }

  static bool classof(const SectionBase *d) {
    return SyntheticSection::classof(d) && d->name == ".eh_frame";
  }
lld/ELF/AArch64ErrataFix.cpp
385

Probably return SyntheticSection::classof(d) && d->name == ".text.patch";

See EhFrameSection::classof.

ruiu added a comment.Dec 10 2019, 6:02 PM

classof is an LLVM's way of implementing a dynamic casting, and the code is idiomatic -- we almost always dispatch only by an enum field. So this could be a bit confusing to those who are expecting that idiomatic mechanism? I wonder if it is better to define a new function instead of overloading classof.

We already have such a code pattern

class EhFrameSection final : public SyntheticSection {
public:
  EhFrameSection();
  void writeTo(uint8_t *buf) override;
  void finalizeContents() override;
  bool isNeeded() const override { return !sections.empty(); }
  size_t getSize() const override { return size; }

  static bool classof(const SectionBase *d) {
    return SyntheticSection::classof(d) && d->name == ".eh_frame";
  }

Ah, that's true. Not sure if it's a good pattern, but it seems it doesn't cause a confusion, so I'm fine with that.