December 18, 2013
Am Tue, 17 Dec 2013 21:12:41 +0100
schrieb "David Nadlinger" <code@klickverbot.at>:

> On Tuesday, 17 December 2013 at 20:07:41 UTC, Iain Buclaw wrote:
> > The hidden subtext that you didn't understand being, I'm holding back on Martin's patches for now.
> 
> That subtext isn't exactly hidden, given the first sentence in your first post. ;)
> 
> Do you have a plan yet regarding how to implement module discovery for shared libraries? Would be a good idea to coordinate efforts and find a solution that works for all the backends, as Martin has been suggesting as well.
> 
> David

I hope I'm not talking bullshit here as I'm not 100% sure what's meant with 'module discovery'.

But if the question is how to get all ModuleInfos in a library, we should probably not forget the way C handles it's 'module constructors', aka the '.ctors' / '.dtors' section.

They use linker scripts to make sure these sections are always correctly bracketed by _start and _end symbols and we could do the same for a '.moduleinfo' section and for the standard tls sections.

Here's the relevant part of a linker script:
------------------------
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
------------------------

We can then access the bracket-symbols from a module-constructor (or a c-like .ctor constructor) in the library? So we'd have to add drtbegin.o / drtend.o files to every d library or executable.

Ideally we'd get the default linker scripts changed, but that may take
some time if the binutils guys even agree. It's also possible to
1) give a linker script to ld to replace the default script (not so
   good for us)
2) give ld a script to extend the default script (could work
   for .moduleinfo section, I'm not sure about TLS)

One big problem is of course portability. But it seems such a solution
might be more portable than a solution relying on runtime
linkers (especially considering gcc already uses this internally for c++
support)
December 18, 2013
On 18 December 2013 15:39, Johannes Pfau <nospam@example.com> wrote:
> Am Tue, 17 Dec 2013 21:12:41 +0100
> schrieb "David Nadlinger" <code@klickverbot.at>:
>
>> On Tuesday, 17 December 2013 at 20:07:41 UTC, Iain Buclaw wrote:
>> > The hidden subtext that you didn't understand being, I'm holding back on Martin's patches for now.
>>
>> That subtext isn't exactly hidden, given the first sentence in your first post. ;)
>>
>> Do you have a plan yet regarding how to implement module discovery for shared libraries? Would be a good idea to coordinate efforts and find a solution that works for all the backends, as Martin has been suggesting as well.
>>
>> David
>
> I hope I'm not talking bullshit here as I'm not 100% sure what's meant with 'module discovery'.
>

I'm not so sure about 'module discovery' either.  At least, in emulated TLS, it has a completely different concept - each thread has a dynamically allocated range (effectively, a void**[] on the heap that gets destroyed upon thread termination) which is shared amongst all modules / loaded libraries in D for the duration of the thread. So when it comes to calling getTLSRange() - what is effectively happening is:

  void**[] tlsarray = gthread_getspecific(emutls_key);
  return cast(void[]) tlsarray[0 .. $];

What I'm hoping is that whatever Martin has done, it is compatible with this way of doing things...
December 18, 2013
On 2013-12-18 18:36, Iain Buclaw wrote:

> I'm not so sure about 'module discovery' either.  At least, in
> emulated TLS, it has a completely different concept - each thread has
> a dynamically allocated range (effectively, a void**[] on the heap
> that gets destroyed upon thread termination) which is shared amongst
> all modules / loaded libraries in D for the duration of the thread.
> So when it comes to calling getTLSRange() - what is effectively
> happening is:
>
>    void**[] tlsarray = gthread_getspecific(emutls_key);
>    return cast(void[]) tlsarray[0 .. $];
>
> What I'm hoping is that whatever Martin has done, it is compatible
> with this way of doing things...

After the changes Margin has done DMD now emits .ctors and .dtors sections to to every executable and shared library. These will call "_d_dso_registry", passing in, among other things, the start and end of the module infos.

To get the TLS data the runtime iterates the sections of the executable/shared library and collections these.

I don't know if that will be compatible with how it's done in GDC.

This is only for Linux, FreeBSD and Mac OS X behaves as it did before. FreeBSD uses bracked sections and Mac OS X doing something similar as Linux does now, the dynamic linker has API's for this.

-- 
/Jacob Carlborg
December 19, 2013
Am Tue, 17 Dec 2013 18:48:38 +0100
schrieb "Iain Buclaw" <ibuclaw@ubuntu.com>:

> Gthreads and Emulated TLS are now in GDC!!!
> 
> https://github.com/D-Programming-GDC/GDC/commit/62554bfe1b35ee4f586634a76c65d83ebfa871ef
> 
> The bug noted above still exists, however what I am going to do is update and hook emulated TLS into the GC.

A question about the emutls support:
I guess it's not compatible with C/C++ emutls right now? So if we have:
test.c:
__thread int a;

and test.d:
extern(C) int a;

This wouldn't work right now?

I think it could be possible to treat thread local variables in extern(C) code specially and hook it up with the standard GCC emutls. This way we could make it work, however we likely can't make the GC scan extern(C) thread local variables then.
December 19, 2013
Am Wed, 18 Dec 2013 17:36:53 +0000
schrieb Iain Buclaw <ibuclaw@gdcproject.org>:

> On 18 December 2013 15:39, Johannes Pfau <nospam@example.com> wrote:
> > Am Tue, 17 Dec 2013 21:12:41 +0100
> > schrieb "David Nadlinger" <code@klickverbot.at>:
> >
> >> On Tuesday, 17 December 2013 at 20:07:41 UTC, Iain Buclaw wrote:
> >> > The hidden subtext that you didn't understand being, I'm holding back on Martin's patches for now.
> >>
> >> That subtext isn't exactly hidden, given the first sentence in your first post. ;)
> >>
> >> Do you have a plan yet regarding how to implement module discovery for shared libraries? Would be a good idea to coordinate efforts and find a solution that works for all the backends, as Martin has been suggesting as well.
> >>
> >> David
> >
> > I hope I'm not talking bullshit here as I'm not 100% sure what's meant with 'module discovery'.
> >
> 
> I'm not so sure about 'module discovery' either.  At least, in emulated TLS, it has a completely different concept - each thread has a dynamically allocated range (effectively, a void**[] on the heap that gets destroyed upon thread termination) which is shared amongst all modules / loaded libraries in D for the duration of the thread. So when it comes to calling getTLSRange() - what is effectively happening is:
> 
>   void**[] tlsarray = gthread_getspecific(emutls_key);
>   return cast(void[]) tlsarray[0 .. $];
> 
> What I'm hoping is that whatever Martin has done, it is compatible with this way of doing things...

I guess you can add the scan code here: https://github.com/D-Programming-Language/druntime/blob/master/src/rt/tlsgc.d#L62
December 19, 2013
On 19 December 2013 11:47, Johannes Pfau <nospam@example.com> wrote:
> Am Tue, 17 Dec 2013 18:48:38 +0100
> schrieb "Iain Buclaw" <ibuclaw@ubuntu.com>:
>
>> Gthreads and Emulated TLS are now in GDC!!!
>>
>> https://github.com/D-Programming-GDC/GDC/commit/62554bfe1b35ee4f586634a76c65d83ebfa871ef
>>
>> The bug noted above still exists, however what I am going to do is update and hook emulated TLS into the GC.
>
> A question about the emutls support:
> I guess it's not compatible with C/C++ emutls right now? So if we have:
> test.c:
> __thread int a;
>
> and test.d:
> extern(C) int a;
>
> This wouldn't work right now?
>
> I think it could be possible to treat thread local variables in extern(C) code specially and hook it up with the standard GCC emutls. This way we could make it work, however we likely can't make the GC scan extern(C) thread local variables then.

It's compatible with libgcc emutls.
December 19, 2013
Am Thu, 19 Dec 2013 15:39:28 +0000
schrieb Iain Buclaw <ibuclaw@gdcproject.org>:

> On 19 December 2013 11:47, Johannes Pfau <nospam@example.com> wrote:
> > Am Tue, 17 Dec 2013 18:48:38 +0100
> > schrieb "Iain Buclaw" <ibuclaw@ubuntu.com>:
> >
> 
> It's compatible with libgcc emutls.

Of course! I totally missed the extern(C) in emutls.d. So emutls.d just overwrites the default emutls implementation in libgcc?

I guess this works fine for D apps as long as libgcc is a static library.

What about a shared libgcc? Wouldn't the compiler then pickup the emutls function in libgcc instead of libgdruntme?

The most difficult case is probably a C app loading a shared D library?
December 19, 2013
On 19 December 2013 16:34, Johannes Pfau <nospam@example.com> wrote:
> Am Thu, 19 Dec 2013 15:39:28 +0000
> schrieb Iain Buclaw <ibuclaw@gdcproject.org>:
>
>> On 19 December 2013 11:47, Johannes Pfau <nospam@example.com> wrote:
>> > Am Tue, 17 Dec 2013 18:48:38 +0100
>> > schrieb "Iain Buclaw" <ibuclaw@ubuntu.com>:
>> >
>>
>> It's compatible with libgcc emutls.
>
> Of course! I totally missed the extern(C) in emutls.d. So emutls.d just overwrites the default emutls implementation in libgcc?
>
> I guess this works fine for D apps as long as libgcc is a static library.
>
> What about a shared libgcc? Wouldn't the compiler then pickup the emutls function in libgcc instead of libgdruntme?
>

It picks up the libgdruntime function in both cases.


> The most difficult case is probably a C app loading a shared D library?

That I will worry about when we get to that point.
December 19, 2013
On Wednesday, 18 December 2013 at 15:39:30 UTC, Johannes Pfau wrote:
> I hope I'm not talking bullshit here as I'm not 100% sure what's meant
> with 'module discovery'.
>
> But if the question is how to get all ModuleInfos in a library, […]

Yes, this was the idea.

> We can then access the bracket-symbols from a module-constructor (or a
> c-like .ctor constructor) in the library? So we'd have to add
> drtbegin.o / drtend.o files to every d library or executable.

That is pretty much how it is done in DMD and LDC as well. The only difference is that instead of modifying the linker scripts to accommodate this, we emit the ModuleInfo references to custom sections. The GNU toolchain (and we are in highly system-specific territory here anyway) never changes the order of custom sections, which you can also verify using __attribute__((section("...))) in GCC. Thus, if you emit your relevant symbols into three sections like this,

a.o
---
_minfo_beg: moduleInfoBeginTag
_minfo: moduleInfoForA
_minfo_end: moduleInfoEndTag

b.o
---
_minfo_beg: moduleInfoBeginTag
_minfo: moduleInfoForB
_minfo_end: moduleInfoEndTag

the linked result will be

_minfo_beg: moduleInfoBeginTag
_minfo: moduleInfoForA moduleInfoForB
_minfo_end: moduleInfoEndTag

and you can just use [moduleInfoBeginTag, moduleInfoEndTag) to get a list of all available ModuleInfos.


Of course, once shared libraries come into play, you have to consider quite a few subtleties regarding symbol visibility and so on. Also, due to a bug in LLVM, LDC can't emit weak symbols with custom section names, so we end up with multiple copies of the begin/end symbols and the C .ctor/.dtor table entries.

But in general, this works quite well, and is certainly much more portable than requiring changes to the linker script.

David
December 19, 2013
Am Thu, 19 Dec 2013 18:59:42 +0100
schrieb "David Nadlinger" <code@klickverbot.at>:

> Yes, this was the idea.
> 
> > We can then access the bracket-symbols from a
> > module-constructor (or a
> > c-like .ctor constructor) in the library? So we'd have to add
> > drtbegin.o / drtend.o files to every d library or executable.
> 
> That is pretty much how it is done in DMD and LDC as well. The only difference is that instead of modifying the linker scripts to accommodate this, we emit the ModuleInfo references to custom sections. The GNU toolchain (and we are in highly system-specific territory here anyway) never changes the order of custom sections, which you can also verify using __attribute__((section("...))) in GCC. Thus, if you emit your relevant symbols into three sections like this,
> 
> a.o
> ---
> _minfo_beg: moduleInfoBeginTag
> _minfo: moduleInfoForA
> _minfo_end: moduleInfoEndTag
> 
> b.o
> ---
> _minfo_beg: moduleInfoBeginTag
> _minfo: moduleInfoForB
> _minfo_end: moduleInfoEndTag
> 
> the linked result will be
> 
> _minfo_beg: moduleInfoBeginTag
> _minfo: moduleInfoForA moduleInfoForB
> _minfo_end: moduleInfoEndTag
> 
> and you can just use [moduleInfoBeginTag, moduleInfoEndTag) to get a list of all available ModuleInfos.
> 
> 
> Of course, once shared libraries come into play, you have to consider quite a few subtleties regarding symbol visibility and so on.

Yes, I got that part. Begin/End symbols should be private to the library and accessed from a constructor function in that library which then passes the addresses of these symbols to the _d_dso_registry function.

(And for TLS if we had these symbols tey would also be 'private' to different threads, so we'd have to register them at thread startup for every dso but AFAICS the currect DMD code basically does that already)

However, I'd prefer to pass an additional object file to ld which contains this constructor instead of placing this code into every object file, but that's probably just a personal preference.

> Also, due to a bug in LLVM, LDC can't emit weak symbols with custom section names, so we end up with multiple copies of the begin/end symbols and the C .ctor/.dtor table entries.
> 
> But in general, this works quite well, and is certainly much more portable than requiring changes to the linker script.
> 
> David

Sounds like that could work. But as the module section is a custom section anyway we wouldn't have to replace/modify the default linker script - we can pass a custom script to ld which just handles the ".minfo" section. That should be just as portable as relying on the "don't reorder sections" behavior: Works everywhere where GNU Binutils LD/GOLD are used. (Emitting 3 sections is a clever trick, but it feels like a hack imho. I'm also not sure if we can control the order in which sections are emitted in GCC)

Even if we don't want to go that route I'll try to write a proof of concept this weekend as I really want to know now whether this will work.


It seems like getting the TLS section is the more interesting part. We can't emit sections around the TLS section so IIRC the current dmd implementation therefore relies on the runtime linker and libc specific interfaces?

I think asking the binutils maintainers to add __tdata_begin, __tdata_end, __tbss_begin and __tbss_end markers to the tdata and tbss sections would be a nice long-term solution, or is there some issue with that?

If the maintainers don't want to add these extra symbols for every library we might ask for special treatment of dso_start.o/dso_end.o files, similar to what they do for crtbegin.o/crtend.o for C++.


I'm wondering though if ld actually reorders symbols in a section by default? I know there are some --sort-section options, but does it sort by default? IIRC we used to use TLS bracketing in GDC and Iain said there were some issues. But if we placed the begin/end markers into extra object files and supplied them as first/last file to the linker, wouldn't that work for now?