Skip to content

Commit 8bd9ad1

Browse files
committed
Implement section attribute
1 parent a807811 commit 8bd9ad1

File tree

8 files changed

+268
-2
lines changed

8 files changed

+268
-2
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,8 +1401,8 @@ 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
1405-
if (!(flags & IMAGE_SCN_LNK_COMDAT))
1404+
//assert(strlen(sectname) <= 8); // so it won't go into string_table
1405+
if (!(flags & IMAGE_SCN_LNK_COMDAT) && strlen(sectname) <= 8)
14061406
{
14071407
for (segidx_t seg = 1; seg < SegData.length; seg++)
14081408
{ seg_data* pseg = SegData[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: 100 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,101 @@ 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+
532+
switch (config.objfmt)
533+
{
534+
case OBJ_MACH:
535+
import dmd.backend.mach;
536+
537+
// name does not start with a _
538+
//s.Sflags |= SFLnounderscore;
539+
540+
s.Sseg = Obj.getsegment(
541+
userDefinedSection.ptr,
542+
canBeReadOnly ? "__TEXT" : "__DATA",
543+
alignToPower, // convert alignment to the power of
544+
545+
//S_ATTR_NO_DEAD_STRIP |
546+
S_REGULAR // flags
547+
);
548+
break;
549+
case OBJ_ELF:
550+
import dmd.backend.elfobj;
551+
import dmd.backend.melf;
552+
553+
s.Sseg = Obj.getsegment(
554+
userDefinedSection.ptr,
555+
null, // suffix
556+
SHT_PROGBITS, // type
557+
558+
//SHF_GNU_RETAIN |
559+
SHF_ALLOC | (canBeReadOnly ? 0 : SHF_WRITE), // flags
560+
561+
alignTo // align
562+
);
563+
break;
564+
case OBJ_MSCOFF:
565+
import dmd.backend.mscoff;
566+
567+
const alignTo2 = IMAGE_SCN_ALIGN_1BYTES * (alignToPower + 1);
568+
const alignTo3 = alignTo2 <= IMAGE_SCN_ALIGN_8192BYTES ? alignTo2 : IMAGE_SCN_ALIGN_8192BYTES;
569+
570+
// Windows will not dead strip symbols, as long as start/end are used.
571+
572+
s.Sseg = Obj.getsegment(
573+
userDefinedSection.ptr,
574+
575+
// flags
576+
alignTo3
577+
| IMAGE_SCN_MEM_READ
578+
| IMAGE_SCN_CNT_INITIALIZED_DATA
579+
| (canBeReadOnly ? 0 : IMAGE_SCN_MEM_WRITE)
580+
);
581+
break;
582+
default:
583+
break;
584+
}
585+
}
586+
}
587+
488588
/* Make C static functions SCstatic
489589
*/
490590
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: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
EXTRA_SOURCES: extra-files/sectiondefs.d
3+
EXTRA_FILES: extra-files/sectiondefs.d
4+
DFLAGS(windows): -L/INCREMENTAL:NO
5+
*/
6+
module sectiondefs;
7+
import core.attribute;
8+
9+
version (linux)
10+
version = ELF;
11+
else version (FreeBSD)
12+
version = ELF;
13+
else version (OpenBSD)
14+
version = ELF;
15+
else version (NetBSD)
16+
version = ELF;
17+
18+
version(Windows)
19+
enum PlatformEntryName(string Name) = "." ~ Name ~ "$N";
20+
else
21+
enum PlatformEntryName(string Name) = Name;
22+
23+
mixin template SectionRange(string SectionName, Type)
24+
{
25+
version (OSX)
26+
{
27+
enum Segment = (is(Type == const) || is(Type == immutable)) ? "__TEXT" : "__DATA";
28+
29+
extern(C) extern __gshared
30+
{
31+
pragma(mangle, "section$start$" ~ Segment ~ "$" ~ SectionName)
32+
Type start;
33+
pragma(mangle, "section$end$" ~ Segment ~ "$" ~ SectionName)
34+
Type end;
35+
}
36+
}
37+
else version (ELF)
38+
{
39+
extern(C) extern __gshared
40+
{
41+
pragma(mangle, "__start_" ~ SectionName)
42+
Type start;
43+
pragma(mangle, "__stop_" ~ SectionName)
44+
Type end;
45+
}
46+
}
47+
else version (Windows)
48+
{
49+
__gshared
50+
{
51+
@section("." ~ SectionName ~ "$A")
52+
Type _head;
53+
54+
@section("." ~ SectionName ~ "$Z")
55+
Type _tail;
56+
}
57+
58+
Type* start()
59+
{
60+
return &_head + 1;
61+
}
62+
63+
Type* end()
64+
{
65+
return &_tail;
66+
}
67+
}
68+
69+
Type[] range()
70+
{
71+
version (Windows)
72+
return start()[0 .. end() - start()];
73+
else
74+
return (&start)[0 .. (&end - &start)];
75+
}
76+
}
77+
78+
mixin SectionRange!("myInts", int) myIntsSection;
79+
mixin SectionRange!("my8Ints", int[8]) my8IntsSection;
80+
81+
@section(PlatformEntryName!"myInts")
82+
__gshared int anInt = 2;
83+
84+
@section(PlatformEntryName!"my8Ints")
85+
__gshared int[8] an8Int = [46, 92, 11, 7, 2, 55, 33, 22];
86+
87+
void main()
88+
{
89+
//int dummy = anInt, dummy8 = an8Int[0];
90+
91+
version(all)
92+
{
93+
import core.stdc.stdio;
94+
printf("=========== sectiondefs tests ================\n");
95+
printf("myInts %p %lld\n", myIntsSection.range.ptr, myIntsSection.range.length);
96+
printf("my8IntsSection %p %lld\n", my8IntsSection.range.ptr, my8IntsSection.range.length);
97+
98+
version (Windows)
99+
printf("start %p %p\n", myIntsSection.start(), my8IntsSection.start());
100+
else
101+
printf("start %p %p\n", &myIntsSection.start, &my8IntsSection.start);
102+
103+
version (Windows)
104+
printf("end %p %p\n", myIntsSection.end(), my8IntsSection.end());
105+
else
106+
printf("end %p %p\n", &myIntsSection.end, &my8IntsSection.end);
107+
108+
printf("- ");
109+
foreach (v; myIntsSection.range)
110+
printf("%d, ", v);
111+
printf("\n-\n");
112+
foreach(v; my8IntsSection.range)
113+
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]);
114+
printf("\n");
115+
}
116+
117+
assert(myIntsSection.range == [2, 9] || myIntsSection.range == [9, 2]);
118+
119+
assert(my8IntsSection.range == [
120+
[46, 92, 11, 7, 2, 55, 33, 22], [64, 72, 9, 81, 21, 59, 45, 2]
121+
] || my8IntsSection.range == [
122+
[64, 72, 9, 81, 21, 59, 45, 2], [46, 92, 11, 7, 2, 55, 33, 22]
123+
]);
124+
}

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)