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.
Details
- Reviewers
Wallbraker ruiu
Diff Detail
Event Timeline
It's not very easy to write one due to the nature of the problem, but I'll think of it.
This change gives me linking errors when I try to compile it on git head.
git: 722e076e650f0e43f2c31f32194507591a8d45c6
svn: 278819
Cheers, Jakob.
Jacob, I've added explicit template instantiations for DynamicReloc.
Please check, may be it works for you now.
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.
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.
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.