Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Forney
e786f06032 rv64: use pc-relative addressing for globals
When extern was added, the rv64 code switched regular globals from
using la (a pseudo-instruction that uses pc-relative addressing
with auipc + addi) to lui + addi (absolute addressing). Presumably,
this was done to match gcc's output with -fPIC and -fno-PIC
respectively.  However, the key difference here is actually the
directive `%option pic` vs `%option nopic`, which determines whether
la uses the GOT or not.

This broke linking as PIE (for instance in compilers with
--enable-default-pie), even when there are no global references
outside the executable. The other architectures always use pc-relative
addressing, so rv64 should do the same.

It turns out there are more specific pseudo-instructions lla and
lga we can use instead. lla uses auipc+addi, and lga uses auipc+ld
from the GOT.

lga does not allow an offset. If you try to use one, it will assemble
without error, but fail at link time with

(.text+0x10): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20

For now, just add a check for this. A proper fix involves some
changes to rv64/isel like is done for amd64.
2026-06-08 12:01:16 +02:00
Michael Forney
80d745c842 arm64: fix extern with offset
We need to add the offset after loading from the GOT.

This is a fix for the issue reported in [0], and removes the offsets
in isel to avoid the problem with large offsets in the naive patch.
This is similar to what is done on amd64.

Tested with cproc bootstrap using extern on aarch64.

[0] https://lists.sr.ht/~mpu/qbe/%3Cd71fac06-1208-4e4f-85a4-e5edc7fd979c@app.fastmail.com%3E#%3C2F4DUTRJ9GA5V.3VK2QXK848F7U@mforney.org%3E
2026-06-08 11:56:20 +02:00
3 changed files with 23 additions and 22 deletions

View File

@ -292,12 +292,13 @@ loadaddr(Con *c, char *rn, E *e)
"\tadd\tR, R, #:tprel_lo12_nc:SO\n"; "\tadd\tR, R, #:tprel_lo12_nc:SO\n";
break; break;
case SExt: case SExt:
assert(c->bits.i == 0);
if (T.apple) if (T.apple)
s = "\tadrp\tR, S@gotpageO\n" s = "\tadrp\tR, S@gotpage\n"
"\tldr\tR, [R, S@gotpageoffO]\n"; "\tldr\tR, [R, S@gotpageoff]\n";
else else
s = "\tadrp\tR, :got:SO\n" s = "\tadrp\tR, :got:S\n"
"\tldr\tR, [R, #:got_lo12:SO]\n"; "\tldr\tR, [R, #:got_lo12:S]\n";
break; break;
} }

View File

@ -78,9 +78,8 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
switch (rtype(r0)) { switch (rtype(r0)) {
case RCon: case RCon:
c = &fn->con[r0.val]; c = &fn->con[r0.val];
if (T.apple if (c->type == CAddr && ((c->sym.type & SExt)
&& c->type == CAddr || (T.apple && (c->sym.type & SThr)))) {
&& (c->sym.type & SThr)) {
r1 = newtmp("isel", Kl, fn); r1 = newtmp("isel", Kl, fn);
*pr = r1; *pr = r1;
if (c->bits.i) { if (c->bits.i) {
@ -91,16 +90,19 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
emit(Oadd, Kl, r1, r2, r3); emit(Oadd, Kl, r1, r2, r3);
r1 = r2; r1 = r2;
} }
if (T.apple && (c->sym.type & SThr)) {
emit(Ocopy, Kl, r1, TMP(R0), R); emit(Ocopy, Kl, r1, TMP(R0), R);
r1 = newtmp("isel", Kl, fn); r1 = newtmp("isel", Kl, fn);
r2 = newtmp("isel", Kl, fn); r2 = newtmp("isel", Kl, fn);
emit(Ocall, 0, R, r1, CALL(33)); emit(Ocall, 0, R, r1, CALL(33));
emit(Ocopy, Kl, TMP(R0), r2, R); emit(Ocopy, Kl, TMP(R0), r2, R);
emit(Oload, Kl, r1, r2, R); emit(Oload, Kl, r1, r2, R);
r1 = r2;
}
cc = *c; cc = *c;
cc.bits.i = 0; cc.bits.i = 0;
r3 = newcon(&cc, fn); r3 = newcon(&cc, fn);
emit(Ocopy, Kl, r2, r3, R); emit(Ocopy, Kl, r1, r3, R);
break; break;
} }
if (KBASE(k) == 0 && phi) if (KBASE(k) == 0 && phi)

View File

@ -133,8 +133,12 @@ emitaddr(Con *c, FILE *f)
{ {
assert((c->sym.type & ~SExt) == SGlo); assert((c->sym.type & ~SExt) == SGlo);
fputs(str(c->sym.id), f); fputs(str(c->sym.id), f);
if (c->bits.i) if (c->bits.i) {
/* TODO: fix isel to ensure no offset for SGlo */
if (c->sym.type & SExt)
die("extern with offset is not supported");
fprintf(f, "+%"PRIi64, c->bits.i); fprintf(f, "+%"PRIi64, c->bits.i);
}
} }
static void static void
@ -233,14 +237,8 @@ loadaddr(Con *c, char *rn, FILE *f)
switch (c->sym.type) { switch (c->sym.type) {
case SGlo: case SGlo:
fprintf(f, "\tlui %s, %%hi(", rn);
emitaddr(c, f);
fprintf(f, ")\n\taddi %s, %s, %%lo(", rn, rn);
emitaddr(c, f);
fputs(")\n", f);
break;
case SExt: case SExt:
fprintf(f, "\tla %s, ", rn); fprintf(f, "\t%s %s, ", c->sym.type == SExt ? "lga" : "lla", rn);
emitaddr(c, f); emitaddr(c, f);
fputc('\n', f); fputc('\n', f);
break; break;