Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

ELF COMDAT needed for templates to enable linker data culling #3589

Closed
JohanEngelen opened this issue Oct 19, 2020 · 2 comments
Closed

ELF COMDAT needed for templates to enable linker data culling #3589

JohanEngelen opened this issue Oct 19, 2020 · 2 comments

Comments

@JohanEngelen
Copy link
Member

PR #3424 disabled COMDAT for ELF, which had an (obscure) side-effect that hurts a particular use case at Weka: it prevents unused data culling in a section when that section is accessed using the magic __start_* and __stop_* linker symbols.

The test case (4 files):

// File:  templ.d
import ldc.attributes;
auto get(int I)() {
    @(section("test_section")) @assumeUsed static __gshared int getInfo = I;
    return &getInfo;
}
// File: b.d and c.d (identical content, just to get more data into the test_section section)
import templ;
auto get() { return templ.get!(0)(); }
// File: a.d
import templ;
import b;
import c;

auto get() { return templ.get!(0)(); }

extern extern(C) __gshared {
  // Magic symbols to refer to the start and end of test_section.
    byte __start_test_section;
    byte __stop_test_section;
}

int main() {
    version(none) {
        import std.stdio;
        auto a = get();
        auto b = b.get();
        auto c = c.get();
        writeln(a != b, " (expected = false)");
        writeln(b != c, " (expected = false)");
        writeln(cast(size_t) (&__stop_test_section - &__start_test_section), " section size");
    }

    // The referal to the magic symbols prevents removal of the symbols inside test_section
    // if the program doesn't refer to those symbols otherwise (@assumeUsed prevents the compiler
    // from stripping the symbols, but not prevent the linker from doing so).
    size_t size = &__stop_test_section - &__start_test_section;
    return size > 0;
}

Build steps:

ldc2 -c b.d -of=b.o
ldc2 -c c.d -of=c.o
ldc2 -c templ.d -of=templ.o
ldc2 a.d b.o c.o templ.o -of=test

Objdump shows the problem. This is the output with and without COMDAT for the symbols in ELF (objdump --section-headers --section test_section test):

Without COMDAT:
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
 28 test_section  0000000c  0000000000444ea8  0000000000444ea8  00043ea8  2**2

With COMDAT:
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
 28 test_section  00000004  0000000000444ea8  0000000000444ea8  00043ea8  2**2

Without COMDAT: the symbols are merged, the pointers a, b, and c are all the same, but the unused pre-merge data remains and the size of test_section is 0xc = 3 integers.
With COMDAT: the symbols are merged, the pointers a, b, and c are all the same, and the unused data is removed and the size of test_section is 0x4 = 1 integers.

I don't know of another way to prevent the linker from stripping unreferenced symbols other than __start_/__stop_.

@kinke
Copy link
Member

kinke commented Sep 7, 2024

I've quickly tested the testcase on Ubuntu 22, with the bfd/gold/lld linkers (default distro versions). Differences:

  • The section size of 12 does not depend on accessing the magic start/stop linker symbols.
  • When removing @assumeUsed (but uncommenting the main body which accesses all symbols), lld (v14) correctly merges the symbols, yielding the expected section size of 4. bfd and gold yield 12. Edit: I've also checked mold v2.33 now; it also yields 12. :/

kinke added a commit to kinke/ldc that referenced this issue Sep 7, 2024
kinke added a commit to kinke/ldc that referenced this issue Sep 7, 2024
@kinke
Copy link
Member

kinke commented Sep 9, 2024

Fixed by #4748.

@kinke kinke closed this as completed Sep 9, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants