Bug 14748 – Removing std.stdio import causes 2x increase in "Hello, world" program binary filesize
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
All
OS
Linux
Creation time
2015-06-29T13:04:00Z
Last change time
2015-08-04T21:38:51Z
Assigned to
nobody
Creator
dlang-bugzilla
Comments
Comment #0 by dlang-bugzilla — 2015-06-29T13:04:31Z
https://github.com/D-Programming-Language/phobos/pull/3443#issuecomment-116250557
This looks like a Phobos regression caused by a compiler bug.
To reproduce, you can use Digger:
digger build e2dc1a631d1b0bd3eb751c6b7f6d70cfdc5b40c1 # old, small executable
digger build f1bf3d208546728d433de7b3d53631497846b117 # new, big executable
Comment #1 by bugzilla — 2015-06-30T03:59:12Z
On Win32, I get the same exe file size, and 'stream' symbols do not appear in the executable.
Comment #2 by bugzilla — 2015-06-30T04:00:02Z
(In reply to Walter Bright from comment #1)
> On Win32, I get the same exe file size, and 'stream' symbols do not appear
> in the executable.
The file size is 200Kb.
Comment #3 by ketmar — 2015-06-30T04:33:50Z
hm. it seems to pull the whole Phobos in (or at least a great amount of it). i removed "std.stream" from libphobos2.a, the file is smaller (yet still around 800 kb), and now i see other crap there, like "std.path", for example.
it seems that if this bug will be fixed, linux binaries can become lesser in many cases.
Comment #4 by ketmar — 2015-06-30T04:41:04Z
anyway, something is wrong with generated object file. i generated "hello.o" for phobos without PR3443 applied and with PR3443 applied, then linked that object files with "libphobos2.a" WITH PR3443 applied, and got two ELFs with very different sizes (~900 kb and ~400 kb respectively).
so seems that with PR3443 DMD generates an object file which somehow pulls in alot of unnecessary modules. very strange.
Comment #5 by ketmar — 2015-06-30T04:42:54Z
oops. disregard my #4, i'm an idiot and messed link commands.
Comment #6 by dlang-bugzilla — 2015-06-30T16:10:27Z
(In reply to Walter Bright from comment #1)
> On Win32, I get the same exe file size, and 'stream' symbols do not appear
> in the executable.
The test machine that detected this is running Ubuntu Server 14.04 x64.
Comment #7 by k.hara.pg — 2015-07-01T15:34:18Z
(In reply to Walter Bright from comment #2)
> (In reply to Walter Bright from comment #1)
> > On Win32, I get the same exe file size, and 'stream' symbols do not appear
> > in the executable.
>
> The file size is 200Kb.
Also in Win64, PR 3443 does not introduce the binary size difference. The file size is around 350Kb.
Comment #8 by k.hara.pg — 2015-07-01T15:38:12Z
(In reply to Vladimir Panteleev from comment #6)
> The test machine that detected this is running Ubuntu Server 14.04 x64.
Looks like it's a platform-dependent issue.
Comment #9 by code — 2015-07-21T11:51:14Z
Can you guys please provide exact instructions to reproduce a bug.
I don't get any file size differences for the following program compiled with 2.067.1 vs. 2.068.0-b1 on a linux x64
cat > bug.d << CODE
import std.stdio;
void main()
{
writeln("Hello");
}
CODE
dmd bug && size bug
----
2.067.1
text data bss dec hex filename
413016 26440 2320 441776 6bdb0 bug
----
2.068.0-b1
text data bss dec hex filename
407761 25344 2416 435521 6a541 bug
Same for ld.bfd version 2.24 and ld.gold 1.11
Comment #10 by dlang-bugzilla — 2015-07-21T12:11:18Z
(In reply to Martin Nowak from comment #9)
> Can you guys please provide exact instructions to reproduce a bug.
I can reproduce this just fine with Digger, as explained in the original report.
Here is a script that does all the work:
--------------------------------------------------------------
#!/bin/bash
set -eu
cat << EOF > test.d
import std.stdio;
void main()
{
writeln("Hello, world!");
}
EOF
rm -f results.txt
test() {
digger build $1
mkdir -p $1
cd $1
~/Digger/result/bin/dmd -O -inline -release ../test.d
cd ..
ls -al $1/test >> results.txt
}
test e2dc1a631d1b0bd3eb751c6b7f6d70cfdc5b40c1
test f1bf3d208546728d433de7b3d53631497846b117
cat results.txt
--------------------------------------------------------------
I just confirmed the results, and verified that this is not due to a corrupted Digger cache or change in build environment.
I can provide an account on the machine this is reproducible on if you like.
Comment #11 by code — 2015-07-22T11:22:34Z
This is not in the stable branch, so it won't affect 2.068.0.
@Vladimir didn't you wrote a tool at some point, that finds out why a certain symbol was dragged into a binary?
Comment #12 by dlang-bugzilla — 2015-07-22T11:35:42Z
std.stream does not get dragged in by the usual imported modules problem.
When I remove stream.o from libphobos2.a I get a surprising linker error.
dmd/src/../../phobos/generated/linux/release/64/libphobos2.a(curl.o):std/net/curl.d:function _D3std3net4curl4HTTP18_sharedStaticCtor1FZv: error: undefined reference to 'curl_version_info'
dmd/src/../../phobos/generated/linux/release/64/libphobos2.a(curl.o):std/net/curl.d:function _D3std3net4curl4Curl18_sharedStaticCtor2FZv: error: undefined reference to 'curl_global_init'
dmd/src/../../phobos/generated/linux/release/64/libphobos2.a(curl.o):std/net/curl.d:function _D3std3net4curl4Curl18_sharedStaticDtor3FZv: error: undefined reference to 'curl_global_cleanup
If I also remove curl.o then linking works and I get a small and operating binary.
Both modules define weak definitions of the following symbols, which is likely the reason why they got dragged into the binary.
_D3std8internal7cstring15__unittest_failFiZv
_D3std8internal7cstring7__arrayZ
_D3std8internal7cstring8__assertFiZv
Comment #14 by code — 2015-07-22T11:51:56Z
When extracting cstring.o from libphobos2.a and manually linking against it, I also get a small binary.
ar x path/to/libphobos2.a cstring.o
dmd hello.d
ls -lh bug
dmd hello.d cstring.o
ls -lh bug
Comment #15 by k.hara.pg — 2015-08-01T05:18:56Z
(In reply to Martin Nowak from comment #13)
> When I remove stream.o from libphobos2.a
>
> If I also remove curl.o
> binary.
>
> Both modules define weak definitions of the following symbols, which is
> likely the reason why they got dragged into the binary.
>
> _D3std8internal7cstring15__unittest_failFiZv
> _D3std8internal7cstring7__arrayZ
> _D3std8internal7cstring8__assertFiZv
I'm mostly sure that it's same with issue 14828. The COMDAT module helper functions of std.internal.cstring should be placed in its own obj file. Otherwise, if a user code requires them, that might drag stream.o or curl.o into the user program.
(Whether the file size issue happens, would depend on the symbol name list order in libphobos.a. If stream.o and curl.o are listed in the back of in it, linker would pull the first found symbol and stream.o and curl.o are not pulled).