This is an archive of the discontinued LLVM Phabricator instance.

[ARM] [LLD] Add support for SHF_LINK_ORDER flag to ARM Target
AbandonedPublic

Authored by peter.smith on Aug 30 2016, 8:48 AM.

Details

Summary

I've added the folks implementing ldscripts to the review list as SHF_LINK_ORDER does have some impact, particularly for ld -r. I also ran into a couple of problems whilst testing against ldscripts. In particular ld -r with a linker script isn't working at all right now. Apologies for abusing this review to communicate, I thought the surrounding context might be useful. I'm happy to restate in llvm-dev or PRs if you'd prefer.

Sections with the SHF_LINK_ORDER flag set have an ordering dependency on the Section identified by the sh_link field. The wording in the ELF specification is not especially clear but the intent behind the only known use case is. SHF_LINK_ORDER is used to build a table of exception table sections in order of ascending address such that it can be binary searched by the exceptions runtime based on the address the exception was thrown.

Note:
The known uses of the SHF_LINK_ORDER flag is limited to ARM and Itanium exception table index sections .ARM.exidx and .IA_64.unwind. As far as I can tell it is not possible with clang and gcc to create arbitrary sections with the SHF_LINK_ORDER flag set, the exception table sections are created by the assembler in response to directives such as .cantunwind.

References:

ELF Specification: http://www.sco.com/developers/gabi/latest/ch4.sheader.html
ARM EHABI: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
Itanium ABI: http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-IA64/LSB-Core-IA64/sections.html

I have used the limited scope of sections that lld will encounter to simplify the implementation. A similar approach is taken by Gold, which doesn't seem to handle SHF_LINK_ORDER generally, instead it makes a special case of .ARM.exidx sections. I've put the limitations in Review questions.

Review questions:
Should SHF_LINK_ORDER support be restricted to Target ARM?
SHF_LINK_ORDER is in the generic ELF specification, but the only known ABIs that use it are ARM and Itanium, both for exception index tables. As the implementation has a performance penalty I've restricted it to the ARM target.

Is it acceptable to reorder the SHF_LINK_ORDER sections post address assignment?
The sorting of the InputSections is currently done after addresses are assigned to OutputSections. This isn't ideal as in the general case reordering InputSections could invalidate the dynamic relocations created by ScanRelocations. It also prevents an permitted size optimization to .ARM.exidx sections that compresses identical adjacent table entries. In practice this can't happen in any ABI conforming image due to the properties of .ARM.exidx (All .ARM.exidx sections must be contiguous, all have 4-byte alignment and a size that is a multiple of 8, so interchanging their order won't affect anything else).

In an ideal world the reordering of SHF_LINK_ORDER sections would be done as soon as the order of Output and Input Sections is known but prior to any function that depends on precise addresses. However there isn't a simple way of getting the section order information out of ldscripts early without side-effecting the image. See ldscript issues.

Is the support for ld -r robust enough?
For relocatable links each OutputSection with a SHF_LINK_ORDER flag can only link to a single OutputSection. The current implementation takes advantage of the naming convention of the ABI for .ARM.exidx sections. Supporting arbitrary names for SHF_LINK_ORDER sections will need a more complex solution based on following shf_link.

Linker Script issues:
ld -r with a linker script isn't working at all right now. The default createSections() calls assignOffsets(), if a script is used with -r then neither assignOffsets or assignAddresses() is called so all the output section headers have size 0. I think a possible fix is to use assignAddresses() with orphan OutputSections given a base address of 0.

Sorting OutputSections and calling LinkerScript::assignAddresses() has side-effects. If assignAddresses() is called before addPredefineSections() and in its normal place after addPredefineSections() then any user-defined section with a name like .shstrtab (in test linkersctipt-sections.s) has an OutputSection created for it and hence gains an index. This sorts it before all the predefined sections when the second sort is performed after addPredefineSections(). More seriously assignOffsets() is called twice on some section types which will alter their size as sh_size will be non-zero from the first call to assignAddresses(). I considered writing some code to unpick the side-effects but instead went for the late resolution of SHF_LINK_ORDER. I think it would be very useful to have a way of incrementally updating the output and input section addresses when using ldscripts. For example consider long branch thunks, to calculate that a thunk is needed we need the address of source and destination, adding a thunk affects the addresses.

Diff Detail

Event Timeline

peter.smith retitled this revision from to [ARM] [LLD] Add support for SHF_LINK_ORDER flag to ARM Target.
peter.smith updated this object.
peter.smith added a subscriber: llvm-commits.
ruiu edited edge metadata.Aug 30 2016, 11:17 AM

We are doing something similar for Windows in which exception tables need to be sorted to allow runtime to binary-search it. Because COFF does not have a generic mechanism to enforce it, but rather it requires linkers sort exception table contents, we do it as a post-process. That is, we link everything normally, and then sort the output file buffer contents if the exception table is.

That is less generic mechanism, but I think I like it more than what ELF requires us do. It's straightforward, easy to understand and sufficient. On the other hand, SHF_LINK_ORDER would raise a lot of potential issues with other features of the linker as you described in this patch comment.

So I'm wondering if this works: after everything is done, but just before the buffer is committed to disk, find ".ARM.exidx" output section. If the section exists, sort the contents, assuming that the section contains an exception index table.

grimar edited edge metadata.Aug 31 2016, 1:21 AM

About linkerscript and -r combination: I don't think we did something for it yet, so I am not surprised it is completely broken atm.

peter.smith abandoned this revision.Aug 31 2016, 1:32 AM

Thanks both for the comments. I'll see what I can do if only the exception table use case is supported.