Skip to content
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
1 change: 1 addition & 0 deletions compiler/src/dmd/backend/melf.d
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ struct Elf32_Ehdr
enum SHF_GROUP = 0x200; // Member of a section group
enum SHF_TLS = 0x400; /* Thread local */
enum SHF_MASKPROC = 0xf0000000; /* Mask for processor-specific */
enum SHF_GNU_RETAIN = (1 << 21); /* Do not garbage collect section */

struct Elf32_Shdr
{
Expand Down
8 changes: 6 additions & 2 deletions compiler/src/dmd/backend/mscoffobj.d
Original file line number Diff line number Diff line change
Expand Up @@ -1401,8 +1401,12 @@ int MsCoffObj_jmpTableSegment(Symbol* s)
segidx_t MsCoffObj_getsegment(const(char)* sectname, uint flags)
{
//printf("getsegment(%s)\n", sectname);
assert(strlen(sectname) <= 8); // so it won't go into string_table
if (!(flags & IMAGE_SCN_LNK_COMDAT))

// As of writing there is no way to lookup where in the string_table sectname may be.
// Instead if the section name is > 8 characters long, we'll create a new section.
// This isn't an issue in practice, the linker will combine them, but it is less than ideal.

if (!(flags & IMAGE_SCN_LNK_COMDAT) && strlen(sectname) <= 8)
{
for (segidx_t seg = 1; seg < SegData.length; seg++)
{ seg_data* pseg = SegData[seg];
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -8881,6 +8881,7 @@ struct Id final
static Identifier* udaOptional;
static Identifier* udaMustUse;
static Identifier* udaStandalone;
static Identifier* udaSection;
static Identifier* TRUE;
static Identifier* FALSE;
static Identifier* ImportC;
Expand Down
100 changes: 100 additions & 0 deletions compiler/src/dmd/glue/toobj.d
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@ void toObjFile(Dsymbol ds, bool multiobj)
return;
}

// Check to see if we're doing special section mangling, these are not regular variables.
// Do not prepend an underscore to the name, it won't work.
if (config.objfmt == OBJ_MACH && vd.mangleOverride.length > 8 && vd.mangleOverride[0 .. 8] == "section$")
vd.noUnderscore = true;

if (!vd.isDataseg() || vd.storage_class & STC.extern_)
return;

Expand All @@ -485,6 +490,101 @@ void toObjFile(Dsymbol ds, bool multiobj)
Dsymbol parent = vd.toParent();
s.Sclass = SC.global;

{
string userDefinedSection;

// find the @section("name") uda
foreachUdaNoSemantic(vd, (e) {
import dmd.expressionsem : toUTF8;

if (!e.isStructLiteralExp())
return 0;

auto literal = e.isStructLiteralExp();
assert(literal.sd);

if (!isCoreUda(literal.sd, Id.udaSection))
return 0;

if (userDefinedSection)
{
error(vd.loc, "%s `%s` can only have one section attribute", vd.kind, vd.toPrettyChars);
return 1;
}

assert(literal.elements.length == 1);
auto se = (*literal.elements)[0].isStringExp();
assert(se);

userDefinedSection = cast(string)se.toUTF8(vd._scope).toStringz();
return 0;
});

if (userDefinedSection)
{
import core.bitop;
const canBeReadOnly = !vd.type.isMutable;

// Alignment of a type will be a power of 2 and will not be 0.
const alignTo = vd.type.alignsize();
const alignToPower = bsr(alignTo);

switch (config.objfmt)
{
case OBJ_MACH:
import dmd.backend.mach;

// name does not start with a _
//s.Sflags |= SFLnounderscore;

s.Sseg = Obj.getsegment(
userDefinedSection.ptr,
canBeReadOnly ? "__TEXT" : "__DATA",
alignToPower, // convert alignment to the power of

//S_ATTR_NO_DEAD_STRIP |
S_REGULAR // flags
);
break;
case OBJ_ELF:
import dmd.backend.elfobj;
import dmd.backend.melf;

s.Sseg = Obj.getsegment(
userDefinedSection.ptr,
null, // suffix
SHT_PROGBITS, // type

//SHF_GNU_RETAIN |
SHF_ALLOC | (canBeReadOnly ? 0 : SHF_WRITE), // flags

alignTo // align
);
break;
case OBJ_MSCOFF:
import dmd.backend.mscoff;

const alignTo2 = IMAGE_SCN_ALIGN_1BYTES * (alignToPower + 1);
const alignTo3 = alignTo2 <= IMAGE_SCN_ALIGN_8192BYTES ? alignTo2 : IMAGE_SCN_ALIGN_8192BYTES;

// Windows will not dead strip symbols, as long as start/end are used.

s.Sseg = Obj.getsegment(
userDefinedSection.ptr,

// flags
alignTo3
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_CNT_INITIALIZED_DATA
| (canBeReadOnly ? 0 : IMAGE_SCN_MEM_WRITE)
);
break;
default:
break;
}
}
}

/* Make C static functions SCstatic
*/
if (vd.storage_class & STC.static_ && vd.isCsymbol())
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ immutable Msgtable[] msgtable =
{ "udaOptional", "optional"},
{ "udaMustUse", "mustuse" },
{ "udaStandalone", "standalone" },
{ "udaSection", "section" },

// Editions
{ "__edition_latest_do_not_use", },
Expand Down
13 changes: 13 additions & 0 deletions compiler/test/runnable/extra-files/sectiondefs.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module extrafiles.sectiondefs;
import core.attribute;

version(Windows)
enum PlatformEntryName(string Name) = "." ~ Name ~ "$N";
else
enum PlatformEntryName(string Name) = Name;

@section(PlatformEntryName!"myInts")
__gshared int anInt = 9;

@section(PlatformEntryName!"my8Ints")
__gshared int[8] an8Int = [64, 72, 9, 81, 21, 59, 45, 2];
121 changes: 121 additions & 0 deletions compiler/test/runnable/sectiondefs.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
EXTRA_SOURCES: extra-files/sectiondefs.d
EXTRA_FILES: extra-files/sectiondefs.d
REQUIRED_ARGS(windows): -L/INCREMENTAL:NO
*/
// Incremental linking must be turned off, or it will add padding.
module sectiondefs;
import core.attribute;

version (ELFv1)
version = ELF;
else version (ELFv2)
version = ELF;

version(Windows)
enum PlatformEntryName(string Name) = "." ~ Name ~ "$N";
else
enum PlatformEntryName(string Name) = Name;

mixin template SectionRange(string SectionName, Type)
{
version (OSX)
{
enum Segment = (is(Type == const) || is(Type == immutable)) ? "__TEXT" : "__DATA";

extern(C) extern __gshared
{
pragma(mangle, "section$start$" ~ Segment ~ "$" ~ SectionName)
Type start;
pragma(mangle, "section$end$" ~ Segment ~ "$" ~ SectionName)
Type end;
}
}
else version (ELF)
{
extern(C) extern __gshared
{
pragma(mangle, "__start_" ~ SectionName)
Type start;
pragma(mangle, "__stop_" ~ SectionName)
Type end;
}
}
else version (Windows)
{
__gshared
{
@section("." ~ SectionName ~ "$A")
Type _head;

@section("." ~ SectionName ~ "$Z")
Type _tail;
}

Type* start()
{
return &_head + 1;
}

Type* end()
{
return &_tail;
}
}

Type[] range()
{
version (Windows)
return start()[0 .. end() - start()];
else
return (&start)[0 .. (&end - &start)];
}
}

mixin SectionRange!("myInts", int) myIntsSection;
mixin SectionRange!("my8Ints", int[8]) my8IntsSection;

@section(PlatformEntryName!"myInts")
__gshared int anInt = 2;

@section(PlatformEntryName!"my8Ints")
__gshared int[8] an8Int = [46, 92, 11, 7, 2, 55, 33, 22];

void main()
{
//int dummy = anInt, dummy8 = an8Int[0];

version(none)
{
import core.stdc.stdio;
printf("=========== sectiondefs tests ================\n");
printf("myInts %p %zd\n", myIntsSection.range.ptr, myIntsSection.range.length);
printf("my8IntsSection %p %zd\n", my8IntsSection.range.ptr, my8IntsSection.range.length);

version (Windows)
printf("start %p %p\n", myIntsSection.start(), my8IntsSection.start());
else
printf("start %p %p\n", &myIntsSection.start, &my8IntsSection.start);

version (Windows)
printf("end %p %p\n", myIntsSection.end(), my8IntsSection.end());
else
printf("end %p %p\n", &myIntsSection.end, &my8IntsSection.end);

printf("- ");
foreach (v; myIntsSection.range)
printf("%d, ", v);
printf("\n-\n");
foreach(v; my8IntsSection.range)
printf(" - [%d, %d, %d, %d, %d, %d, %d, %d],\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
printf("\n");
}

assert(myIntsSection.range == [2, 9] || myIntsSection.range == [9, 2]);

assert(my8IntsSection.range == [
[46, 92, 11, 7, 2, 55, 33, 22], [64, 72, 9, 81, 21, 59, 45, 2]
] || my8IntsSection.range == [
[64, 72, 9, 81, 21, 59, 45, 2], [46, 92, 11, 7, 2, 55, 33, 22]
]);
}
26 changes: 26 additions & 0 deletions druntime/src/core/attribute.d
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,32 @@ else
// GDC and LDC declare this attribute in their own modules.
}

/**
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

documentation starts here

* When applied to a global variable, causes it to be emitted to a
* non-standard object file/executable section.
*
* The target platform might impose certain restrictions on the format for
* section names.
*
* Examples:
* ---
* import core.attributes;
*
* @section("mySection") int myGlobal;
* ---
*/
version (DigitalMars)
{
struct section
{
string name;
}
}
else
{
// GDC and LDC declare this attribute in their own modules.
}

/**
* Use this attribute to attach an Objective-C selector to a method.
*
Expand Down
5 changes: 5 additions & 0 deletions spec/pragma.dd
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ $(H3 $(LNAME2 mangle, $(D pragma mangle)))
for all compatible (POSIX in one case, win64 in another) platforms instead of having to special-case.
)

$(IMPLEMENTATION_DEFINED On macOS since 2.113, the leading underscore (`_`) will not be emitted automatically
if the name of the symbol starts with `section$`, this name is a special name generated by the macOS linker for sections,
and does not start with a leading underscore.
)

$(RATIONALE
$(UL
$(LI Enables linking to symbol names that D cannot represent.)
Expand Down
Loading