mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-01 04:20:09 +08:00
riscv: fix relocs for global syms
loads and stores to global symbols need to go via the GOT (at least for weaks), otherwise -run doesn't work. Ideally we'd generate GOT relocs (and loads) always and replace them with PCREL relocs and adds during linking.
This commit is contained in:
parent
69c77d1597
commit
06184aec53
@ -145,7 +145,7 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
int bt = sv->type.t & VT_BTYPE;
|
int bt = sv->type.t & VT_BTYPE;
|
||||||
int align, size = type_size(&sv->type, &align);
|
int align, size = type_size(&sv->type, &align);
|
||||||
if (fr & VT_LVAL) {
|
if (fr & VT_LVAL) {
|
||||||
int func3, opcode = 0x03;
|
int func3, opcode = 0x03, doload = 0;
|
||||||
if (is_freg(r)) {
|
if (is_freg(r)) {
|
||||||
assert(bt == VT_DOUBLE || bt == VT_FLOAT);
|
assert(bt == VT_DOUBLE || bt == VT_FLOAT);
|
||||||
opcode = 0x07;
|
opcode = 0x07;
|
||||||
@ -176,12 +176,19 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
EI(opcode, func3, rr, ireg(v), fc); // l[bhwd][u] RR, 0(V)
|
EI(opcode, func3, rr, ireg(v), fc); // l[bhwd][u] RR, 0(V)
|
||||||
} else if (v == VT_CONST && (fr & VT_SYM)) {
|
} else if (v == VT_CONST && (fr & VT_SYM)) {
|
||||||
static Sym label;
|
static Sym label;
|
||||||
int addend = 0, tempr;
|
int tempr;
|
||||||
if (1 || ((unsigned)fc + (1 << 11)) >> 12)
|
if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax
|
||||||
addend = fc, fc = 0;
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
|
R_RISCV_PCREL_HI20, sv->c.i);
|
||||||
greloca(cur_text_section, sv->sym, ind,
|
fc = 0;
|
||||||
R_RISCV_PCREL_HI20, addend);
|
sv->c.i = 0;
|
||||||
|
} else {
|
||||||
|
if (((unsigned)fc + (1 << 11)) >> 12)
|
||||||
|
tcc_error("unimp: large addend for global address");
|
||||||
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
|
R_RISCV_GOT_HI20, 0);
|
||||||
|
doload = 1;
|
||||||
|
}
|
||||||
if (!label.v) {
|
if (!label.v) {
|
||||||
label.v = tok_alloc(".L0 ", 4)->tok;
|
label.v = tok_alloc(".L0 ", 4)->tok;
|
||||||
label.type.t = VT_VOID | VT_STATIC;
|
label.type.t = VT_VOID | VT_STATIC;
|
||||||
@ -192,6 +199,12 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
o(0x17 | (tempr << 7)); // auipc TR, 0 %pcrel_hi(sym)+addend
|
o(0x17 | (tempr << 7)); // auipc TR, 0 %pcrel_hi(sym)+addend
|
||||||
greloca(cur_text_section, &label, ind,
|
greloca(cur_text_section, &label, ind,
|
||||||
R_RISCV_PCREL_LO12_I, 0);
|
R_RISCV_PCREL_LO12_I, 0);
|
||||||
|
if (doload) {
|
||||||
|
EI(0x03, 3, tempr, tempr, 0); // ld TR, 0(TR)
|
||||||
|
if (fc)
|
||||||
|
EI(0x13, 0, tempr, tempr, fc << 20 >> 20); // addi TR, TR, FC
|
||||||
|
fc = 0;
|
||||||
|
}
|
||||||
EI(opcode, func3, rr, tempr, fc); // l[bhwd][u] RR, fc(TR)
|
EI(opcode, func3, rr, tempr, fc); // l[bhwd][u] RR, fc(TR)
|
||||||
} else if (v == VT_LLOCAL) {
|
} else if (v == VT_LLOCAL) {
|
||||||
int br = 8, tempr = is_ireg(r) ? rr : 5;
|
int br = 8, tempr = is_ireg(r) ? rr : 5;
|
||||||
@ -361,13 +374,20 @@ ST_FUNC void store(int r, SValue *sv)
|
|||||||
ptrreg, rr, fc); // s[bhwd] RR, fc(PTRREG)
|
ptrreg, rr, fc); // s[bhwd] RR, fc(PTRREG)
|
||||||
} else if ((sv->r & ~VT_LVAL_TYPE) == (VT_CONST | VT_SYM | VT_LVAL)) {
|
} else if ((sv->r & ~VT_LVAL_TYPE) == (VT_CONST | VT_SYM | VT_LVAL)) {
|
||||||
static Sym label;
|
static Sym label;
|
||||||
int tempr, addend = 0;
|
int tempr, doload = 0;
|
||||||
if (1 || ((unsigned)fc + (1 << 11)) >> 12)
|
|
||||||
addend = fc, fc = 0;
|
|
||||||
|
|
||||||
tempr = 5; // t0
|
tempr = 5; // t0
|
||||||
greloca(cur_text_section, sv->sym, ind,
|
if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax
|
||||||
R_RISCV_PCREL_HI20, addend);
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
|
R_RISCV_PCREL_HI20, sv->c.i);
|
||||||
|
fc = 0;
|
||||||
|
sv->c.i = 0;
|
||||||
|
} else {
|
||||||
|
if (((unsigned)fc + (1 << 11)) >> 12)
|
||||||
|
tcc_error("unimp: large addend for global address");
|
||||||
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
|
R_RISCV_GOT_HI20, 0);
|
||||||
|
doload = 1;
|
||||||
|
}
|
||||||
if (!label.v) {
|
if (!label.v) {
|
||||||
label.v = tok_alloc(".L0 ", 4)->tok;
|
label.v = tok_alloc(".L0 ", 4)->tok;
|
||||||
label.type.t = VT_VOID | VT_STATIC;
|
label.type.t = VT_VOID | VT_STATIC;
|
||||||
@ -376,7 +396,13 @@ ST_FUNC void store(int r, SValue *sv)
|
|||||||
put_extern_sym(&label, cur_text_section, ind, 0);
|
put_extern_sym(&label, cur_text_section, ind, 0);
|
||||||
o(0x17 | (tempr << 7)); // auipc TEMPR, 0 %pcrel_hi(sym)+addend
|
o(0x17 | (tempr << 7)); // auipc TEMPR, 0 %pcrel_hi(sym)+addend
|
||||||
greloca(cur_text_section, &label, ind,
|
greloca(cur_text_section, &label, ind,
|
||||||
R_RISCV_PCREL_LO12_S, 0);
|
doload ? R_RISCV_PCREL_LO12_I : R_RISCV_PCREL_LO12_S, 0);
|
||||||
|
if (doload) {
|
||||||
|
EI(0x03, 3, tempr, tempr, 0); // ld TR, 0(TR)
|
||||||
|
if (fc)
|
||||||
|
EI(0x13, 0, tempr, tempr, fc << 20 >> 20); // addi TR, TR, FC
|
||||||
|
fc = 0;
|
||||||
|
}
|
||||||
if (is_freg(r))
|
if (is_freg(r))
|
||||||
ES(0x27, size == 4 ? 2 : 3, tempr, rr, fc); // fs[wd] RR, fc(TEMPR)
|
ES(0x27, size == 4 ? 2 : 3, tempr, rr, fc); // fs[wd] RR, fc(TEMPR)
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user