This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Linkerscript: fix relocation offsets
AbandonedPublic

Authored by evgeny777 on Aug 16 2016, 8:38 AM.

Details

Reviewers
Wallbraker
ruiu
Summary

Now, when we assign scripted sections offsets in assignAddresses, we should also fix relocation offsets there, because input section offset is used to calculate relocation offset.
When linker script is used scanRelocs adds relocation entries which offsets begin from the start of input section. We fix them in fixStaticRelocs() and fixDynamicRelocs() by means of adding input section offset, so relocation offset becomes an offset from beginning of output section - the way it should be.

Diff Detail

Event Timeline

evgeny777 updated this revision to Diff 68191.Aug 16 2016, 8:38 AM
evgeny777 retitled this revision from to [ELF] Linkerscript: fix relocation offsets.
evgeny777 updated this object.
evgeny777 added a reviewer: ruiu.
evgeny777 set the repository for this revision to rL LLVM.
evgeny777 added a project: lld.
evgeny777 added subscribers: grimar, ikudrin, emaste and 2 others.

This is PR28976.

It's not very easy to write one due to the nature of the problem, but I'll think of it.

Wallbraker added a subscriber: Wallbraker.EditedAug 16 2016, 10:18 AM

This change gives me linking errors when I try to compile it on git head.

git: 722e076e650f0e43f2c31f32194507591a8d45c6
svn: 278819

Cheers, Jakob.

evgeny777 updated this revision to Diff 68222.Aug 16 2016, 10:57 AM
evgeny777 removed rL LLVM as the repository for this revision.

Jacob, I've added explicit template instantiations for DynamicReloc.
Please check, may be it works for you now.

Wallbraker accepted this revision.Aug 16 2016, 11:27 AM
Wallbraker added a reviewer: Wallbraker.

This commit compiles, fixes my test case and my full code now links correctly! Awesome thanks.

I'm not a stakeholder (nor do I know the code at all) in the code, so somebody else will need to sign off on the code itself.

Cheers, Jakob.

This revision is now accepted and ready to land.Aug 16 2016, 11:27 AM
silvas added a subscriber: silvas.Aug 16 2016, 5:06 PM

Together with fixes for the things mentioned in https://reviews.llvm.org/D23352#516156, with this patch applied we can link and boot the FreeBSD 10.3 kernel!

I'm not sure that this is the right implementation though. It seems weird that we have to fixup the relocations. Could you explain why we need to do that? Could we implement this in a more natural way?

Let me elaborate a little bit:
Roughly current workflow is like following:

Create output sections (createSections) -> Scan relocations (scanRelocs) -> Assign output section VA (assignAddresses)

The current implementation of scanRelocs assumes that output section sizes and input section offsets are already known. This is not always true when linker scripts are used.
For example this script creates output section .foo, which size depends on its own virtual address:

.foo : {
   *(.foo)
   . = ALIGN(0x1000); /* this line creates gap inside the output section .foo, which size depends on .foo virtual address */
   *(.bar)
}

This means that in case of linker script we only know exact size of the output and offset of the inputs after call to assignAddresses().
At the same time scanRelocs() cannot be called from assignAddresses(), because scanRelocs() creates and fills some predefined sections (.got, .rela.dyn, .got.plt),
and all sections must be created before assignAddresses() is called.

To my understanding some refactoring to the whole workflow is needed, which would probably look like this:

createSections() -> createRelocs() -> assignAddresses() -> assignRelocs()

This patch is just a quick fix for a specific problem.

evgeny777 updated this revision to Diff 68369.Aug 17 2016, 8:54 AM
evgeny777 edited edge metadata.

Fixed bug in fixDynamicRelocs()

ruiu edited edge metadata.Aug 17 2016, 2:16 PM

Eugene,

Thank you for your description. I agree that the order we compute offset is the cause of the problem. In scanRelocs, we compute a symbol offset for each symbol and assign it to a local variable Offset -- but that value may change if linker scripts are in use. That value is computed too early, and we want to do it lazily.

As to this patch, I'd refactor instead of applying a quick fix. It doesn't seem hard to do. For C.Relocations in scanRelocs, we are able to not store Offset to them because it can be computed from Body.

In D23565#518608, @ruiu wrote:

Eugene,

Thank you for your description. I agree that the order we compute offset is the cause of the problem. In scanRelocs, we compute a symbol offset for each symbol and assign it to a local variable Offset -- but that value may change if linker scripts are in use. That value is computed too early, and we want to do it lazily.

As to this patch, I'd refactor instead of applying a quick fix. It doesn't seem hard to do. For C.Relocations in scanRelocs, we are able to not store Offset to them because it can be computed from Body.

This makes sense, but it may have performance implications to get the offset later (at least more pointer chasing for data that we already had in cache in scanRelocs); it will need to be measured to make sure that we implement it without costing too much performance.