Skip to content

Commit 94cb8f1

Browse files
committed
Implement section attribute
1 parent a807811 commit 94cb8f1

File tree

11 files changed

+262
-1
lines changed

11 files changed

+262
-1
lines changed

compiler/src/dmd/backend/melf.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct Elf32_Ehdr
144144
enum SHF_GROUP = 0x200; // Member of a section group
145145
enum SHF_TLS = 0x400; /* Thread local */
146146
enum SHF_MASKPROC = 0xf0000000; /* Mask for processor-specific */
147+
enum SHF_GNU_RETAIN = (1 << 21); /* No not garbage collect section */
147148

148149
struct Elf32_Shdr
149150
{

compiler/src/dmd/backend/mscoffobj.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ int MsCoffObj_jmpTableSegment(Symbol* s)
14011401
segidx_t MsCoffObj_getsegment(const(char)* sectname, uint flags)
14021402
{
14031403
//printf("getsegment(%s)\n", sectname);
1404-
assert(strlen(sectname) <= 8); // so it won't go into string_table
1404+
//assert(strlen(sectname) <= 8); // so it won't go into string_table
14051405
if (!(flags & IMAGE_SCN_LNK_COMDAT))
14061406
{
14071407
for (segidx_t seg = 1; seg < SegData.length; seg++)

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: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,11 @@ void toObjFile(Dsymbol ds, bool multiobj)
466466
return;
467467
}
468468

469+
// Check to see if we're doing special section mangling, these are not regular variables.
470+
// Do not prepend an underscore to the name, it won't work.
471+
if (config.objfmt == OBJ_MACH && vd.mangleOverride.length > 8 && vd.mangleOverride[0 .. 8] == "section$")
472+
vd.noUnderscore = true;
473+
469474
if (!vd.isDataseg() || vd.storage_class & STC.extern_)
470475
return;
471476

@@ -485,6 +490,72 @@ void toObjFile(Dsymbol ds, bool multiobj)
485490
Dsymbol parent = vd.toParent();
486491
s.Sclass = SC.global;
487492

493+
494+
if (auto sectionName = vd.userDefinedSection)
495+
{
496+
import core.bitop;
497+
const canBeReadOnly = !(vd.type.isTypeClass || vd.type.isMutable);
498+
499+
// Alignment of a type will be a power of 2 and will not be 0.
500+
const alignTo = vd.type.alignsize();
501+
const alignToPower = bsr(alignTo);
502+
const alignToPowerForBitShift = alignToPower - 1; // 2^^(n-1) so that we don't bitshift an extra step
503+
504+
switch (config.objfmt)
505+
{
506+
case OBJ_MACH:
507+
import dmd.backend.mach;
508+
509+
// name does not start with a _
510+
//s.Sflags |= SFLnounderscore;
511+
512+
s.Sseg = Obj.getsegment(
513+
sectionName.ptr,
514+
canBeReadOnly ? "__TEXT" : "__DATA",
515+
alignToPower, // convert alignment to the power of
516+
517+
//S_ATTR_NO_DEAD_STRIP |
518+
S_REGULAR // flags
519+
);
520+
break;
521+
case OBJ_ELF:
522+
import dmd.backend.elfobj;
523+
import dmd.backend.melf;
524+
525+
s.Sseg = Obj.getsegment(
526+
sectionName.ptr,
527+
null, // suffix
528+
SHT_PROGBITS, // type
529+
530+
//SHF_GNU_RETAIN |
531+
SHF_ALLOC | (canBeReadOnly ? 0 : SHF_WRITE), // flags
532+
533+
alignTo // align
534+
);
535+
break;
536+
case OBJ_MSCOFF:
537+
import dmd.backend.mscoff;
538+
539+
const alignTo2 = IMAGE_SCN_ALIGN_1BYTES << alignToPowerForBitShift;
540+
const alignTo3 = alignTo2 <= IMAGE_SCN_ALIGN_8192BYTES ? alignTo2 : IMAGE_SCN_ALIGN_8192BYTES;
541+
542+
// Windows will not dead strip symbols, as long as start/end are used.
543+
544+
s.Sseg = Obj.getsegment(
545+
sectionName.ptr,
546+
547+
// flags
548+
alignTo3
549+
| IMAGE_SCN_MEM_READ
550+
| IMAGE_SCN_CNT_INITIALIZED_DATA
551+
| (canBeReadOnly ? 0 : IMAGE_SCN_MEM_WRITE)
552+
);
553+
break;
554+
default:
555+
break;
556+
}
557+
}
558+
488559
/* Make C static functions SCstatic
489560
*/
490561
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module extrafiles.sectiondefs;
2+
import core.attribute;
3+
4+
version(Windows)
5+
enum PlatformEntryName(string Name) = Name ~ "$N";
6+
else
7+
enum PlatformEntryName(string Name) = Name;
8+
9+
@section(PlatformEntryName!"myInts")
10+
__gshared int anInt = 9;
11+
12+
@section(PlatformEntryName!"my8Ints")
13+
__gshared int[8] an8Int = [64, 72, 9, 81, 21, 59, 45, 2];
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
version(Windows)
18+
enum PlatformEntryName(string Name) = Name ~ "$N";
19+
else
20+
enum PlatformEntryName(string Name) = Name;
21+
22+
mixin template SectionRange(string SectionName, Type)
23+
{
24+
version (OSX)
25+
{
26+
enum Segment = (is(Type == const) || is(Type == immutable)) ? "__TEXT" : "__DATA";
27+
28+
extern(C) extern __gshared
29+
{
30+
pragma(mangle, "section$start$" ~ Segment ~ "$" ~ SectionName)
31+
Type start;
32+
pragma(mangle, "section$end$" ~ Segment ~ "$" ~ SectionName)
33+
Type end;
34+
}
35+
}
36+
else version (ELF)
37+
{
38+
extern(C) extern __gshared
39+
{
40+
pragma(mangle, "__start_" ~ SectionName)
41+
Type start;
42+
pragma(mangle, "__stop_" ~ SectionName)
43+
Type end;
44+
}
45+
}
46+
else version (Windows)
47+
{
48+
__gshared
49+
{
50+
@section(SectionName ~ "$A")
51+
Type _head;
52+
53+
@section(SectionName ~ "$Z")
54+
Type _tail;
55+
}
56+
57+
Type* start()
58+
{
59+
return &_head + 1;
60+
}
61+
62+
Type* end()
63+
{
64+
return &_tail;
65+
}
66+
}
67+
68+
Type[] range()
69+
{
70+
version (Windows)
71+
return start()[0 .. end() - start()];
72+
else
73+
return (&start)[0 .. (&end - &start)];
74+
}
75+
}
76+
77+
mixin SectionRange!("myInts", int) myIntsSection;
78+
mixin SectionRange!("my8Ints", int[8]) my8IntsSection;
79+
80+
@section(PlatformEntryName!"myInts")
81+
__gshared int anInt = 2;
82+
83+
@section(PlatformEntryName!"my8Ints")
84+
__gshared int[8] an8Int = [46, 92, 11, 7, 2, 55, 33, 22];
85+
86+
void main()
87+
{
88+
//int dummy = anInt, dummy8 = an8Int[0];
89+
90+
version(none)
91+
{
92+
import core.stdc.stdio;
93+
printf("=========== sectiondefs tests ================\n");
94+
printf("myInts %p %lld\n", myIntsSection.range.ptr, myIntsSection.range.length);
95+
printf("my8IntsSection %p %lld\n", my8IntsSection.range.ptr, my8IntsSection.range.length);
96+
97+
version (Windows)
98+
printf("start %p %p\n", myIntsSection.start(), my8IntsSection.start());
99+
else
100+
printf("start %p %p\n", &myIntsSection.start, &my8IntsSection.start);
101+
102+
version (Windows)
103+
printf("end %p %p\n", myIntsSection.end(), my8IntsSection.end());
104+
else
105+
printf("end %p %p\n", &myIntsSection.end, &my8IntsSection.end);
106+
107+
foreach (v; myIntsSection.range)
108+
printf("- %d\n", v);
109+
}
110+
111+
assert(myIntsSection.range == [2, 9] || myIntsSection.range == [9, 2]);
112+
113+
assert(my8IntsSection.range == [
114+
[46, 92, 11, 7, 2, 55, 33, 22], [64, 72, 9, 81, 21, 59, 45, 2]
115+
] || my8IntsSection.range == [
116+
[64, 72, 9, 81, 21, 59, 45, 2], [46, 92, 11, 7, 2, 55, 33, 22]
117+
]);
118+
}

0 commit comments

Comments
 (0)