Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ SRCS=\
src\rt\sections.d \
src\rt\sections_android.d \
src\rt\sections_elf_shared.d \
src\rt\sections_osx.d \
src\rt\sections_osx_x86.d \
src\rt\sections_osx_x86_64.d \
src\rt\sections_solaris.d \
src\rt\sections_win32.d \
src\rt\sections_win64.d \
Expand Down
6 changes: 6 additions & 0 deletions posix.mak
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ SRCS:=$(subst \,/,$(SRCS))

OBJS= $(ROOT)/errno_c.o $(ROOT)/bss_section.o $(ROOT)/threadasm.o

ifeq ($(OS),osx)
ifeq ($(MODEL), 64)
OBJS+=$(ROOT)/osx_tls.o
endif
endif

# build with shared library support
SHARED=$(if $(findstring $(OS),linux freebsd),1,)

Expand Down
51 changes: 51 additions & 0 deletions src/rt/osx_tls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Helpers for determining TLS memory ranges on OS X.
*
* This unfortunately cannot be entirely done in D, as the OS X API uses
* the Apple-specific blocks C extension.
*
* Copyright: David Nadlinger, 2012.
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
* Authors: David Nadlinger
*/

#ifndef __APPLE__
#ifndef __BLOCKS__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for OSX, not for lambda support.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a theoretical possibility that someone will try to compile this with GCC. So perhaps check for both OS X and blocks? @klickverbot will it be possible for LDC to use this functionality? In that case what, preprocessor constant can I use to cover all Apple platforms?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@klickverbot will it be possible for LDC to use this functionality?

Huh? The file is from LDC's druntime, so of course we use it already. If your question is about using Blocks from D, then I don't think anybody is planning to add this to the ObjC interop implementation just yet.

In either case, the file is supposed to be excluded from the build on all other platforms anyway, so strictly speaking, the #ifndef is completely unnecessary. However, since the error messages produced by tools that don't support Blocks can be quite puzzling (especially if you are not aware that Blocks even exist), I added the extra check to get a clean preprocessor error in such cases, which is why I used __BLOCKS__.

Feel free to change it so that it refers to another version or remove it entirely, though. I don't think a strong argument is to be made either way. You'd need to look into what other preprocessor constant to use yourself, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MartinNowak checking for both OS X and blocks now.

#error "Need a C compiler with Apple Blocks support – not building on OS X with Clang?"
#endif
#endif

#include <assert.h>
#include <stddef.h>
#include <stdio.h>

/*
* Declarations from dyld_priv.h, available on 10.7+.
*/
enum dyld_tlv_states {
dyld_tlv_state_allocated = 10,
dyld_tlv_state_deallocated = 20
};
typedef struct {
size_t info_size;
void * tlv_addr;
size_t tlv_size;
} dyld_tlv_info;
typedef void (^dyld_tlv_state_change_handler)(enum dyld_tlv_states state, const dyld_tlv_info *info);
extern void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler);
extern void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A dummy symbol will only get you a single section, try to connect this to __tls_data below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this comment. Is it still relevant when __tls_data is not used/removed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be only a single section given that shared libraries are not supported on OS X yet. Or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work for LDC? It does support dynamic libraries?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really do yet (except for Linux).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should've already figured out how generic native tls accesses work (for the dmd part), so why introducing sth. that's incompatible with shared libraries?

void _d_dyld_getTLSRange(void* arbitraryTLSSymbol, void** start, size_t* size) {
dyld_enumerate_tlv_storage(
^(enum dyld_tlv_states state, const dyld_tlv_info *info) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use weird vendor extensions, for sure you can do it with a plain callback or a struct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API is only offered using a blocks-based callback. The need to do that is in fact the only reason why the code exists in an extra .c file. I briefly considered reverse-engineering the Blocks ABI to use it from D, but just using it the way it is supposed to seems like the much easier and more robust solution.

assert(state == dyld_tlv_state_allocated);
if (info->tlv_addr <= arbitraryTLSSymbol &&
arbitraryTLSSymbol < (info->tlv_addr + info->tlv_size)
) {
// Found the range.
*start = info->tlv_addr;
*size = info->tlv_size;
}
}
);
}
9 changes: 8 additions & 1 deletion src/rt/sections.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ else version (FreeBSD)
else version (Solaris)
public import rt.sections_solaris;
else version (OSX)
public import rt.sections_osx;
{
version (X86_64)
public import rt.sections_osx_x86_64;
else version (X86)
public import rt.sections_osx_x86;
else
static assert(0, "unimplemented");
}
else version (CRuntime_DigitalMars)
public import rt.sections_win32;
else version (CRuntime_Microsoft)
Expand Down
31 changes: 8 additions & 23 deletions src/rt/sections_osx.d → src/rt/sections_osx_x86.d
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/**
* Written in the D programming language.
* This module provides OSX-specific support for sections.
* This module provides OS X x86 specific support for sections.
*
* Copyright: Copyright Digital Mars 2008 - 2012.
* Copyright: Copyright Digital Mars 2008 - 2016.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Walter Bright, Sean Kelly, Martin Nowak
* Source: $(DRUNTIMESRC src/rt/_sections_osx.d)
* Authors: Walter Bright, Sean Kelly, Martin Nowak, Jacob Carlborg
* Source: $(DRUNTIMESRC src/rt/_sections_osx_x86.d)
*/

module rt.sections_osx;
module rt.sections_osx_x86;

version(OSX):
version(X86):

// debug = PRINTF;
import core.stdc.stdio;
Expand Down Expand Up @@ -180,7 +180,6 @@ ref void[] getTLSBlockAlloc()
return *pary;
}


__gshared SectionGroup _sections;

extern (C) void sections_osx_onAddImage(in mach_header* h, intptr_t slide)
Expand Down Expand Up @@ -254,22 +253,8 @@ static immutable SegRef[] dataSegs = [{SEG_DATA, SECT_DATA},
ubyte[] getSection(in mach_header* header, intptr_t slide,
in char* segmentName, in char* sectionName)
{
version (X86)
{
assert(header.magic == MH_MAGIC);
auto sect = getsectbynamefromheader(header,
segmentName,
sectionName);
}
else version (X86_64)
{
assert(header.magic == MH_MAGIC_64);
auto sect = getsectbynamefromheader_64(cast(mach_header_64*)header,
segmentName,
sectionName);
}
else
static assert(0, "unimplemented");
assert(header.magic == MH_MAGIC);
auto sect = getsectbynamefromheader(header, segmentName, sectionName);

if (sect !is null && sect.size > 0)
return (cast(ubyte*)sect.addr + slide)[0 .. cast(size_t)sect.size];
Expand Down
186 changes: 186 additions & 0 deletions src/rt/sections_osx_x86_64.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/**
* Written in the D programming language.
* This module provides OS X x86-64 specific support for sections.
*
* Copyright: Copyright Digital Mars 2016.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Jacob Carlborg
* Source: $(DRUNTIMESRC src/rt/_sections_osx_x86_64.d)
*/
module rt.sections_osx_x86_64;

version(OSX):
version(X86_64):

// debug = PRINTF;
import core.stdc.stdio;
import core.stdc.string, core.stdc.stdlib;
import core.sys.posix.pthread;
import core.sys.osx.mach.dyld;
import core.sys.osx.mach.getsect;
import rt.deh, rt.minfo;
import rt.util.container.array;

struct SectionGroup
{
static int opApply(scope int delegate(ref SectionGroup) dg)
{
return dg(_sections);
}

static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
{
return dg(_sections);
}

@property immutable(ModuleInfo*)[] modules() const
{
return _moduleGroup.modules;
}

@property ref inout(ModuleGroup) moduleGroup() inout
{
return _moduleGroup;
}

@property inout(void[])[] gcRanges() inout
{
return _gcRanges[];
}

@property immutable(FuncTable)[] ehTables() const
{
return _ehTables[];
}

private:
immutable(FuncTable)[] _ehTables;
ModuleGroup _moduleGroup;
Array!(void[]) _gcRanges;
immutable(void)[][2] _tlsImage;
}

/****
* Boolean flag set to true while the runtime is initialized.
*/
__gshared bool _isRuntimeInitialized;

/****
* Gets called on program startup just before GC is initialized.
*/
void initSections()
{
_dyld_register_func_for_add_image(&sections_osx_onAddImage);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well unless something changed this function is still a dead-end because you cannot deregister the callback, meaning that this change makes D shared libraries (a VST plugin) ununloadable.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a fix on the way to add linux ctors/dtors to all modules and replace this callback usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well unless something changed this function is still a dead-end because you cannot deregister the callback

@MartinNowak this PR won't fix dynamic libraries. It implements native TLS, nothing else. But native TLS is a prerequisite to fix dynamic libraries.

meaning that this change makes D shared libraries (a VST plugin) ununloadable.

I don't see how this PR would affect the way dynamic libraries work. The state of dynamic libraries will not be any worse than they are now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use D shared libraries as plugins for C hosts (statically linking against phobos), this change breaks the use-case. So please finish your work on ctors/dtors first, or come up w/ a different solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Master is using _dyld_register_func_for_add_image, this change is still using _dyld_register_func_for_add_image. Please explain how this change breaks shared libraries?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if you want to support shared libraries, theres should be a test for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't remember that we've always used those callbacks, would still be great to replace them soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't remember that we've always used those callbacks

No worries 😃.

would still be great to replace them soon.

Absolutely. But let's take this one step at the time.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. But let's take this one step at the time.

Indeed, I would like to go at the ctor problem knowing we've got a clean slate(all tests passing)

_isRuntimeInitialized = true;
}

/***
* Gets called on program shutdown just after GC is terminated.
*/
void finiSections()
{
_sections._gcRanges.reset();
_isRuntimeInitialized = false;
}

void[] initTLSRanges()
{
void* start = null;
size_t size = 0;
_d_dyld_getTLSRange(&dummyTlsSymbol, &start, &size);
assert(start && size, "Could not determine TLS range.");
return start[0 .. size];
}

void finiTLSRanges(void[] rng)
{

}

void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
{
dg(rng.ptr, rng.ptr + rng.length);
}

private:

extern(C) void _d_dyld_getTLSRange(void*, void**, size_t*);

__gshared SectionGroup _sections;
ubyte dummyTlsSymbol;

extern (C) void sections_osx_onAddImage(in mach_header* h, intptr_t slide)
{
foreach (e; dataSegs)
{
auto sect = getSection(h, slide, e.seg.ptr, e.sect.ptr);
if (sect != null)
_sections._gcRanges.insertBack((cast(void*)sect.ptr)[0 .. sect.length]);
}

auto minfosect = getSection(h, slide, "__DATA", "__minfodata");
if (minfosect != null)
{
// no support for multiple images yet
// take the sections from the last static image which is the executable
if (_isRuntimeInitialized)
{
fprintf(stderr, "Loading shared libraries isn't yet supported on OSX.\n");
return;
}
else if (_sections.modules.ptr !is null)
{
fprintf(stderr, "Shared libraries are not yet supported on OSX.\n");
}

debug(PRINTF) printf(" minfodata\n");
auto p = cast(immutable(ModuleInfo*)*)minfosect.ptr;
immutable len = minfosect.length / (*p).sizeof;

_sections._moduleGroup = ModuleGroup(p[0 .. len]);
}

auto ehsect = getSection(h, slide, "__DATA", "__deh_eh");
if (ehsect != null)
{
debug(PRINTF) printf(" deh_eh\n");
auto p = cast(immutable(FuncTable)*)ehsect.ptr;
immutable len = ehsect.length / (*p).sizeof;

_sections._ehTables = p[0 .. len];
}

auto tlssect2 = getSection(h, slide, "__DATA", "__tlscoal_nt");
if (tlssect2 != null)
{
debug(PRINTF) printf(" tlscoal_nt %p %p\n", tlssect2.ptr, tlssect2.ptr + tlssect2.length);
_sections._tlsImage[1] = (cast(immutable(void)*)tlssect2.ptr)[0 .. tlssect2.length];
}
}

struct SegRef
{
string seg;
string sect;
}


static immutable SegRef[] dataSegs = [{SEG_DATA, SECT_DATA},
{SEG_DATA, SECT_BSS},
{SEG_DATA, SECT_COMMON}];


ubyte[] getSection(in mach_header* header, intptr_t slide,
in char* segmentName, in char* sectionName)
{
assert(header.magic == MH_MAGIC_64);
auto sect = getsectbynamefromheader_64(cast(mach_header_64*)header,
segmentName,
sectionName);

if (sect !is null && sect.size > 0)
return (cast(ubyte*)sect.addr + slide)[0 .. cast(size_t)sect.size];
return null;
}