[llvm-dev] Any LLD guarantees on section alignment across TUs?

Fangrui Song via llvm-dev llvm-dev at lists.llvm.org
Sat Jul 25 09:39:55 PDT 2020


On 2020-07-24, Zachary Turner via llvm-dev wrote:
>Suppose i write
>
>// foo.cpp
>__attribute__((section(“foo”))) int x;
>
>// bar.cpp
>__attribute__((section(“foo”))) int y;
>
>And i compile and link these two object files together using lld.  What
>assumptions can I make regarding alignment/padding between the two symbols?
>
>I’m comfortable getting an answer by reading the source, but that won’t
>tell if any properties i discover  are guaranteed or just happenstance.

I am only relatively confident about ELF semantics.

The ELF specification defines says
(http://www.sco.com/developers/gabi/latest/ch4.sheader.html) that:

   ... When not otherwise constrained, sections should be emitted in input order.

For object files this is clear. For archives without --start-group this
can be considered clear as well. For archives with --start-group (LLD
implicitly adds --start-group for every archive)) the input order is the
time point its member is fetched.

    ld.lld ... foo.a bar.o   # bar.o(foo) may come before foo.a(foo.o(foo))

>Are all of the following guaranteed ?
>A) relative order of symbols within a TU is not modified by the linker

If you have more symbols defined relative to foo, i.e.

   __attribute__((section('foo"))) int x;
   __attribute__((section("foo"))) int z;

Yes, the order of x and z in the input section is their relative order
in the output section. The input section is handled as a whole. A linker
cannot reorder content within an input section.

>B) No padding is inserted by the linker between symbols in a TU aside from
>that which was already inserted by the compiler/assembler

Yes. The ELF spec says "...  it must honor the alignment constraints of
the input sections (asserted by the sh_addralign field)"

>C) When merging section A from inputs B and C, the minimal amount of
>padding necessary so that the first symbol from C is properly aligned is
>inserted.

Yes (unless you use linker scripts: foo : { foo.o(foo) BYTE(0) bar.o(foo) })

>I think(?) these conditions would be sufficient to guarantee, for example,
>that I could implement my own .ctor / @init_array logic using only the
>front end.

You can implement .ctor, which is of type SHT_PROGBITS.

For .init_array, GCC __attribute__((section(name))) cannot set the
section type to SHT_INIT_ARRAY. GNU as will set SHT_PROGBITS anyway but
also emit a warning: Warning: setting incorrect section attributes for .init_array

You can use module level inline asm (.pushsection ... .popsection), though...

>And are there any subtle interactions here with -fdata-sections or
>behavioral differences across COFF/ELF/MachO?
>
>Is there anyone who can provide some insight on this?


More information about the llvm-dev mailing list