Simple "INSERT AFTER" linker script results in excessively large binary

Corey Thompson cmtptr@gmail.com
Thu Feb 22 20:43:00 GMT 2018


I'm not sure to which mailing list this question should go, so
apologies if I should be addressing the binutils list.

I have put together a minimal working example of some behavior in
recent gcc/ld versions that I cannot explain.  I have a simple linker
script for the purpose of locating related data together so that I can
iterate it from a function in my program.  Strangely, the type or
contents of the data seem to have a drastic impact on the output size
of the binary executable.


First, version info:

$ gcc --version; ld --version
gcc (Debian 6.3.0-18) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

GNU ld (GNU Binutils for Debian) 2.28
Copyright (C) 2017 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.


My linker script, test.ld:

SECTIONS {
        .rodata.foo : {
                PROVIDE_HIDDEN(foo_start = .);
                *(.foo)
                PROVIDE_HIDDEN(foo_end = .);
        }
}
INSERT AFTER .rodata


My program source, test.c:

#include <stdio.h>

struct foo {
        int x, y;
};

static const struct foo bar __attribute__ ((section (".foo"))) = {
        .x = 123, .y = 456,
};

extern const struct foo foo_start[], foo_end[];
int main()
{
        printf("%p %p\n", (void *)foo_start, (void *)foo_end);
        return 0;
}


I compile it as follows and find a generated a.out that is 8.7KB in
size, as I would expect:

$ gcc -T test.ld test.c
$ ls -lh a.out
-rwxr-xr-x 1 corey corey 8.7K Feb 22 11:10 a.out


Now I make a small, seemingly benign change to my program - I edit
struct foo to include a pointer to some static const int:

#include <stdio.h>

struct foo {
        int x;
        const int *y;
};

static const int y = 456;
static const struct foo bar __attribute__ ((section (".foo"))) = {
        .x = 123, .y = &y,
};

extern const struct foo foo_start[], foo_end[];
int main()
{
        printf("%p %p\n", (void *)foo_start, (void *)foo_end);
        return 0;
}


With this new source, I compile and find a generated a.out that is
2.1MB in size!:

$ gcc -T test.ld test.c
$ ls -lh a.out
-rwxr-xr-x 1 corey corey 2.1M Feb 22 11:12 a.out


I tried the same test on another machine with the following gcc/ld
versions and did not see this problem; both programs resulted in an
a.out of ~8.6KB or so:

$ gcc --version; ld --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

GNU ld version 2.23.52.0.1-55.el7 20130226
Copyright 2013 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.


Any thoughts or suggestions?  Using the -Wl,-zmax-page-size=0x1000
option seems to reduce the binary size considerably, but given that a
differently-versioned toolchain produced expected results, and that
the unexpected result is exposed by simply changing the structure to
include the address of another symbol, I'm more inclined to suspect
that the root cause is either that I've done something wrong or that
there's a toolchain bug somewhere, in which case -zmax-page-size would
only be a workaround in lieu of a better fix.

Thank you,
Corey



More information about the Gcc-help mailing list