From 0f62ca9c5102cf2a14dc93fadf52e5f0b6913784 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 25 Apr 2024 12:28:56 +0900 Subject: [PATCH] Extend compressed to normal instruction if needed `c.j` => `j`. --- src/as/arch/riscv64/asm_code.c | 1 - src/as/arch/riscv64/ir_asm.c | 58 +++++++++++++++++++++++++++++----- src/as/as.c | 3 +- src/as/ir_asm.h | 1 + src/util/gen_section.c | 2 +- 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index fa4a52f2c..2bb5f4629 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -499,7 +499,6 @@ static unsigned char *asm_sd(Inst *inst, Code *code) { static unsigned char *asm_j(Inst *inst, Code *code) { UNUSED(inst); - // TODO: Non compact instruction? // imm[11|4|9:8|10|6|7|3:1|5] C_J(); return code->buf; diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 1058fd62c..f8795234e 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -153,6 +153,31 @@ bool calc_label_address(uintptr_t start_address, Vector **section_irs, Table *la return settle; } +#ifndef MAKE_CODE32 +#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) +#endif +void make_code32(Inst *inst, Code *code, unsigned int *buf, int len); + +#define ZERO 0 +#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) +#define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type +#define W_JAL(rd, imm) UTYPE(imm, rd, 0x6f) + +static bool make_jmp_long(IR *ir) { + if (ir->code.flag & INST_LONG_OFFSET) + return false; + + Code *code = &ir->code; + Inst *inst = code->inst; + // Change to long offset, and recalculate. + code->flag |= INST_LONG_OFFSET; + code->len = 0; + assert(inst->op == J); + + W_JAL(ZERO, 0); + return true; +} + bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector *unresolved) { assert(unresolved != NULL); vec_clear(unresolved); @@ -221,7 +246,7 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * // Put rela even if the label is defined in the same object file. UnresolvedInfo *info; info = calloc_or_die(sizeof(*info)); - info->kind = UNRES_RISCV_RVC_JUMP; + info->kind = (ir->code.flag & INST_LONG_OFFSET) ? UNRES_RISCV_JAL : UNRES_RISCV_RVC_JUMP; info->label = value.label; info->src_section = sec; info->offset = address - start_address; @@ -236,14 +261,28 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * if (target_address != 0) { Code *code = &ir->code; int64_t offset = target_address - VOIDP2INT(address); - if (offset < (1 << 11) && offset >= -(1 << 11)) { + bool long_offset = ir->code.flag & INST_LONG_OFFSET; + if (!long_offset) { assert(code->len == 2); - uint16_t *buf = (uint16_t*)code->buf; - // Compressed: imm[11|4|9:8|10|6|7|3:1|5] -#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) - buf[0] = (buf[0] & 0xe003) | (IMM(offset, 11, 11) << 12) | (IMM(offset, 4, 4) << 11) | - (IMM(offset, 9, 8) << 9) | (IMM(offset, 10, 10) << 8) | (IMM(offset, 6, 6) << 7) | - (IMM(offset, 7, 7) << 6) | (IMM(offset, 3, 1) << 3) | (IMM(offset, 5, 5) << 2); + if (offset < (1 << 11) && offset >= -(1 << 11)) { + uint16_t *buf = (uint16_t*)code->buf; + // Compressed: imm[11|4|9:8|10|6|7|3:1|5] + buf[0] = (buf[0] & 0xe003) | (IMM(offset, 11, 11) << 12) | (IMM(offset, 4, 4) << 11) | + (IMM(offset, 9, 8) << 9) | (IMM(offset, 10, 10) << 8) | (IMM(offset, 6, 6) << 7) | + (IMM(offset, 7, 7) << 6) | (IMM(offset, 3, 1) << 3) | (IMM(offset, 5, 5) << 2); + } else { + size_upgraded |= make_jmp_long(ir); + } + } else { + if (offset < (1 << 20) && offset >= -(1 << 20)) { + uint32_t *buf = (uint32_t*)code->buf; + // Compressed: imm[20|10:1|11|19:12] + buf[0] = (buf[0] & 0x000007ff) | (IMM(offset, 20, 20) << 31) | (IMM(offset, 10, 1) << 21) | + (IMM(offset, 11, 11) << 20) | (IMM(offset, 19, 12) << 12); + } else { + // Linker extends the branch instruction to long offset? + assert(false); + } } } } @@ -279,6 +318,9 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * uint32_t *buf = (uint32_t*)code->buf; // STYPE buf[0] = (buf[0] & 0x01fff07f) | (IMM(offset, 11, 5) << 25) | (IMM(offset, 4, 0) << 7); + } else { + // Linker extends the branch instruction to long offset? + // assert(false); } } } diff --git a/src/as/as.c b/src/as/as.c index 8c5652115..748cc27ae 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -292,13 +292,14 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add; } break; + case UNRES_RISCV_JAL: case UNRES_RISCV_RVC_JUMP: { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(symidx, R_RISCV_RVC_JUMP); + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_JAL ? R_RISCV_JAL : R_RISCV_RVC_JUMP); rela->r_addend = u->add; } break; diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index ad252ac11..d4aec40da 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -38,6 +38,7 @@ enum UnresolvedKind { UNRES_ABS64, UNRES_RISCV_BRANCH, + UNRES_RISCV_JAL, UNRES_RISCV_CALL, UNRES_RISCV_PCREL_HI20, UNRES_RISCV_PCREL_LO12_I, diff --git a/src/util/gen_section.c b/src/util/gen_section.c index 1596e60e4..e0f03a610 100644 --- a/src/util/gen_section.c +++ b/src/util/gen_section.c @@ -15,7 +15,7 @@ typedef struct { static Section sections[SECTION_COUNT]; static size_t bss_size; -size_t section_aligns[SECTION_COUNT] = {1, 1, 1, 1}; +size_t section_aligns[SECTION_COUNT] = {8, 8, 1, 1}; uintptr_t section_start_addresses[SECTION_COUNT]; void add_bss(size_t size) {