-
-
Notifications
You must be signed in to change notification settings - Fork 270
Description
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=testObjdump 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_.