Skip to content

Commit

Permalink
Extend compressed to normal instruction if needed
Browse files Browse the repository at this point in the history
`c.j` => `j`.
  • Loading branch information
tyfkda committed Apr 27, 2024
1 parent 1910acc commit 8194e7a
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 11 deletions.
1 change: 0 additions & 1 deletion src/as/arch/riscv64/asm_code.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
58 changes: 50 additions & 8 deletions src/as/arch/riscv64/ir_asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,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);
Expand Down Expand Up @@ -183,7 +208,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;
Expand All @@ -198,14 +223,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);
}
}
}
}
Expand Down Expand Up @@ -241,6 +280,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);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/as/as.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,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;
Expand Down
1 change: 1 addition & 0 deletions src/as/ir_asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum UnresolvedKind {
UNRES_ABS64,

UNRES_RISCV_BRANCH,
UNRES_RISCV_JAL,
UNRES_RISCV_CALL,
UNRES_RISCV_PCREL_HI20,
UNRES_RISCV_PCREL_LO12_I,
Expand Down
2 changes: 1 addition & 1 deletion src/util/gen_section.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 8194e7a

Please sign in to comment.