From 4e3deae96d605cc5be6759b6ffdf659006e4c3a4 Mon Sep 17 00:00:00 2001
From: Michael Hudson-Doyle <michael.hudson@canonical.com>
Date: Wed, 24 Jun 2015 22:31:24 +1200
Subject: [PATCH] cmd/link, runtime: arm64 implementation of addmoduledata

Change-Id: I62fb5b20d7caa51b77560a4bfb74a39f17089805
Reviewed-on: https://go-review.googlesource.com/13999
Reviewed-by: Russ Cox <rsc@golang.org>
---
 src/cmd/link/internal/arm64/asm.go | 53 +++++++++++++++++++++++++++++-
 src/runtime/asm_arm64.s            | 11 +++++++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 8517a90004..2e974cc3f4 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -38,7 +38,58 @@ import (
 	"log"
 )
 
-func gentext() {}
+func gentext() {
+	if !ld.DynlinkingGo() {
+		return
+	}
+	addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+	if addmoduledata.Type == obj.STEXT {
+		// we're linking a module containing the runtime -> no need for
+		// an init function
+		return
+	}
+	addmoduledata.Reachable = true
+	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+	initfunc.Type = obj.STEXT
+	initfunc.Local = true
+	initfunc.Reachable = true
+	o := func(op uint32) {
+		ld.Adduint32(ld.Ctxt, initfunc, op)
+	}
+	// 0000000000000000 <local.dso_init>:
+	// 0:	90000000 	adrp	x0, 0 <runtime.firstmoduledata>
+	// 	0: R_AARCH64_ADR_PREL_PG_HI21	local.moduledata
+	// 4:	91000000 	add	x0, x0, #0x0
+	// 	4: R_AARCH64_ADD_ABS_LO12_NC	local.moduledata
+	o(0x90000000)
+	o(0x91000000)
+	rel := ld.Addrel(initfunc)
+	rel.Off = 0
+	rel.Siz = 8
+	rel.Sym = ld.Ctxt.Moduledata
+	rel.Type = obj.R_ADDRARM64
+
+	// 8:	14000000 	bl	0 <runtime.addmoduledata>
+	// 	8: R_AARCH64_CALL26	runtime.addmoduledata
+	o(0x14000000)
+	rel = ld.Addrel(initfunc)
+	rel.Off = 8
+	rel.Siz = 4
+	rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+	rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
+
+	if ld.Ctxt.Etextp != nil {
+		ld.Ctxt.Etextp.Next = initfunc
+	} else {
+		ld.Ctxt.Textp = initfunc
+	}
+	ld.Ctxt.Etextp = initfunc
+	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+	initarray_entry.Reachable = true
+	initarray_entry.Local = true
+	initarray_entry.Type = obj.SINITARR
+	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+}
 
 func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
 	log.Fatalf("adddynrela not implemented")
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index 4c964c0b2d..80309868f4 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -1030,3 +1030,14 @@ TEXT runtime路prefetchnta(SB),NOSPLIT,$0-8
 
 TEXT runtime路sigreturn(SB),NOSPLIT,$0-8
         RET
+
+// This is called from .init_array and follows the platform, not Go, ABI.
+TEXT runtime路addmoduledata(SB),NOSPLIT,$0-0
+	SUB	$0x10, RSP
+	MOVD	R27, 8(RSP) // The access to global variables below implicitly uses R27, which is callee-save
+	MOVD	runtime路lastmoduledatap(SB), R1
+	MOVD	R0, moduledata_next(R1)
+	MOVD	R0, runtime路lastmoduledatap(SB)
+	MOVD	8(RSP), R27
+	ADD	$0x10, RSP
+	RET
-- 
2.30.9