This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: protected __start_section and __stop_section symbols


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++)
        (*f)();
}

$ gcc -g -O0    -fPIC -shared foo.c -o libfoo.so
$ 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
http://lists.gnu.org/archive/html/bug-binutils/2017-08/msg00195.html
   (no nice bugzilla entry because of intermittant bugzilla db corruption)
and
https://sourceware.org/ml/binutils/2018-01/msg00265.html
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 *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 libfoo.so  | 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 https://sourceware.org/ml/binutils/2018-01/msg00265.html 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 section.


Thanks for your time,
Cimbali


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]