From 31ecaa7c28c787ee3992aa5f2a1b6fd28fa64213 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 15 Jul 2019 23:15:51 +0200 Subject: [PATCH] riscv: GOT loads, signed remainder, ELF flags * support loading sym addresses from GOT: important for weak syms, fixes 104_inline. This is still incomplete, it only works for taking the sym address, not for directly loading/storing into such symbols (i.e. not for VT_LVAL) * another op: '%' * ELF flags: add EF_RISCV_FLOAT_ABI_DOUBLE, which is our ABI. --- riscv64-gen.c | 29 ++++++++++++++++++++++------- riscv64-link.c | 8 ++++---- tccelf.c | 2 ++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/riscv64-gen.c b/riscv64-gen.c index 2eab4e41..c2a71191 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -189,12 +189,22 @@ ST_FUNC void load(int r, SValue *sv) tcc_error("unimp: load(non-local lval)"); } } else if (v == VT_CONST) { - int rb = 0, do32bit = 8; + int rb = 0, do32bit = 8, doload = 0; assert(!is_float(sv->type.t) && is_ireg(r)); if (fr & VT_SYM) { static Sym label; - greloca(cur_text_section, sv->sym, ind, - R_RISCV_PCREL_HI20, sv->c.i); + if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax + 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) { label.v = tok_alloc(".L0 ", 4)->tok; label.type.t = VT_VOID | VT_STATIC; @@ -205,8 +215,6 @@ ST_FUNC void load(int r, SValue *sv) greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0); rb = rr; - fc = 0; - sv->c.i = 0; do32bit = 0; } if (is_float(sv->type.t)) @@ -244,7 +252,12 @@ ST_FUNC void load(int r, SValue *sv) } if (((unsigned)fc + (1 << 11)) >> 12) o(0x37 | (rr << 7) | ((0x800 + fc) & 0xfffff000)), rb = rr; //lui RR, upper(fc) - EI(0x13 | do32bit, 0, rr, rb, fc << 20 >> 20); // addi[w] R, x0|R, FC + if (doload) { + EI(0x03, 3, rr, rr, 0); // ld RR, 0(RR) + if (fc) + EI(0x13 | do32bit, 0, rr, rr, fc << 20 >> 20); // addi[w] R, x0|R, FC + } else + EI(0x13 | do32bit, 0, rr, rb, fc << 20 >> 20); // addi[w] R, x0|R, FC } else if (v == VT_LOCAL) { assert(is_ireg(r)); if (((unsigned)fc + (1 << 11)) >> 12) @@ -636,7 +649,6 @@ static void gen_opil(int op, int ll) d = ireg(d); ll = ll ? 0 : 8; switch (op) { - case '%': case TOK_PDIV: default: tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL)); @@ -671,6 +683,9 @@ static void gen_opil(int op, int ll) case '|': o(0x33 | (d << 7) | (a << 15) | (b << 20) | (6 << 12)); // or d, a, b break; + case '%': + o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (6 << 12)); //rem d, a, b + break; case TOK_UMOD: o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (7 << 12)); //remu d, a, b break; diff --git a/riscv64-link.c b/riscv64-link.c index 765475c1..6e850aef 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -19,6 +19,7 @@ #else /* !TARGET_DEFS_ONLY */ +//#define DEBUG_RELOC #include "tcc.h" /* Returns 1 for a code relocation, 0 for a data relocation. For unknown @@ -177,9 +178,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, uint64_t off64; uint32_t off32; int sym_index = ELFW(R_SYM)(rel->r_info); -#ifdef DEBUG_RELOC ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; -#endif switch(type) { case R_RISCV_ALIGN: @@ -223,8 +222,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, #endif off64 = (int64_t)(val - addr + 0x800) >> 12; if ((off64 + ((uint64_t)1 << 20)) >> 21) - tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx", - off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21)); + tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx sym=%s", + off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21), + symtab_section->link->data + sym->st_name); write32le(ptr, (read32le(ptr) & 0xfff) | ((off64 & 0xfffff) << 12)); last_hi.addr = addr; diff --git a/tccelf.c b/tccelf.c index ae468c04..5b6737e7 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1910,6 +1910,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, #else ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; #endif +#elif defined TCC_TARGET_RISCV64 + ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE; #endif switch(file_type) { default: