Skip to content

Commit f0541d6

Browse files
authored
implement __d_dso_init for AArch64 (dlang#21450)
* implement dos_init for AArch64 * implement __d_dso_init
1 parent 0d60359 commit f0541d6

4 files changed

Lines changed: 204 additions & 7 deletions

File tree

compiler/src/dmd/backend/arm/cod3.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ void genmovreg(ref CodeBuilder cdb, reg_t to, reg_t from, tym_t ty = TYMAX)
11831183
{
11841184
// integer
11851185
uint sf = ty == TYMAX || _tysize[ty] == 8;
1186-
cdb.gen1(INSTR.mov_register(sf, from, to));
1186+
cdb.gen1(INSTR.mov_register(sf, from, to)); // MOV to,from
11871187
}
11881188
}
11891189

compiler/src/dmd/backend/arm/disasmarm.d

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ void disassemble(uint c) @trusted
387387
uint imm = op ? ((immhi << 2) | immlo) << 12
388388
: ((immhi << 2) | immlo);
389389
p3 = wordtostring(imm);
390+
url2 = p1;
390391
}
391392
else if (field(ins, 28, 23) == 0x22) // https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_imm
392393
{
@@ -411,10 +412,13 @@ void disassemble(uint c) @trusted
411412

412413
if (opS == 0 && sh == 0 && imm12 == 0 && (Rd == 31 || Rn == 31))
413414
{
414-
p1 = "mov"; // https://www.scs.stanford.edu/~zyedidia/arm64/add_addsub_imm.html
415+
p1 = "mov"; // https://www.scs.stanford.edu/~zyedidia/arm64/mov_add_addsub_imm.html
415416
p4 = "";
416417
p5 = "";
418+
url2 = "mov_add_addsub_imm";
417419
}
420+
else if (opS == 0 && sh == 0)
421+
url2 = "add_addsub_imm"; // https://www.scs.stanford.edu/~zyedidia/arm64/add_addsub_imm.html
418422
else if (opS == 1 && Rd == 31) // adds
419423
{
420424
p1 = "cmn"; // https://www.scs.stanford.edu/~zyedidia/arm64/adds_addsub_imm.html
@@ -508,17 +512,18 @@ void disassemble(uint c) @trusted
508512
}
509513
}
510514
}
511-
else if (field(ins, 28, 23) == 0x25) // https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#movewidex
515+
else if (field(ins, 28, 23) == 0x25) // https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#movewide
512516
{
513517
if (log) printf("Move wide (immediate)\n");
514-
url = "movewidex";
518+
url = "movewide";
515519
uint sf = field(ins, 31, 31);
516520
uint opc = field(ins, 30, 29);
517521
uint hw = field(ins, 22, 21);
518522
uint imm16 = field(ins, 20, 5);
519523
uint Rd = field(ins, 4, 0);
520524
if (opc == 0) // https://www.scs.stanford.edu/~zyedidia/arm64/movn.html
521525
{
526+
url2 = "movn";
522527
if (useAlias)
523528
{
524529
bool mov = !(imm16 == 0 && hw != 0) && imm16 != 0xFFFF;
@@ -530,6 +535,8 @@ void disassemble(uint c) @trusted
530535
imm &= 0xFFFF_FFFF;
531536
p3 = wordtostring(imm);
532537
hw = 0;
538+
if (mov)
539+
url2 = "mov_movn";
533540
}
534541
else
535542
{
@@ -539,11 +546,13 @@ void disassemble(uint c) @trusted
539546
}
540547
else if (opc == 2)
541548
{
549+
url2 = (imm16 || hw == 0) ? "mov_movz" : "movz";
542550
p1 = (imm16 || hw == 0) ? "mov" : "movz";
543551
p3 = wordtostring(imm16);
544552
}
545553
else if (opc == 3)
546554
{
555+
url2 = "movk";
547556
p1 = "movk";
548557
p3 = wordtostring(imm16);
549558
}
@@ -3023,7 +3032,7 @@ unittest
30233032
unittest
30243033
{
30253034
int line64 = __LINE__;
3026-
string[83] cases64 = // 64 bit code gen
3035+
string[84] cases64 = // 64 bit code gen
30273036
[
30283037
"6F 00 E4 01 movi v1.2d,#0x0",
30293038
"9E AF 00 3E fmov v30.d[1],x1",
@@ -3092,6 +3101,8 @@ unittest
30923101
"9A C1 20 02 lsl x2,x0,x1",
30933102
"9A C1 24 02 lsr x2,x0,x1",
30943103
"D3 43 FC 01 lsr x1,x0,#3",
3104+
3105+
"D2 80 00 20 mov x0,#1",
30953106
"D2 80 01 C0 mov x0,#0xE",
30963107
"92 80 01 A1 mov x1,#0xFFFFFFFFFFFFFFF2",
30973108
"D2 80 02 02 mov x2,#0x10",

compiler/src/dmd/backend/arm/instr.d

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@ struct INSTR
143143
Rd;
144144
}
145145

146+
/* MOV (to/from) SP)
147+
* MOV <Rd|SP>,<Rn|SP>
148+
* https://www.scs.stanford.edu/~zyedidia/arm64/mov_add_addsub_imm.html
149+
*/
150+
static uint mov_add_addsub_imm(uint sf, reg_t Rn, reg_t Rd)
151+
{
152+
return addsub_imm(sf, 0, 0, 0, 0, Rn, Rd);
153+
}
154+
146155
/* Add/subtract (immediate, with tags)
147156
* ADDG/SUBG
148157
* http://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_immtags
@@ -169,7 +178,16 @@ struct INSTR
169178
Rd;
170179
}
171180

172-
/* Move wide (immediate)
181+
/* NOV (bitmask immediate)
182+
* MOV Rd,#<imm>
183+
* https://www.scs.stanford.edu/~zyedidia/arm64/mov_orr_log_imm.html
184+
*/
185+
static uint mov_orr_log_imm(uint sf, uint N, uint immr, uint imms, reg_t Rd)
186+
{
187+
return log_imm(sf, 1, N, immr, imms, 31, Rd);
188+
}
189+
190+
/* move wide (immediate)
173191
* MOVN/MOVZ/MOVK Rd, #imm{, LSL #shift}
174192
* https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#movewide
175193
*/

compiler/src/dmd/backend/elfobj.d

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import dmd.backend.oper;
3939
import dmd.backend.symtab;
4040
import dmd.backend.ty;
4141
import dmd.backend.type;
42+
import dmd.backend.arm.instr;
4243

4344
import dmd.common.outbuffer;
4445

@@ -3484,7 +3485,7 @@ void ElfObj_dehinfo(Symbol* scc)
34843485
private void obj_rtinit()
34853486
{
34863487
if (config.target_cpu == TARGET_AArch64)
3487-
return;
3488+
return obj_rtinit_aarch64();
34883489

34893490
// section start/stop symbols are defined by the linker (https://www.airs.com/blog/archives/56)
34903491
// make the symbols hidden so that each DSO gets its own brackets
@@ -3844,6 +3845,173 @@ else
38443845
p.sh_size = cast(uint)Offset(groupseg);
38453846
}
38463847

3848+
/**********************************
3849+
* Same as obj_rtinit() but for AArch64
3850+
*/
3851+
private void obj_rtinit_aarch64()
3852+
{
3853+
// section start/stop symbols are defined by the linker (https://www.airs.com/blog/archives/56)
3854+
// make the symbols hidden so that each DSO gets its own brackets
3855+
IDXSYM minfo_beg, minfo_end, dso_rec;
3856+
3857+
IDXSYM deh_beg, deh_end;
3858+
3859+
{
3860+
// needs to be writeable for PIC code, see Bugzilla 13117
3861+
const shf_flags = SHF_ALLOC | SHF_WRITE;
3862+
3863+
if (config.exe & (EX_OPENBSD | EX_OPENBSD64))
3864+
{
3865+
const namidx3 = ElfObj_addstr(&elfobj.symtab_strings,"__start_deh");
3866+
deh_beg = elf_addsym(namidx3, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3867+
3868+
ElfObj_getsegment("deh", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]);
3869+
3870+
const namidx4 = ElfObj_addstr(&elfobj.symtab_strings,"__stop_deh");
3871+
deh_end = elf_addsym(namidx4, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3872+
}
3873+
3874+
const namidx = ElfObj_addstr(&elfobj.symtab_strings,"__start_minfo");
3875+
minfo_beg = elf_addsym(namidx, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3876+
3877+
ElfObj_getsegment("minfo", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]);
3878+
3879+
const namidx2 = ElfObj_addstr(&elfobj.symtab_strings,"__stop_minfo");
3880+
minfo_end = elf_addsym(namidx2, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN);
3881+
}
3882+
3883+
// Create a COMDAT section group
3884+
const groupseg = ElfObj_getsegment(".group.d_dso", null, SHT_GROUP, 0, 0);
3885+
SegData[groupseg].SDbuf.write32(GRP_COMDAT);
3886+
3887+
{
3888+
/*
3889+
* Create an instance of DSORec as global static data in the section .data.d_dso_rec
3890+
* It is writeable and allows the runtime to store information.
3891+
* Make it a COMDAT so there's only one per DSO.
3892+
*
3893+
* union DSO
3894+
* {
3895+
* size_t id;
3896+
* void* data;
3897+
* }
3898+
*/
3899+
const seg = ElfObj_getsegment(".data.d_dso_rec", null, SHT_PROGBITS,
3900+
SHF_ALLOC|SHF_WRITE|SHF_GROUP, _tysize[TYnptr]);
3901+
dso_rec = MAP_SEG2SYMIDX(seg);
3902+
ElfObj_bytes(seg, 0, _tysize[TYnptr], null);
3903+
// add to section group
3904+
SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(seg));
3905+
3906+
/*
3907+
* see druntime/src/rt/sections_elf_shared.d
3908+
* Create an instance of this on the stack:
3909+
*
3910+
* struct CompilerDSOData
3911+
* {
3912+
* size_t _version; // currently 1
3913+
* DSO* _slot; // used to store runtime data
3914+
* void* minfo_beg, minfo_end; // array of modules in this object file
3915+
* }
3916+
*
3917+
* Generate the function:
3918+
*
3919+
* void __dso_init()
3920+
* {
3921+
* CompilerDSOData dso;
3922+
* dso.minfo_end = &__stop_minfo;
3923+
* dso.minfo_beg = &__start_minfo;
3924+
* dso.slot = &d_dso_rec;
3925+
* dso.version = 1;
3926+
* _d_dso_registry(&dso);
3927+
* }
3928+
*
3929+
* and then put a pointer to that function in .init_array and in .fini_array so it'll
3930+
* get executed once upon loading and once upon unloading the DSO.
3931+
*/
3932+
const codseg = ElfObj_getsegment(".text.d_dso_init", null, SHT_PROGBITS,
3933+
SHF_ALLOC|SHF_EXECINSTR|SHF_GROUP, _tysize[TYnptr]);
3934+
// add to section group
3935+
SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(codseg));
3936+
3937+
debug
3938+
{
3939+
// adds a local symbol (name) to the code, useful to set a breakpoint
3940+
const namidx = ElfObj_addstr(&elfobj.symtab_strings, "__d_dso_init");
3941+
elf_addsym(namidx, 0, 0, STT_FUNC, STB_LOCAL, MAP_SEG2SECIDX(codseg));
3942+
}
3943+
3944+
OutBuffer* buf = SegData[codseg].SDbuf;
3945+
assert(!buf.length());
3946+
size_t off = 0;
3947+
3948+
static immutable uint[17] ins =
3949+
[ // implementation of __dso_init()
3950+
INSTR.ldstpair_pre(2,0,0,-48/8 & 127,30,31,29), // STP x29,x30,[sp,#-48]!
3951+
INSTR.mov_add_addsub_imm(1,31,29), // MOV x29,sp
3952+
INSTR.adr(1,0,0), // ADRP x0,<minfo_end> R_AARCH64_ADR_PREL_PG_HI21 minfo_end
3953+
INSTR.addsub_imm(1,0,0,0,0,0,0), // ADD x0,x0,#0x0 R_AARCH64_ADD_ABS_LO12_NC minfo_end
3954+
INSTR.str_imm_gen(1,0,31,40), // STR x0,[sp,#40]
3955+
INSTR.adr(1,0,0), // ADRP x0,<minfo_beg> R_AARCH64_ADR_PREL_PG_HI21 minfo_beg
3956+
INSTR.addsub_imm(1,0,0,0,0,0,0), // ADD x0,x0,#0x0 R_AARCH64_ADD_ABS_LO12_NC minfo_beg
3957+
INSTR.str_imm_gen(1,0,31,32), // STR x0,[sp,#32]
3958+
INSTR.adr(1,0,0), // ADRP x0,<slot> R_AARCH64_ADR_PREL_PG_HI21 slot
3959+
INSTR.addsub_imm(1,0,0,0,0,0,0), // ADD x0,x0,#0x0 R_AARCH64_ADD_ABS_LO12_NC slot
3960+
INSTR.str_imm_gen(1,0,31,24), // STR x0,[sp,#24]
3961+
INSTR.movewide(1,2,0,1,0), // MOV x0,#1
3962+
INSTR.str_imm_gen(1,0,31,16), // STR x0,[sp,#16]
3963+
INSTR.addsub_imm(1,0,0,0,0x10,31,0), // ADD x0,sp,#0x10
3964+
INSTR.bl(0), // BL 0<dso_registry> R_AARCH64_CALL26 dso_registry
3965+
INSTR.ldstpair_post(2,0,1,48/8,30,31,29),// LDP x29,x30,[sp],#48
3966+
INSTR.ret(), // RET
3967+
];
3968+
buf.write(ins);
3969+
ElfObj_writerel(codseg, off+ 2*4, R_AARCH64_ADR_PREL_PG_HI21, minfo_end, 0);
3970+
ElfObj_writerel(codseg, off+ 3*4, R_AARCH64_ADD_ABS_LO12_NC, minfo_end, 0);
3971+
ElfObj_writerel(codseg, off+ 5*4, R_AARCH64_ADR_PREL_PG_HI21, minfo_beg, 0);
3972+
ElfObj_writerel(codseg, off+ 6*4, R_AARCH64_ADD_ABS_LO12_NC, minfo_beg, 0);
3973+
ElfObj_writerel(codseg, off+ 8*4, R_AARCH64_ADR_PREL_PG_HI21, dso_rec, 0);
3974+
ElfObj_writerel(codseg, off+ 9*4, R_AARCH64_ADD_ABS_LO12_NC, dso_rec, 0);
3975+
ElfObj_writerel(codseg, off+14*4, R_AARCH64_CALL26, dso_rec, 0);
3976+
off = buf.length();
3977+
3978+
Offset(codseg) = off;
3979+
3980+
// put a reference into .init_array/.fini_array each
3981+
// needs to be writeable for PIC code, see Bugzilla 13117
3982+
const int flags = SHF_ALLOC | SHF_WRITE | SHF_GROUP;
3983+
{
3984+
const fini_name = USE_INIT_ARRAY() ? ".fini_array.d_dso_dtor" : ".dtors.d_dso_dtor";
3985+
const fini_type = USE_INIT_ARRAY() ? SHT_FINI_ARRAY : SHT_PROGBITS;
3986+
const cdseg = ElfObj_getsegment(fini_name.ptr, null, fini_type, flags, _tysize[TYnptr]);
3987+
assert(!SegData[cdseg].SDbuf.length());
3988+
// add to section group
3989+
SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg));
3990+
// relocation
3991+
const reltype2 = I64 ? R_X86_64_64 : R_386_32;
3992+
SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0);
3993+
}
3994+
{
3995+
const init_name = USE_INIT_ARRAY() ? ".init_array.d_dso_ctor" : ".ctors.d_dso_ctor";
3996+
const init_type = USE_INIT_ARRAY() ? SHT_INIT_ARRAY : SHT_PROGBITS;
3997+
const cdseg = ElfObj_getsegment(init_name.ptr, null, init_type, flags, _tysize[TYnptr]);
3998+
assert(!SegData[cdseg].SDbuf.length());
3999+
// add to section group
4000+
SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg));
4001+
// relocation
4002+
const reltype2 = I64 ? R_X86_64_64 : R_386_32;
4003+
SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0);
4004+
}
4005+
}
4006+
// set group section infos
4007+
Offset(groupseg) = SegData[groupseg].SDbuf.length();
4008+
Elf32_Shdr* p = MAP_SEG2SEC(groupseg);
4009+
p.sh_link = SHN_SYMTAB;
4010+
p.sh_info = dso_rec; // set the dso_rec as group symbol
4011+
p.sh_entsize = IDXSYM.sizeof;
4012+
p.sh_size = cast(uint)Offset(groupseg);
4013+
}
4014+
38474015
/*************************************
38484016
*/
38494017

0 commit comments

Comments
 (0)