protected __start_section and __stop_section symbols

Tue Feb 6 00:56:00 GMT 2018

Hi HJ Michael and Alan, and thanks for your replies.

On 05/02/18 22:28, H.J. Lu wrote:
> __start_XXX and __stop_XXX symbols are defined for section XXX within
> the executable or share objects.  You can create a shared object which
> contains section XXX to provide the default __start_XXX and __stop_XXX
> if they aren't defined in the executable.
Yes that's the behaviour I want, however it does *not* work anymore. The 
shared object symbols do not act as "default", in the sense that the 
values from the shared object are always used. Even when they are 
defined in the executable.

Just to check that we mean the same thing, here's a simple test case:

==> bar.c <==
#include <stdio.h>
typedef void (*fptr)();

void pre_init() { printf("OK -- run me from library constructor\n"); }
fptr section_fptrlist __attribute__((section("fptrlist"))) = (fptr)pre_init;

int main() { return 0; }

==> foo.c <==
#include <stdio.h>
typedef void (*fptr)();

void dummy() { printf("NO -- I should be overriden by prog_function\n"); }

fptr section_fptrlist __attribute__((section("fptrlist"))) = (fptr)dummy;
extern fptr __start_fptrlist, __stop_fptrlist;

void __attribute__((constructor)) setup()
     // setup library: try to call pre_init()
     for (fptr *f = &__start_fptrlist; f != &__stop_fptrlist; f++)

$ gcc -g -O0    -fPIC -shared foo.c -o
$ gcc -g -O0    bar.c -L. -lfoo -o linked
$ LD_LIBRARY_PATH=. ./linked
NO -- I should be overriden by prog_function

Until commit cbd0eecf2, running this code resulted in "OK -- run me from 
library constructor".

On 05/02/18 23:39, Michael Matz wrote:
> Actually that just relaxed the visibility again to protected.  Before that
> commit they were even hidden and not even exported.  They were initially
> made hidden by cbd0eecf.
> Since then we're recovering from this.  See
>    (no nice bugzilla entry because of intermittant bugzilla db corruption)
> and
You're right, I missed that because I went straight from 2.26.1 to 
2.29.1, so I mistook the latest commit changing these symbols' 
visibility for the cause of all this. Running git bisect with my test 
case does confirm that the "first bad commit" is cbd0eecf
> Hmm, so you want them interposable.  But others actually don't (as in,
> references from inside a shared lib should resolve to the one form the
> share lib).  Target conflict, where I don't see a solution :-/
> (The intricate usage I know about is pacemaker, and they're using
> dlopen/dlsym, so don't actually care for interposition or not; they'd be
> fine with the old rules).
Well, it's not so much that I *want* that, than it's the way it used to 
work, so I now have code on my hands that relies on this behaviour. The 
fact that it does not anymore caused me quite some head scratching. Of 
course I can work around it, but I thought I'd check if this was meant 
to be first.

On 06/02/18 00:01, Alan Modra wrote:
> Commit f3996791 changed the visibility of __start/__stop symbols from
> hidden to protected.  From the nature of your complaint, I assume you
> would have liked hidden visibility symbols even less.
Yes, my bad, cbd0eecf2 is probably the commit I should have quoted.
> As to why these changes were made, the answer is that a change to the
> order of processing various things in the bfd linker meant that we had
> to change the way __start/__stop symbols were handled.  For more
> details, see PR 11133, 19161, 19167, 20022, 21557, 21562, 21571,
> 21964.
> If you want to know specifically why the symbols were changed from
> default visibility, that reason is given in the git log for commit
> cbd0eecf2.
 From everything I read in these PRs and commit messages, and if I 
understand them right, the changes were about how to handle garbage 
collection properly for orphaned sections:
- PR 21557 was about interactions between __start/__stop symbols with 
the SECTIONS command in the linker script, and was solved by changing 
the script, and putting the PROVIDE for the __start_section inside the 
output section declaration.
- PR 21562 was about references to __start/__stop_section when those 
symbols were not defined (e.g. for non-orphan sections) causing those 
sections to not be garbage-collected properly.
- PR 21571 was about a regression in 2.28 causing sections whose 
__start/__stop symbols were referenced to be wrongly garbage-collected.
- PR 20022 was about garbage collecting a wrong section when it appeared 
both in an object file and a shared object.
At this point all those PRs were closed by cbd0eecf2 which also gave a 
hidden visibility to all __start/__stop symbols.
- PR 21964 was about __start/__stop symbols not being accessible through 
dlsym anymore, and was fixed by changing the symbols to protected.

So I'm still not sure why the behaviour changed in the case where no 
garbage collection happens. In my examples, all __start/__stop symbols 
are both defined and referenced. Actually, I might have been mistaken 
about the visibility, something else in the same set of changes could be 
the root of all this. I tried just leaving the visibility of 
__start/__stop symbols to default, i.e. on top of f3996791:

--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -14247,8 +14247,6 @@ bfd_elf_define_start_stop (struct bfd_link_info 
           /* .startof. and .sizeof. symbols are local.  */
           _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
-      else if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-       h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED;
        return &h->root;
    return NULL;

Now symbols do indeed have default visibility (with the example above):

$ readelf -s  | grep fptrlist
      5: 0000000000201028     8 OBJECT  GLOBAL DEFAULT   23 section_fptrlist
      8: 0000000000201028     0 NOTYPE  GLOBAL DEFAULT   23 __start_fptrlist
     12: 0000000000201030     0 NOTYPE  GLOBAL DEFAULT   23 __stop_fptrlist
     53: 0000000000201028     8 OBJECT  GLOBAL DEFAULT   23 section_fptrlist
     56: 0000000000201028     0 NOTYPE  GLOBAL DEFAULT   23 __start_fptrlist
     60: 0000000000201030     0 NOTYPE  GLOBAL DEFAULT   23 __stop_fptrlist

However I still get:

$ gcc -g -O0    bar.c -L. -lfoo -o linked
$ LD_LIBRARY_PATH=. ./linked
NO -- I should be overriden by prog_function

This is not the issue described in either as far 
as I can tell, as that is about __start/__stop symbols for a section in 
a different object without redefining the section. In my case the 
section is defined both in the executable and the library, with the 
library being a "fallback" for when the executable does not contain the 

Thanks for your time,

More information about the Binutils mailing list