summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2022-08-29 18:45:52 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2022-08-31 21:42:49 +0200
commit8dddb971d923fa19dced39013e6d4a39676e065a (patch)
tree88192ecf3a60de73f06d03dab51dc51f17fb4ab7
parent5490268683c82ad07eac6d2e8296a45702a8381e (diff)
downloadroux-8dddb971d923fa19dced39013e6d4a39676e065a.tar.gz
drop -G flag and add target amd64_apple
apple support is more than assembly syntax
in case of arm64 machines, and apple syntax
is currently useless in all cases but amd64;
rather than having a -G option that only
makes sense with amd64, we add a new target
amd64_apple
-rw-r--r--Makefile6
-rw-r--r--all.h23
-rw-r--r--amd64/all.h3
-rw-r--r--amd64/emit.c31
-rw-r--r--amd64/isel.c2
-rw-r--r--amd64/targ.c42
-rw-r--r--arm64/emit.c24
-rw-r--r--arm64/isel.c2
-rw-r--r--arm64/targ.c2
-rw-r--r--emit.c (renamed from gas.c)100
-rw-r--r--main.c25
-rw-r--r--rv64/emit.c2
-rw-r--r--rv64/isel.c2
-rw-r--r--rv64/targ.c2
14 files changed, 143 insertions, 123 deletions
diff --git a/Makefile b/Makefile
index 18a5066..9c9b401 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ PREFIX = /usr/local
 BINDIR = $(PREFIX)/bin
 
 COMMOBJ  = main.o util.o parse.o cfg.o mem.o ssa.o alias.o load.o copy.o \
-           fold.o live.o spill.o rega.o gas.o
+           fold.o live.o spill.o rega.o emit.o
 AMD64OBJ = amd64/targ.o amd64/sysv.o amd64/isel.o amd64/emit.o
 ARM64OBJ = arm64/targ.o arm64/abi.o arm64/isel.o arm64/emit.o
 RV64OBJ  = rv64/targ.o rv64/abi.o rv64/isel.o rv64/emit.o
@@ -30,11 +30,9 @@ main.o: config.h
 config.h:
 	@case `uname` in                               \
 	*Darwin*)                                      \
-		echo "#define Defasm Gasmacho";        \
-		echo "#define Deftgt T_amd64_sysv";    \
+		echo "#define Deftgt T_amd64_apple";   \
 		;;                                     \
 	*)                                             \
-		echo "#define Defasm Gaself";          \
 		case `uname -m` in                     \
 		*aarch64*)                             \
 			echo "#define Deftgt T_arm64"; \
diff --git a/all.h b/all.h
index c8ec93c..1ecea8e 100644
--- a/all.h
+++ b/all.h
@@ -55,6 +55,9 @@ struct Target {
 	void (*abi)(Fn *);
 	void (*isel)(Fn *);
 	void (*emitfn)(Fn *, FILE *);
+	void (*emitfin)(FILE *);
+	char asloc[4];
+	char assym[4];
 };
 
 #define BIT(n) ((bits)1 << (n))
@@ -524,16 +527,10 @@ void spill(Fn *);
 /* rega.c */
 void rega(Fn *);
 
-/* gas.c */
-enum Asm {
-	Gasmacho,
-	Gaself,
-};
-extern char *gasloc;
-extern char *gassym;
-void gasinit(enum Asm);
-void gasemitlnk(char *, Lnk *, char *, FILE *);
-void gasemitfntail(char *, FILE *);
-void gasemitdat(Dat *, FILE *);
-int gasstash(void *, int);
-void gasemitfin(FILE *);
+/* emit.c */
+void emitlnk(char *, Lnk *, char *, FILE *);
+void emitdat(Dat *, FILE *);
+int stashbits(void *, int);
+void elf_emitfnfin(char *, FILE *);
+void elf_emitfin(FILE *);
+void macho_emitfin(FILE *);
diff --git a/amd64/all.h b/amd64/all.h
index 3a2db0e..f6ad227 100644
--- a/amd64/all.h
+++ b/amd64/all.h
@@ -67,4 +67,5 @@ void amd64_sysv_abi(Fn *);
 void amd64_isel(Fn *);
 
 /* emit.c */
-void amd64_emitfn(Fn *, FILE *);
+void amd64_sysv_emitfn(Fn *, FILE *);
+void amd64_apple_emitfn(Fn *, FILE *);
diff --git a/amd64/emit.c b/amd64/emit.c
index b8e9e8e..db6ead8 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -166,7 +166,7 @@ emitcon(Con *con, FILE *f)
 	switch (con->type) {
 	case CAddr:
 		l = str(con->label);
-		p = con->local ? gasloc : l[0] == '"' ? "" : gassym;
+		p = con->local ? T.asloc : l[0] == '"' ? "" : T.assym;
 		fprintf(f, "%s%s", p, l);
 		if (con->bits.i)
 			fprintf(f, "%+"PRId64, con->bits.i);
@@ -425,8 +425,8 @@ emitins(Ins i, Fn *fn, FILE *f)
 			fprintf(f,
 				"\txorp%c %sfp%d(%%rip), %%%s\n",
 				"xxsd"[i.cls],
-				gasloc,
-				gasstash(negmask[i.cls], 16),
+				T.asloc,
+				stashbits(negmask[i.cls], 16),
 				regtoa(i.to.val, SLong)
 			);
 		break;
@@ -535,8 +535,8 @@ framesz(Fn *fn)
 	return 4*f + 8*o + 176*fn->vararg;
 }
 
-void
-amd64_emitfn(Fn *fn, FILE *f)
+static void
+emitfn(Fn *fn, FILE *f)
 {
 	static char *ctoa[] = {
 	#define X(c, s) [c] = s,
@@ -549,7 +549,7 @@ amd64_emitfn(Fn *fn, FILE *f)
 	int *r, c, o, n, lbl;
 	uint64_t fs;
 
-	gasemitlnk(fn->name, &fn->lnk, ".text", f);
+	emitlnk(fn->name, &fn->lnk, ".text", f);
 	fputs("\tpushq %rbp\n\tmovq %rsp, %rbp\n", f);
 	fs = framesz(fn);
 	if (fs)
@@ -570,7 +570,7 @@ amd64_emitfn(Fn *fn, FILE *f)
 
 	for (lbl=0, b=fn->start; b; b=b->link) {
 		if (lbl || b->npred > 1)
-			fprintf(f, "%sbb%d:\n", gasloc, id0+b->id);
+			fprintf(f, "%sbb%d:\n", T.asloc, id0+b->id);
 		for (i=b->ins; i!=&b->ins[b->nins]; i++)
 			emitins(*i, fn, f);
 		lbl = 1;
@@ -596,7 +596,7 @@ amd64_emitfn(Fn *fn, FILE *f)
 		Jmp:
 			if (b->s1 != b->link)
 				fprintf(f, "\tjmp %sbb%d\n",
-					gasloc, id0+b->s1->id);
+					T.asloc, id0+b->s1->id);
 			else
 				lbl = 0;
 			break;
@@ -610,7 +610,7 @@ amd64_emitfn(Fn *fn, FILE *f)
 				} else
 					c = cmpneg(c);
 				fprintf(f, "\tj%s %sbb%d\n", ctoa[c],
-					gasloc, id0+b->s2->id);
+					T.asloc, id0+b->s2->id);
 				goto Jmp;
 			}
 			die("unhandled jump %d", b->jmp.type);
@@ -618,3 +618,16 @@ amd64_emitfn(Fn *fn, FILE *f)
 	}
 	id0 += fn->nblk;
 }
+
+void
+amd64_sysv_emitfn(Fn *fn, FILE *f)
+{
+	emitfn(fn, f);
+	elf_emitfnfin(fn->name, f);
+}
+
+void
+amd64_apple_emitfn(Fn *fn, FILE *f)
+{
+	emitfn(fn, f);
+}
diff --git a/amd64/isel.c b/amd64/isel.c
index 5a64429..640bf12 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -79,7 +79,7 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
 		memset(&a, 0, sizeof a);
 		a.offset.type = CAddr;
 		a.offset.local = 1;
-		n = gasstash(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
+		n = stashbits(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
 		sprintf(buf, "fp%d", n);
 		a.offset.label = intern(buf);
 		fn->mem[fn->nmem-1] = a;
diff --git a/amd64/targ.c b/amd64/targ.c
index 2cf1bdc..e58ba2f 100644
--- a/amd64/targ.c
+++ b/amd64/targ.c
@@ -12,20 +12,34 @@ amd64_memargs(int op)
 	return amd64_op[op].nmem;
 }
 
+#define AMD64_COMMON \
+	.gpr0 = RAX, \
+	.ngpr = NGPR, \
+	.fpr0 = XMM0, \
+	.nfpr = NFPR, \
+	.rglob = BIT(RBP) | BIT(RSP), \
+	.nrglob = 2, \
+	.rsave = amd64_sysv_rsave, \
+	.nrsave = {NGPS, NFPS}, \
+	.retregs = amd64_sysv_retregs, \
+	.argregs = amd64_sysv_argregs, \
+	.memargs = amd64_memargs, \
+	.abi = amd64_sysv_abi, \
+	.isel = amd64_isel, \
+
 Target T_amd64_sysv = {
 	.name = "amd64_sysv",
-	.gpr0 = RAX,
-	.ngpr = NGPR,
-	.fpr0 = XMM0,
-	.nfpr = NFPR,
-	.rglob = BIT(RBP) | BIT(RSP),
-	.nrglob = 2,
-	.rsave = amd64_sysv_rsave,
-	.nrsave = {NGPS, NFPS},
-	.retregs = amd64_sysv_retregs,
-	.argregs = amd64_sysv_argregs,
-	.memargs = amd64_memargs,
-	.abi = amd64_sysv_abi,
-	.isel = amd64_isel,
-	.emitfn = amd64_emitfn,
+	.emitfn = amd64_sysv_emitfn,
+	.emitfin = elf_emitfin,
+	.asloc = ".L",
+	AMD64_COMMON
+};
+
+Target T_amd64_apple = {
+	.name = "amd64_apple",
+	.emitfn = amd64_apple_emitfn,
+	.emitfin = macho_emitfin,
+	.asloc = "L",
+	.assym = "_",
+	AMD64_COMMON
 };
diff --git a/arm64/emit.c b/arm64/emit.c
index 2506eea..ec4d350 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -245,7 +245,7 @@ emitf(char *s, Ins *i, E *e)
 static void
 loadcon(Con *c, int r, int k, FILE *f)
 {
-	char *rn, *p, off[32];
+	char *rn, *l, *p, off[32];
 	int64_t n;
 	int w, sh;
 
@@ -258,11 +258,12 @@ loadcon(Con *c, int r, int k, FILE *f)
 			sprintf(off, "+%"PRIi64, n);
 		else
 			off[0] = 0;
-		p = c->local ? ".L" : "";
+		l = str(c->label);
+		p = c->local ? T.asloc : l[0] == '"' ? "" : T.assym;
 		fprintf(f, "\tadrp\t%s, %s%s%s\n",
-			rn, p, str(c->label), off);
+			rn, p, l, off);
 		fprintf(f, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
-			rn, rn, p, str(c->label), off);
+			rn, rn, p, l, off);
 		return;
 	}
 	assert(c->type == CBits);
@@ -451,7 +452,7 @@ arm64_emitfn(Fn *fn, FILE *out)
 	Ins *i;
 	E *e;
 
-	gasemitlnk(fn->name, &fn->lnk, ".text", out);
+	emitlnk(fn->name, &fn->lnk, ".text", out);
 	e = &(E){.f = out, .fn = fn};
 	framelayout(e);
 
@@ -500,7 +501,7 @@ arm64_emitfn(Fn *fn, FILE *out)
 
 	for (lbl=0, b=e->fn->start; b; b=b->link) {
 		if (lbl || b->npred > 1)
-			fprintf(e->f, ".L%d:\n", id0+b->id);
+			fprintf(e->f, "%s%d:\n", T.asloc, id0+b->id);
 		for (i=b->ins; i!=&b->ins[b->nins]; i++)
 			emitins(i, e);
 		lbl = 1;
@@ -550,7 +551,10 @@ arm64_emitfn(Fn *fn, FILE *out)
 		case Jjmp:
 		Jmp:
 			if (b->s1 != b->link)
-				fprintf(e->f, "\tb\t.L%d\n", id0+b->s1->id);
+				fprintf(e->f,
+					"\tb\t%s%d\n",
+					T.asloc, id0+b->s1->id
+				);
 			else
 				lbl = 0;
 			break;
@@ -564,9 +568,13 @@ arm64_emitfn(Fn *fn, FILE *out)
 				b->s2 = t;
 			} else
 				c = cmpneg(c);
-			fprintf(e->f, "\tb%s\t.L%d\n", ctoa[c], id0+b->s2->id);
+			fprintf(e->f,
+				"\tb%s\t%s%d\n",
+				ctoa[c], T.asloc, id0+b->s2->id
+			);
 			goto Jmp;
 		}
 	}
 	id0 += e->fn->nblk;
+	elf_emitfnfin(e->fn->name, e->f);
 }
diff --git a/arm64/isel.c b/arm64/isel.c
index bb5c12b..f064321 100644
--- a/arm64/isel.c
+++ b/arm64/isel.c
@@ -84,7 +84,7 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
 			emit(Ocopy, k, r1, r0, R);
 		} else {
 			c = &fn->con[r0.val];
-			n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
+			n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
 			vgrow(&fn->con, ++fn->ncon);
 			c = &fn->con[fn->ncon-1];
 			sprintf(buf, "fp%d", n);
diff --git a/arm64/targ.c b/arm64/targ.c
index 33b14f4..ddaee2f 100644
--- a/arm64/targ.c
+++ b/arm64/targ.c
@@ -41,6 +41,8 @@ Target T_arm64 = {
 	.abi = arm64_abi,
 	.isel = arm64_isel,
 	.emitfn = arm64_emitfn,
+	.emitfin = elf_emitfin,
+	.asloc = ".L",
 };
 
 MAKESURE(globals_are_not_arguments,
diff --git a/gas.c b/emit.c
index 865edba..372ce3d 100644
--- a/gas.c
+++ b/emit.c
@@ -1,27 +1,7 @@
 #include "all.h"
 
-
-char *gasloc, *gassym;
-static int gasasm;
-
 void
-gasinit(enum Asm asmmode)
-{
-	gasasm = asmmode;
-	switch (gasasm) {
-	case Gaself:
-		gasloc = ".L";
-		gassym = "";
-		break;
-	case Gasmacho:
-		gasloc = "L";
-		gassym = "_";
-		break;
-	}
-}
-
-void
-gasemitlnk(char *n, Lnk *l, char *s, FILE *f)
+emitlnk(char *n, Lnk *l, char *s, FILE *f)
 {
 	char *p;
 
@@ -35,23 +15,14 @@ gasemitlnk(char *n, Lnk *l, char *s, FILE *f)
 	fputc('\n', f);
 	if (l->align)
 		fprintf(f, ".balign %d\n", l->align);
-	p = n[0] == '"' ? "" : gassym;
+	p = n[0] == '"' ? "" : T.assym;
 	if (l->export)
 		fprintf(f, ".globl %s%s\n", p, n);
 	fprintf(f, "%s%s:\n", p, n);
 }
 
 void
-gasemitfntail(char *fn, FILE *f)
-{
-	if (gasasm == Gaself) {
-		fprintf(f, ".type %s, @function\n", fn);
-		fprintf(f, ".size %s, .-%s\n", fn, fn);
-	}
-}
-
-void
-gasemitdat(Dat *d, FILE *f)
+emitdat(Dat *d, FILE *f)
 {
 	static char *dtoa[] = {
 		[DB] = "\t.byte",
@@ -68,7 +39,7 @@ gasemitdat(Dat *d, FILE *f)
 		break;
 	case DEnd:
 		if (zero != -1) {
-			gasemitlnk(d->name, d->lnk, ".bss", f);
+			emitlnk(d->name, d->lnk, ".bss", f);
 			fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
 		}
 		break;
@@ -80,7 +51,7 @@ gasemitdat(Dat *d, FILE *f)
 		break;
 	default:
 		if (zero != -1) {
-			gasemitlnk(d->name, d->lnk, ".data", f);
+			emitlnk(d->name, d->lnk, ".data", f);
 			if (zero > 0)
 				fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
 			zero = -1;
@@ -91,7 +62,7 @@ gasemitdat(Dat *d, FILE *f)
 			fprintf(f, "\t.ascii %s\n", d->u.str);
 		}
 		else if (d->isref) {
-			p = d->u.ref.name[0] == '"' ? "" : gassym;
+			p = d->u.ref.name[0] == '"' ? "" : T.assym;
 			fprintf(f, "%s %s%s%+"PRId64"\n",
 				dtoa[d->type], p, d->u.ref.name,
 				d->u.ref.off);
@@ -115,7 +86,7 @@ struct Asmbits {
 static Asmbits *stash;
 
 int
-gasstash(void *bits, int size)
+stashbits(void *bits, int size)
 {
 	Asmbits **pb, *b;
 	int i;
@@ -133,38 +104,37 @@ gasstash(void *bits, int size)
 	return i;
 }
 
-void
-gasemitfin(FILE *f)
+static void
+emitfin(FILE *f, char *sec[3])
 {
 	Asmbits *b;
 	char *p;
-	int sz, i;
+	int lg, i;
 	double d;
 
-	if (gasasm == Gaself)
-		fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n\n");
 	if (!stash)
 		return;
-	fprintf(f, "/* floating point constants */\n.data\n");
-	for (sz=16; sz>=4; sz/=2)
+	fprintf(f, "/* floating point constants */\n");
+	for (lg=4; lg>=2; lg--)
 		for (b=stash, i=0; b; b=b->link, i++) {
-			if (b->size == sz) {
+			if (b->size == (1<<lg)) {
 				fprintf(f,
-					".balign %d\n"
+					".section %s\n"
+					".p2align %d\n"
 					"%sfp%d:",
-					sz, gasloc, i
+					sec[lg-2], lg, T.asloc, i
 				);
-				for (p=b->bits; p<&b->bits[sz]; p+=4)
+				for (p=b->bits; p<&b->bits[b->size]; p+=4)
 					fprintf(f, "\n\t.int %"PRId32,
 						*(int32_t *)p);
-				if (sz <= 8) {
-					if (sz == 4)
+				if (lg <= 3) {
+					if (lg == 2)
 						d = *(float *)b->bits;
 					else
 						d = *(double *)b->bits;
-					fprintf(f, " /* %f */\n", d);
+					fprintf(f, " /* %f */\n\n", d);
 				} else
-					fprintf(f, "\n");
+					fprintf(f, "\n\n");
 			}
 		}
 	while ((b=stash)) {
@@ -172,3 +142,31 @@ gasemitfin(FILE *f)
 		free(b);
 	}
 }
+
+void
+elf_emitfin(FILE *f)
+{
+	static char *sec[3] = { ".rodata", ".rodata", ".rodata" };
+
+	emitfin(f ,sec);
+	fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n");
+}
+
+void
+elf_emitfnfin(char *fn, FILE *f)
+{
+	fprintf(f, ".type %s, @function\n", fn);
+	fprintf(f, ".size %s, .-%s\n", fn, fn);
+}
+
+void
+macho_emitfin(FILE *f)
+{
+	static char *sec[3] = {
+		"__TEXT,__literal4,4byte_literals",
+		"__TEXT,__literal8,8byte_literals",
+		".rodata", /* should not happen */
+	};
+
+	emitfin(f, sec);
+}
diff --git a/main.c b/main.c
index 5ea5704..e82b062 100644
--- a/main.c
+++ b/main.c
@@ -19,11 +19,13 @@ char debug['Z'+1] = {
 };
 
 extern Target T_amd64_sysv;
+extern Target T_amd64_apple;
 extern Target T_arm64;
 extern Target T_rv64;
 
 static Target *tlist[] = {
 	&T_amd64_sysv,
+	&T_amd64_apple,
 	&T_arm64,
 	&T_rv64,
 	0
@@ -40,7 +42,7 @@ data(Dat *d)
 		fputs("/* end data */\n\n", outf);
 		freeall();
 	}
-	gasemitdat(d, outf);
+	emitdat(d, outf);
 }
 
 static void
@@ -92,7 +94,6 @@ func(Fn *fn)
 			fn->rpo[n]->link = fn->rpo[n+1];
 	if (!dbg) {
 		T.emitfn(fn, outf);
-		gasemitfntail(fn->name, outf);
 		fprintf(outf, "/* end function %s */\n\n", fn->name);
 	} else
 		fprintf(stderr, "\n");
@@ -105,12 +106,11 @@ main(int ac, char *av[])
 	Target **t;
 	FILE *inf, *hf;
 	char *f, *sep;
-	int c, asmmode;
+	int c;
 
-	asmmode = Defasm;
 	T = Deftgt;
 	outf = stdout;
-	while ((c = getopt(ac, av, "hd:o:G:t:")) != -1)
+	while ((c = getopt(ac, av, "hd:o:t:")) != -1)
 		switch (c) {
 		case 'd':
 			for (; *optarg; optarg++)
@@ -144,16 +144,6 @@ main(int ac, char *av[])
 				}
 			}
 			break;
-		case 'G':
-			if (strcmp(optarg, "e") == 0)
-				asmmode = Gaself;
-			else if (strcmp(optarg, "m") == 0)
-				asmmode = Gasmacho;
-			else {
-				fprintf(stderr, "unknown gas flavor '%s'\n", optarg);
-				exit(1);
-			}
-			break;
 		case 'h':
 		default:
 			hf = c != 'h' ? stderr : stdout;
@@ -168,13 +158,10 @@ main(int ac, char *av[])
 					fputs(" (default)", hf);
 			}
 			fprintf(hf, "\n");
-			fprintf(hf, "\t%-11s generate gas (e) or osx (m) asm\n", "-G {e,m}");
 			fprintf(hf, "\t%-11s dump debug information\n", "-d <flags>");
 			exit(c != 'h');
 		}
 
-	gasinit(asmmode);
-
 	do {
 		f = av[optind];
 		if (!f || strcmp(f, "-") == 0) {
@@ -192,7 +179,7 @@ main(int ac, char *av[])
 	} while (++optind < ac);
 
 	if (!dbg)
-		gasemitfin(outf);
+		T.emitfin(outf);
 
 	exit(0);
 }
diff --git a/rv64/emit.c b/rv64/emit.c
index 2656c60..f976ade 100644
--- a/rv64/emit.c
+++ b/rv64/emit.c
@@ -415,7 +415,7 @@ rv64_emitfn(Fn *fn, FILE *f)
 	Blk *b, *s;
 	Ins *i;
 
-	gasemitlnk(fn->name, &fn->lnk, ".text", f);
+	emitlnk(fn->name, &fn->lnk, ".text", f);
 
 	if (fn->vararg) {
 		/* TODO: only need space for registers
diff --git a/rv64/isel.c b/rv64/isel.c
index e41578b..3d9884f 100644
--- a/rv64/isel.c
+++ b/rv64/isel.c
@@ -41,7 +41,7 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
 			 * immediates
 			 */
 			assert(c->type == CBits);
-			n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
+			n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
 			vgrow(&fn->con, ++fn->ncon);
 			c = &fn->con[fn->ncon-1];
 			sprintf(buf, "fp%d", n);
diff --git a/rv64/targ.c b/rv64/targ.c
index 9360cf7..70701db 100644
--- a/rv64/targ.c
+++ b/rv64/targ.c
@@ -47,6 +47,8 @@ Target T_rv64 = {
 	.abi = rv64_abi,
 	.isel = rv64_isel,
 	.emitfn = rv64_emitfn,
+	.emitfin = elf_emitfin,
+	.asloc = ".L",
 };
 
 MAKESURE(rsave_size_ok, sizeof rv64_rsave == (NGPS+NFPS+1) * sizeof(int));