Skip to content

Commit 8e46945

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

File tree

8 files changed

+273
-2
lines changed

8 files changed

+273
-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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,8 +1401,12 @@ 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+
1405+
// As of writing there is no way to lookup where in the string_table sectname may be.
1406+
// Instead if the section name is > 8 characters long, we'll create a new section.
1407+
// This isn't an issue in practice, the linker will combine them, but it is less than ideal.
1408+
1409+
if (!(flags & IMAGE_SCN_LNK_COMDAT) && strlen(sectname) <= 8)
14061410
{
14071411
for (segidx_t seg = 1; seg < SegData.length; seg++)
14081412
{ 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: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
EXTRA_SOURCES: extra-files/sectiondefs.d
3+
EXTRA_FILES: extra-files/sectiondefs.d
4+
REQUIRED_ARGS(windows): -L/INCREMENTAL:NO
5+
*/
6+
// Incremental linking must be turned off, or it will add padding.
7+
module sectiondefs;
8+
import core.attribute;
9+
10+
version (linux)
11+
version = ELF;
12+
else version (FreeBSD)
13+
version = ELF;
14+
else version (OpenBSD)
15+
version = ELF;
16+
else version (NetBSD)
17+
version = ELF;
18+
19+
version(Windows)
20+
enum PlatformEntryName(string Name) = "." ~ Name ~ "$N";
21+
else
22+
enum PlatformEntryName(string Name) = Name;
23+
24+
mixin template SectionRange(string SectionName, Type)
25+
{
26+
version (OSX)
27+
{
28+
enum Segment = (is(Type == const) || is(Type == immutable)) ? "__TEXT" : "__DATA";
29+
30+
extern(C) extern __gshared
31+
{
32+
pragma(mangle, "section$start$" ~ Segment ~ "$" ~ SectionName)
33+
Type start;
34+
pragma(mangle, "section$end$" ~ Segment ~ "$" ~ SectionName)
35+
Type end;
36+
}
37+
}
38+
else version (ELF)
39+
{
40+
extern(C) extern __gshared
41+
{
42+
pragma(mangle, "__start_" ~ SectionName)
43+
Type start;
44+
pragma(mangle, "__stop_" ~ SectionName)
45+
Type end;
46+
}
47+
}
48+
else version (Windows)
49+
{
50+
__gshared
51+
{
52+
@section("." ~ SectionName ~ "$A")
53+
Type _head;
54+
55+
@section("." ~ SectionName ~ "$Z")
56+
Type _tail;
57+
}
58+
59+
Type* start()
60+
{
61+
return &_head + 1;
62+
}
63+
64+
Type* end()
65+
{
66+
return &_tail;
67+
}
68+
}
69+
70+
Type[] range()
71+
{
72+
version (Windows)
73+
return start()[0 .. end() - start()];
74+
else
75+
return (&start)[0 .. (&end - &start)];
76+
}
77+
}
78+
79+
mixin SectionRange!("myInts", int) myIntsSection;
80+
mixin SectionRange!("my8Ints", int[8]) my8IntsSection;
81+
82+
@section(PlatformEntryName!"myInts")
83+
__gshared int anInt = 2;
84+
85+
@section(PlatformEntryName!"my8Ints")
86+
__gshared int[8] an8Int = [46, 92, 11, 7, 2, 55, 33, 22];
87+
88+
void main()
89+
{
90+
//int dummy = anInt, dummy8 = an8Int[0];
91+
92+
version(none)
93+
{
94+
import core.stdc.stdio;
95+
printf("=========== sectiondefs tests ================\n");
96+
printf("myInts %p %zd\n", myIntsSection.range.ptr, myIntsSection.range.length);
97+
printf("my8IntsSection %p %zd\n", my8IntsSection.range.ptr, my8IntsSection.range.length);
98+
99+
version (Windows)
100+
printf("start %p %p\n", myIntsSection.start(), my8IntsSection.start());
101+
else
102+
printf("start %p %p\n", &myIntsSection.start, &my8IntsSection.start);
103+
104+
version (Windows)
105+
printf("end %p %p\n", myIntsSection.end(), my8IntsSection.end());
106+
else
107+
printf("end %p %p\n", &myIntsSection.end, &my8IntsSection.end);
108+
109+
printf("- ");
110+
foreach (v; myIntsSection.range)
111+
printf("%d, ", v);
112+
printf("\n-\n");
113+
foreach(v; my8IntsSection.range)
114+
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]);
115+
printf("\n");
116+
}
117+
118+
assert(myIntsSection.range == [2, 9] || myIntsSection.range == [9, 2]);
119+
120+
assert(my8IntsSection.range == [
121+
[46, 92, 11, 7, 2, 55, 33, 22], [64, 72, 9, 81, 21, 59, 45, 2]
122+
] || my8IntsSection.range == [
123+
[64, 72, 9, 81, 21, 59, 45, 2], [46, 92, 11, 7, 2, 55, 33, 22]
124+
]);
125+
}

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)