Skip to content

Commit f1ea646

Browse files
committed
Implement section attribute
1 parent a807811 commit f1ea646

File tree

8 files changed

+262
-1
lines changed

8 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/frontend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8881,6 +8881,7 @@ struct Id final
88818881
static Identifier* udaOptional;
88828882
static Identifier* udaMustUse;
88838883
static Identifier* udaStandalone;
8884+
static Identifier* udaSection;
88848885
static Identifier* TRUE;
88858886
static Identifier* FALSE;
88868887
static Identifier* ImportC;

compiler/src/dmd/glue/toobj.d

Lines changed: 101 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,102 @@ void toObjFile(Dsymbol ds, bool multiobj)
485490
Dsymbol parent = vd.toParent();
486491
s.Sclass = SC.global;
487492

493+
{
494+
string userDefinedSection;
495+
496+
// find the @section("name") uda
497+
foreachUdaNoSemantic(vd, (e) {
498+
import dmd.expressionsem : toUTF8;
499+
500+
if (!e.isStructLiteralExp())
501+
return 0;
502+
503+
auto literal = e.isStructLiteralExp();
504+
assert(literal.sd);
505+
506+
if (!isCoreUda(literal.sd, Id.udaSection))
507+
return 0;
508+
509+
if (userDefinedSection)
510+
{
511+
error(vd.loc, "%s `%s` can only have one section attribute", vd.kind, vd.toPrettyChars);
512+
return 1;
513+
}
514+
515+
assert(literal.elements.length == 1);
516+
auto se = (*literal.elements)[0].isStringExp();
517+
assert(se);
518+
519+
userDefinedSection = cast(string)se.toUTF8(vd._scope).toStringz();
520+
return 0;
521+
});
522+
523+
if (userDefinedSection)
524+
{
525+
import core.bitop;
526+
const canBeReadOnly = !(vd.type.isTypeClass || vd.type.isMutable);
527+
528+
// Alignment of a type will be a power of 2 and will not be 0.
529+
const alignTo = vd.type.alignsize();
530+
const alignToPower = bsr(alignTo);
531+
const alignToPowerForBitShift = alignToPower - 1; // 2^^(n-1) so that we don't bitshift an extra step
532+
533+
switch (config.objfmt)
534+
{
535+
case OBJ_MACH:
536+
import dmd.backend.mach;
537+
538+
// name does not start with a _
539+
//s.Sflags |= SFLnounderscore;
540+
541+
s.Sseg = Obj.getsegment(
542+
userDefinedSection.ptr,
543+
canBeReadOnly ? "__TEXT" : "__DATA",
544+
alignToPower, // convert alignment to the power of
545+
546+
//S_ATTR_NO_DEAD_STRIP |
547+
S_REGULAR // flags
548+
);
549+
break;
550+
case OBJ_ELF:
551+
import dmd.backend.elfobj;
552+
import dmd.backend.melf;
553+
554+
s.Sseg = Obj.getsegment(
555+
userDefinedSection.ptr,
556+
null, // suffix
557+
SHT_PROGBITS, // type
558+
559+
//SHF_GNU_RETAIN |
560+
SHF_ALLOC | (canBeReadOnly ? 0 : SHF_WRITE), // flags
561+
562+
alignTo // align
563+
);
564+
break;
565+
case OBJ_MSCOFF:
566+
import dmd.backend.mscoff;
567+
568+
const alignTo2 = IMAGE_SCN_ALIGN_1BYTES << alignToPowerForBitShift;
569+
const alignTo3 = alignTo2 <= IMAGE_SCN_ALIGN_8192BYTES ? alignTo2 : IMAGE_SCN_ALIGN_8192BYTES;
570+
571+
// Windows will not dead strip symbols, as long as start/end are used.
572+
573+
s.Sseg = Obj.getsegment(
574+
userDefinedSection.ptr,
575+
576+
// flags
577+
alignTo3
578+
| IMAGE_SCN_MEM_READ
579+
| IMAGE_SCN_CNT_INITIALIZED_DATA
580+
| (canBeReadOnly ? 0 : IMAGE_SCN_MEM_WRITE)
581+
);
582+
break;
583+
default:
584+
break;
585+
}
586+
}
587+
}
588+
488589
/* Make C static functions SCstatic
489590
*/
490591
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(all)
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+
}

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+
/**
87+
* When applied to a global variable, causes it to be emitted to a
88+
* non-standard object file/executable section.
89+
*
90+
* The target platform might impose certain restrictions on the format for
91+
* section names.
92+
*
93+
* Examples:
94+
* ---
95+
* import core.attributes;
96+
*
97+
* @section("mySection") int myGlobal;
98+
* ---
99+
*/
100+
version (DigitalMars)
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)