KEMBAR78
ELF COMDAT needed for templates to enable linker data culling · Issue #3589 · ldc-developers/ldc · GitHub
Skip to content

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

@JohanEngelen

Description

@JohanEngelen

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_.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions