[PATCH] D74286: [ELF] Respect output section alignment for AT> (non-null lmaRegion)
Fangrui Song via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 10 12:09:31 PST 2020
MaskRay added a comment.
In D74286#1866537 <https://reviews.llvm.org/D74286#1866537>, @psmith wrote:
> Do you happen to know how this relates to the ALIGN_WITH_INPUT linker script keyword? Apologies I've got stuck in an airport due to flight cancellations and can't check easily. I had thought that in BFD if you wanted InputSection alignment to affect LMA you needed to add ALIGN_WITH_INPUT.
>
> For example, taken from one of the few pages I could find that mentioned it: https://www.openstm32.org/forumthread4866
>
> don’t forget to use ALIGN_WITH_INPUT section attribute, or you’d have aligned sections slipping if previous section doesn’t completely fill the aligned size.
> ...
> /* The startup code goes first into FLASH */
> .isr_vector : ALIGN_WITH_INPUT
> {
> . = ALIGN(4);
> KEEP(*(.isr_vector)) /* Startup code */
> . = ALIGN(4);
> } >FLASH AT > AXIFLASH
>
>
> A brief look at BFD implies that LMA is only aligned for an OS that goes into a memory region if ALIGN_WITH_INPUT is true. I suspect that not aligning LMA can give some size savings, for example if at load time the OutputSections are byte-copied from their LMA to their aligned VMA then it doesn't matter if they are not aligned in LMA.
>
> If I'm right it may be worth following BFD here as if we make ALIGN_WITH_INPUT the default, which is safe, then we can't then introduce ALIGN_WITH_INPUT without risking breaking some programs.
Thanks for mentioning `ALIGN_WITH_INPUT`. I investigated it a bit. The following is my reconstruction of its logic after omitting unimportant things:
if (!bfd_is_abs_section (os->bfd_section)) {
if (os->addr_tree) // output_section_address is specified
section_alignment = exp_get_power (os->section_alignment, "section alignment");
else {
...
newdot = os->region->current;
/// Maximum of input section alignments
section_alignment = os->bfd_section->alignment_power;
}
if (section_alignment > 0) {
dotdelta = align_power (newdot, section_alignment) - newdot;
if (dotdelta != 0 && os->addr_tree)
einfo("warning: changing start of section %s by %lu bytes", ...);
}
os->bfd_section->vma = os->bfd_section->lma = newdot;
}
if (os->load_base) {
bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base");
os->bfd_section->lma = lma;
} else if (os->lma_region != NULL) {
bfd_vma lma = os->lma_region->current;
if (os->align_lma_with_input) // ALIGN_WITH_INPUT
lma += dotdelta;
else {
if (os->lma_region != os->region)
section_alignment = exp_get_power (os->section_alignment, "section alignment");
if (section_alignment > 0)
lma = align_power (lma, section_alignment);
}
os->bfd_section->lma = lma;
}
lld does not support `ALIGN_WITH_INPUT`.
I think BFD either uses maximum input section alignments (addr_tree == NULL), or the ALIGN value (addr_tree != NULL) (not investigated carefully). lld's `sec->alignment` is the maximum of both:
// LinkerScript.cpp
// Handle align (e.g. ".foo : ALIGN(16) { ... }").
if (sec->alignExpr)
sec->alignment =
std::max<uint32_t>(sec->alignment, sec->alignExpr().getValue());
I will do more investigations whether `max` can be dropped.
`ctx->lmaOffset = alignTo(mr->curPos, sec->alignment) - dot;` should work.
After this patch, we may also need a similar `changing start of section .foo by 15 bytes` warning.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D74286/new/
https://reviews.llvm.org/D74286
More information about the llvm-commits
mailing list