This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Change way we place non-scripted (orphan) sections
ClosedPublic

Authored by evgeny777 on Oct 6 2016, 7:33 AM.

Details

Summary

Currently implemented algorithm doesn't work well for me, because my linker scripts put RW or RWX sections first. For example

SECTIONS {
   .rwx : { *(.rwx) } /* RWX sections go here */
   .ro : { *(.ro) } /* RO sections go after RWX */
}

If there is any RO orphan section in linked image it will be placed before RWX sections and produce extra PT_LOAD. This doesn't match nor gold nor ld behavior.
The approach I'm currently using (and one this patch implements) is to first find sections which can share same PT_LOAD with some orphan section. If such sections have been found they are compared with orphan section using compareSectionsNonScript<ELFT>() and best insertion position is chosen. If no section has equal access attributes then insertion position is found using current algorithm (insert before first section which is greater in sort order).

I don't know if this is right way to go, but this works much better for me (I don't have to edit scripts and results match ld/gold)

Diff Detail

Repository
rL LLVM

Event Timeline

evgeny777 updated this revision to Diff 73794.Oct 6 2016, 7:33 AM
evgeny777 retitled this revision from to [ELF] Change way we place non-scripted (orphan) sections.
evgeny777 updated this object.
evgeny777 added reviewers: ruiu, rafael.
evgeny777 set the repository for this revision to rL LLVM.
evgeny777 added a project: lld.
evgeny777 added subscribers: grimar, ikudrin, llvm-commits.

@emaste might want to confirm this doesn't break linking the FreeBSD kernel.

rafael added inline comments.Oct 6 2016, 10:12 AM
ELF/Writer.cpp
750 ↗(On Diff #73794)

This needs to be updated.

772 ↗(On Diff #73794)

This is a bit hard to read. Maybe you can write a lambda that given two candidates decides which one is better for placing the orphan. That way this would be

std:: max_element(I, NonScriptI, [&] (OutputSectionBase<ELFT> *A, OutputSectionBase<ELFT> *B) {
...
}

And if I understand correctly, the logic would be

  • Prefer A/B if one can share a PT_LOAD.
  • Prefer A/B if the element compares less than one.
  • Otherwise prefer the last one.
evgeny777 added inline comments.Nov 1 2016, 9:12 AM
ELF/Writer.cpp
772 ↗(On Diff #73794)

I don't think max_element makes sense here, because this code is about finding best insertion position, not any kind of maximum.
This newer code implements two passes on OutputSections: first pass is done on subset of sections which can share PT_LOAD with NonScriptI and second pass is done on all sections. Hope it's easier to understand now.

evgeny777 updated this revision to Diff 76574.Nov 1 2016, 9:12 AM
evgeny777 removed rL LLVM as the repository for this revision.

Two-pass approach

evgeny777 updated this revision to Diff 77031.Nov 7 2016, 6:47 AM

Rebased + modified test case orphan.s

This revision was automatically updated to reflect the committed changes.