Skip to content

Commit 62be678

Browse files
committed
Implement section attribute
1 parent a807811 commit 62be678

File tree

9 files changed

+199
-0
lines changed

9 files changed

+199
-0
lines changed

compiler/src/dmd/declaration.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ extern (C++) class VarDeclaration : Declaration
433433
Expression edtor; // if !=null, does the destruction of the variable
434434
IntRange* range; // if !=null, the variable is known to be within the range
435435

436+
string userDefinedSection; // the @section("name"), if present
437+
436438
uint endlinnum; // line number of end of scope that this var lives in
437439
uint offset;
438440
uint sequenceNumber; // order the variables are declared

compiler/src/dmd/declaration.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ class VarDeclaration : public Declaration
237237
Expression *edtor; // if !=NULL, does the destruction of the variable
238238
IntRange *range; // if !NULL, the variable is known to be within the range
239239

240+
DString userDefinedSection;
241+
240242
unsigned endlinnum; // line number of end of scope that this var lives in
241243
unsigned offset;
242244
unsigned sequenceNumber; // order the variables are declared

compiler/src/dmd/dsymbolsem.d

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3154,6 +3154,31 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
31543154
}
31553155
}
31563156

3157+
// find the @section("name") uda
3158+
foreachUda(dsym, sc, (e) {
3159+
if (!e.isStructLiteralExp())
3160+
return 0;
3161+
3162+
auto literal = e.isStructLiteralExp();
3163+
assert(literal.sd);
3164+
3165+
if (!isCoreUda(literal.sd, Id.udaSection))
3166+
return 0;
3167+
3168+
if (dsym.userDefinedSection)
3169+
{
3170+
.error(dsym.loc, "%s `%s` can only have one section attribute", dsym.kind, dsym.toPrettyChars);
3171+
return 1;
3172+
}
3173+
3174+
assert(literal.elements.length == 1);
3175+
auto se = (*literal.elements)[0].toStringExp();
3176+
assert(se);
3177+
3178+
dsym.userDefinedSection = cast(string)se.toUTF8(sc).toStringz();
3179+
return 0;
3180+
});
3181+
31573182
dsym.semanticRun = PASS.semanticdone;
31583183

31593184
if (dsym.type.toBasetype().ty == Terror)

compiler/src/dmd/frontend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6598,6 +6598,7 @@ class VarDeclaration : public Declaration
65986598
VarDeclaration* lastVar;
65996599
Expression* edtor;
66006600
IntRange* range;
6601+
_d_dynamicArray< const char > userDefinedSection;
66016602
uint32_t endlinnum;
66026603
uint32_t offset;
66036604
uint32_t sequenceNumber;
@@ -8881,6 +8882,7 @@ struct Id final
88818882
static Identifier* udaOptional;
88828883
static Identifier* udaMustUse;
88838884
static Identifier* udaStandalone;
8885+
static Identifier* udaSection;
88848886
static Identifier* TRUE;
88858887
static Identifier* FALSE;
88868888
static Identifier* ImportC;

compiler/src/dmd/glue/toobj.d

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,62 @@ void toObjFile(Dsymbol ds, bool multiobj)
485485
Dsymbol parent = vd.toParent();
486486
s.Sclass = SC.global;
487487

488+
if (auto sectionName = vd.userDefinedSection)
489+
{
490+
import core.bitop;
491+
const canBeReadOnly = !(vd.type.isTypeClass || vd.type.isMutable);
492+
493+
// The following alignment calculations looks complex, but its actually pretty simple.
494+
// Given either alignment of for the type of the variable, ensure that it is a power of 2 (round up).
495+
// Linkers don't like it when it isn't a power of 2.
496+
const alignToRequested = vd.type.alignsize();
497+
const alignToPower = alignToRequested > 0 ? bsr(alignToRequested) : 0;
498+
const alignToActual = (1 << alignToPower) == alignToRequested ? alignToRequested : (1 << (alignToPower + 1));
499+
500+
switch (config.objfmt)
501+
{
502+
case OBJ_MACH:
503+
import dmd.backend.mach;
504+
505+
s.Sseg = Obj.getsegment(
506+
sectionName.ptr,
507+
canBeReadOnly ? "__TEXT" : "__DATA",
508+
bsr(alignToActual),
509+
S_REGULAR // flags
510+
);
511+
break;
512+
case OBJ_ELF:
513+
import dmd.backend.elfobj;
514+
import dmd.backend.melf;
515+
516+
s.Sseg = Obj.getsegment(
517+
sectionName.ptr,
518+
null, // suffix
519+
SHT_PROGBITS, // type
520+
SHF_ALLOC | (canBeReadOnly ? 0 : SHF_WRITE), // flags
521+
alignToActual // align
522+
);
523+
break;
524+
case OBJ_MSCOFF:
525+
import dmd.backend.mscoff;
526+
527+
const alignTo2 = IMAGE_SCN_ALIGN_1BYTES << (alignToActual > 0 ? bsr(alignToActual) : 0);
528+
const alignTo3 = alignTo2 <= IMAGE_SCN_ALIGN_8192BYTES ? alignTo2 : IMAGE_SCN_ALIGN_8192BYTES;
529+
530+
s.Sseg = Obj.getsegment(
531+
sectionName.ptr,
532+
// flags
533+
alignTo3
534+
| IMAGE_SCN_MEM_READ
535+
| IMAGE_SCN_CNT_INITIALIZED_DATA
536+
| (canBeReadOnly ? 0 : IMAGE_SCN_MEM_WRITE)
537+
);
538+
break;
539+
default:
540+
break;
541+
}
542+
}
543+
488544
/* Make C static functions SCstatic
489545
*/
490546
if (vd.storage_class & STC.static_ && vd.isCsymbol())

compiler/src/dmd/id.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ immutable Msgtable[] msgtable =
500500
{ "udaOptional", "optional"},
501501
{ "udaMustUse", "mustuse" },
502502
{ "udaStandalone", "standalone" },
503+
{ "udaSection", "section" },
503504

504505
// Editions
505506
{ "__edition_latest_do_not_use", },
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module extrafiles.sectiondefs;
2+
import core.attribute;
3+
4+
@section("myInts")
5+
__gshared int anInt = 9;
6+
7+
@section("my8Ints")
8+
__gshared int[8] an8Int = [64, 72, 9, 81, 21, 59, 45, 2];
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
EXTRA_SOURCES: extra-files/sectiondefs.d
3+
EXTRA_FILES: extra-files/sectiondefs.d
4+
*/
5+
module sectiondefs;
6+
import core.attribute;
7+
8+
version (linux)
9+
version = ELF;
10+
else version (FreeBSD)
11+
version = ELF;
12+
else version (OpenBSD)
13+
version = ELF;
14+
else version (NetBSD)
15+
version = ELF;
16+
17+
mixin template SectionRange(string SectionName, Type)
18+
{
19+
version (OSX)
20+
{
21+
pragma(mangle, "section$start$__TEXT$" ~ SectionName) extern (C) extern __gshared Type start;
22+
23+
pragma(mangle, "section$end$__TEXT$" ~ SectionName) extern (C) extern __gshared Type end;
24+
}
25+
else version (ELF)
26+
{
27+
pragma(mangle, "__start_" ~ SectionName) extern (C) extern __gshared Type start;
28+
29+
pragma(mangle, "__stop_" ~ SectionName) extern (C) extern __gshared Type end;
30+
}
31+
else version (Windows)
32+
{
33+
@section(SectionName ~ "$A")
34+
immutable byte _head = 0;
35+
36+
@section(SectionName ~ "$Z")
37+
immutable byte _tail = 0;
38+
39+
Type* start()
40+
{
41+
return cast(Type*)(cast(byte*)&_head + 1);
42+
}
43+
44+
Type* end()
45+
{
46+
return cast(Type*)&_tail;
47+
}
48+
}
49+
50+
Type[] range()
51+
{
52+
version (Windows)
53+
return start()[0 .. end() - start()];
54+
else
55+
return (&start)[0 .. (&end - &start)];
56+
}
57+
}
58+
59+
mixin SectionRange!("myInts", int) myIntsSection;
60+
mixin SectionRange!("my8Ints", int[8]) my8IntsSection;
61+
62+
@section("myInts")
63+
__gshared int anInt = 2;
64+
65+
@section("my8Ints")
66+
__gshared int[8] an8Int = [46, 92, 11, 7, 2, 55, 33, 22];
67+
68+
void main()
69+
{
70+
assert(myIntsSection.range == [2, 9] || myIntsSection.range == [9, 2]);
71+
72+
assert(my8IntsSection.range == [
73+
[46, 92, 11, 7, 2, 55, 33, 22], [64, 72, 9, 81, 21, 59, 45, 2]
74+
] || my8IntsSection.range == [
75+
[64, 72, 9, 81, 21, 59, 45, 2], [46, 92, 11, 7, 2, 55, 33, 22]
76+
]);
77+
}

druntime/src/core/attribute.d

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@ else
8383
// GDC and LDC declare this attribute in their own modules.
8484
}
8585

86+
version(DigitalMars)
87+
{
88+
/**
89+
* When applied to a global variable, causes it to be emitted to a
90+
* non-standard object file/executable section.
91+
*
92+
* The target platform might impose certain restrictions on the format for
93+
* section names.
94+
*
95+
* Examples:
96+
* ---
97+
* import core.attributes;
98+
*
99+
* @section("mySection") int myGlobal;
100+
* ---
101+
*/
102+
struct section
103+
{
104+
string name;
105+
}
106+
}
107+
else
108+
{
109+
// GDC and LDC declare this attribute in their own modules.
110+
}
111+
86112
/**
87113
* Use this attribute to attach an Objective-C selector to a method.
88114
*

0 commit comments

Comments
 (0)