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.
Unified · Split
| @@ -145,7 +145,7 @@ ST_FUNC void load(int r, SValue *sv) · 144 unmodified lines | ||
| 145 | 145 | int bt = sv->type.t & VT_BTYPE; |
| 146 | 146 | int align, size = type_size(&sv->type, &align); |
| 147 | 147 | if (fr & VT_LVAL) { |
| 148 | − int func3, opcode = 0x03; | |
| 148 | + int func3, opcode = 0x03, doload = 0; | |
| 149 | 149 | if (is_freg(r)) { |
| 150 | 150 | assert(bt == VT_DOUBLE || bt == VT_FLOAT); |
| 151 | 151 | opcode = 0x07; |
| @@ -176,12 +176,19 @@ ST_FUNC void load(int r, SValue *sv) · 24 unmodified lines | ||
| 176 | 176 | EI(opcode, func3, rr, ireg(v), fc); // l[bhwd][u] RR, 0(V) |
| 177 | 177 | } else if (v == VT_CONST && (fr & VT_SYM)) { |
| 178 | 178 | static Sym label; |
| 179 | − int addend = 0, tempr; | |
| 180 | − if (1 || ((unsigned)fc + (1 << 11)) >> 12) | |
| 181 | − addend = fc, fc = 0; | |
| 182 | − | |
| 183 | − greloca(cur_text_section, sv->sym, ind, | |
| 184 | − R_RISCV_PCREL_HI20, addend); | |
| 179 | + int tempr; | |
| 180 | + if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax | |
| 181 | + greloca(cur_text_section, sv->sym, ind, | |
| 182 | + R_RISCV_PCREL_HI20, sv->c.i); | |
| 183 | + fc = 0; | |
| 184 | + sv->c.i = 0; | |
| 185 | + } else { | |
| 186 | + if (((unsigned)fc + (1 << 11)) >> 12) | |
| 187 | + tcc_error("unimp: large addend for global address"); | |
| 188 | + greloca(cur_text_section, sv->sym, ind, | |
| 189 | + R_RISCV_GOT_HI20, 0); | |
| 190 | + doload = 1; | |
| 191 | + } | |
| 185 | 192 | if (!label.v) { |
| 186 | 193 | label.v = tok_alloc(".L0 ", 4)->tok; |
| 187 | 194 | label.type.t = VT_VOID | VT_STATIC; |
| @@ -192,6 +199,12 @@ ST_FUNC void load(int r, SValue *sv) · 4 unmodified lines | ||
| 192 | 199 | o(0x17 | (tempr << 7)); // auipc TR, 0 %pcrel_hi(sym)+addend |
| 193 | 200 | greloca(cur_text_section, &label, ind, |
| 194 | 201 | R_RISCV_PCREL_LO12_I, 0); |
| 202 | + if (doload) { | |
| 203 | + EI(0x03, 3, tempr, tempr, 0); // ld TR, 0(TR) | |
| 204 | + if (fc) | |
| 205 | + EI(0x13, 0, tempr, tempr, fc << 20 >> 20); // addi TR, TR, FC | |
| 206 | + fc = 0; | |
| 207 | + } | |
| 195 | 208 | EI(opcode, func3, rr, tempr, fc); // l[bhwd][u] RR, fc(TR) |
| 196 | 209 | } else if (v == VT_LLOCAL) { |
| 197 | 210 | int br = 8, tempr = is_ireg(r) ? rr : 5; |
| @@ -361,13 +374,20 @@ ST_FUNC void store(int r, SValue *sv) · 163 unmodified lines | ||
| 361 | 374 | ptrreg, rr, fc); // s[bhwd] RR, fc(PTRREG) |
| 362 | 375 | } else if ((sv->r & ~VT_LVAL_TYPE) == (VT_CONST | VT_SYM | VT_LVAL)) { |
| 363 | 376 | static Sym label; |
| 364 | − int tempr, addend = 0; | |
| 365 | − if (1 || ((unsigned)fc + (1 << 11)) >> 12) | |
| 366 | − addend = fc, fc = 0; | |
| 367 | − | |
| 377 | + int tempr, doload = 0; | |
| 368 | 378 | tempr = 5; // t0 |
| 369 | − greloca(cur_text_section, sv->sym, ind, | |
| 370 | − R_RISCV_PCREL_HI20, addend); | |
| 379 | + if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax | |
| 380 | + greloca(cur_text_section, sv->sym, ind, | |
| 381 | + R_RISCV_PCREL_HI20, sv->c.i); | |
| 382 | + fc = 0; | |
| 383 | + sv->c.i = 0; | |
| 384 | + } else { | |
| 385 | + if (((unsigned)fc + (1 << 11)) >> 12) | |
| 386 | + tcc_error("unimp: large addend for global address"); | |
| 387 | + greloca(cur_text_section, sv->sym, ind, | |
| 388 | + R_RISCV_GOT_HI20, 0); | |
| 389 | + doload = 1; | |
| 390 | + } | |
| 371 | 391 | if (!label.v) { |
| 372 | 392 | label.v = tok_alloc(".L0 ", 4)->tok; |
| 373 | 393 | label.type.t = VT_VOID | VT_STATIC; |
| @@ -376,7 +396,13 @@ ST_FUNC void store(int r, SValue *sv) · 2 unmodified lines | ||
| 376 | 396 | put_extern_sym(&label, cur_text_section, ind, 0); |
| 377 | 397 | o(0x17 | (tempr << 7)); // auipc TEMPR, 0 %pcrel_hi(sym)+addend |
| 378 | 398 | greloca(cur_text_section, &label, ind, |
| 379 | − R_RISCV_PCREL_LO12_S, 0); | |
| 399 | + doload ? R_RISCV_PCREL_LO12_I : R_RISCV_PCREL_LO12_S, 0); | |
| 400 | + if (doload) { | |
| 401 | + EI(0x03, 3, tempr, tempr, 0); // ld TR, 0(TR) | |
| 402 | + if (fc) | |
| 403 | + EI(0x13, 0, tempr, tempr, fc << 20 >> 20); // addi TR, TR, FC | |
| 404 | + fc = 0; | |
| 405 | + } | |
| 380 | 406 | if (is_freg(r)) |
| 381 | 407 | ES(0x27, size == 4 ? 2 : 3, tempr, rr, fc); // fs[wd] RR, fc(TEMPR) |
| 382 | 408 | else |