From ee1ba35861c14db263669778715fb2d92244173a Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 27 Apr 2024 14:02:02 +0900 Subject: [PATCH 01/11] Funcall `R_AARCH64_CALL26` --- include/elf.h | 2 + src/as/arch/aarch64/aarch64_code.h | 15 +++++ src/as/arch/aarch64/asm_code.c | 53 ++++++++++++++++- src/as/arch/aarch64/inst.h | 14 +++++ src/as/arch/aarch64/ir_asm.c | 52 +++++++++++++++-- src/as/arch/aarch64/parse_aarch64.c | 91 +++++++++++++++++++++++++++++ src/as/arch/riscv64/ir_asm.c | 2 +- src/as/as.c | 10 +++- src/as/ir_asm.h | 2 +- 9 files changed, 231 insertions(+), 10 deletions(-) create mode 100644 src/as/arch/aarch64/aarch64_code.h diff --git a/include/elf.h b/include/elf.h index 27aee079b..9f0e4ab5f 100644 --- a/include/elf.h +++ b/include/elf.h @@ -147,6 +147,8 @@ typedef struct { #define R_X86_64_PC32 (2) /* PC relative 32 bit signed */ #define R_X86_64_PLT32 (4) /* 32 bit PLT address */ +#define R_AARCH64_CALL26 283 + #define R_RISCV_64 (2) #define R_RISCV_BRANCH (16) #define R_RISCV_JAL (17) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h new file mode 100644 index 000000000..687ccc26f --- /dev/null +++ b/src/as/arch/aarch64/aarch64_code.h @@ -0,0 +1,15 @@ +#pragma once + +#define W_MOVK(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x72800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) +#define W_MOVZ(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x52800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) +#define W_MOVN(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x12800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) + +#define W_LDP(sz, rs1, rs2, ofs, base, prepost) MAKE_CODE32(inst, code, 0x28400000U | ((sz) << 31) | ((prepost) << 23) | (((((ofs) >> 3) & ((1U << 7) - 1))) << 15) | ((rs2) << 10) | ((base) << 5) | (rs1)) +#define W_STP(sz, rs1, rs2, ofs, base, prepost) MAKE_CODE32(inst, code, 0x28000000U | ((sz) << 31) | ((prepost) << 23) | (((((ofs) >> 3) & ((1U << 7) - 1))) << 15) | ((rs2) << 10) | ((base) << 5) | (rs1)) + +#define W_BL(offset) MAKE_CODE32(inst, code, 0x94000000U | ((offset) & ((1U << 26) - 1))) +#define W_BLR(rn) MAKE_CODE32(inst, code, 0xd63f0000U | ((rn) << 5)) +#define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) + + + diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index cfb5062d5..93aa062d5 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -4,10 +4,15 @@ #include #include // memcpy +#include "aarch64_code.h" #include "inst.h" #include "parse_asm.h" #include "util.h" +#define ZERO 31 +#define SP 31 +#define LR 30 + void make_code16(Inst *inst, Code *code, unsigned short *buf, int len) { assert(code->len + len <= (int)sizeof(code->buf)); code->inst = inst; @@ -36,13 +41,51 @@ static unsigned char *asm_noop(Inst *inst, Code *code) { static unsigned char *asm_mov(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; - uint32_t x = 0x52800000U | (opr1->reg.size == REG64 ? (1U << 31) : 0U) | (opr2->immediate << 5) | opr1->reg.no; - MAKE_CODE32(inst, code, x); + if (opr2->type == IMMEDIATE) { + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + W_MOVZ(sz, opr1->reg.no, opr2->immediate, 0); + return code->buf; + } + return NULL; +} + +static unsigned char *asm_ldpstp(Inst *inst, Code *code) { + static const uint32_t kPrePost[] = { 2 , 3, 1 }; + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + assert(opr1->reg.size == opr2->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + Operand *opr3 = &inst->opr[2]; + assert(opr3->indirect.reg.size == REG64); + assert(opr3->indirect.offset == NULL || opr3->indirect.offset->kind == EX_FIXNUM); + int64_t offset = opr3->indirect.offset != NULL ? opr3->indirect.offset->fixnum : 0; + assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); + uint32_t base = opr3->indirect.reg.no; + uint32_t prepost = kPrePost[opr3->indirect.prepost]; + switch (inst->op) { + case LDP: W_LDP(sz, opr1->reg.no, opr2->reg.no, offset, base, prepost); break; + case STP: W_STP(sz, opr1->reg.no, opr2->reg.no, offset, base, prepost); break; + default: assert(false); break; + } return code->buf; } +static unsigned char *asm_bl(Inst *inst, Code *code) { + W_BL(0); + return code->buf; +} + +static unsigned char *asm_blr(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + if (opr1->reg.size == REG64) { + W_BLR(opr1->reg.no); + return code->buf; + } + return NULL; +} + static unsigned char *asm_ret(Inst *inst, Code *code) { - MAKE_CODE32(inst, code, 0xd65f03c0); + W_RET(LR); return code->buf; } @@ -53,6 +96,10 @@ typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); static const AsmInstFunc table[] = { [NOOP] = asm_noop, [MOV] = asm_mov, + [LDP] = asm_ldpstp, + [STP] = asm_ldpstp, + [BL] = asm_bl, + [BLR] = asm_blr, [RET] = asm_ret, }; diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index ec384b263..8bbed620c 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -9,6 +9,8 @@ typedef struct Expr Expr; enum Opcode { NOOP, MOV, + LDP, STP, + BL, BLR, RET, }; @@ -26,6 +28,10 @@ enum OperandType { NOOPERAND, REG, // reg IMMEDIATE, // 1234 + DIRECT, // foobar + 345 + INDIRECT, // indirect: [reg,#12] + // pre-index: [reg,#34]! + // post-index: [reg],#34 }; typedef struct { @@ -33,6 +39,14 @@ typedef struct { union { Reg reg; int64_t immediate; + struct { + Expr *expr; + } direct; + struct { + Expr *offset; + Reg reg; + int prepost; // 0=none, 1=pre, 2=post + } indirect; }; } Operand; diff --git a/src/as/arch/aarch64/ir_asm.c b/src/as/arch/aarch64/ir_asm.c index b36ea6e7b..058c3377b 100644 --- a/src/as/arch/aarch64/ir_asm.c +++ b/src/as/arch/aarch64/ir_asm.c @@ -3,6 +3,7 @@ #include +#include "aarch64_code.h" #include "gen_section.h" #include "parse_asm.h" #include "table.h" @@ -114,10 +115,53 @@ bool calc_label_address(uintptr_t start_address, Vector **section_irs, Table *la } bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector *unresolved) { - UNUSED(section_irs); - UNUSED(label_table); - UNUSED(unresolved); - return true; + assert(unresolved != NULL); + vec_clear(unresolved); + bool size_upgraded = false; + for (int sec = 0; sec < SECTION_COUNT; ++sec) { + Vector *irs = section_irs[sec]; + uintptr_t start_address = irs->len > 0 ? ((IR*)irs->data[0])->address : 0; + for (int i = 0, len = irs->len; i < len; ++i) { + IR *ir = irs->data[i]; + uintptr_t address = ir->address; + switch (ir->kind) { + case IR_CODE: + { + Inst *inst = ir->code.inst; + switch (inst->op) { + case BL: + if (inst->opr[0].type == DIRECT) { + Value value = calc_expr(label_table, inst->opr[0].direct.expr); + if (value.label != NULL) { + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = UNRES_CALL; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + } + break; + default: + break; + } + } + break; + case IR_EXPR_BYTE: + case IR_EXPR_SHORT: + case IR_EXPR_LONG: + case IR_EXPR_QUAD: + case IR_LABEL: + case IR_DATA: + case IR_BSS: + case IR_ALIGN: + break; + } + } + } + + return !size_upgraded; } void emit_irs(Vector **section_irs) { diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index aaca9fe7a..c82789fab 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -11,11 +11,16 @@ enum RawOpcode { R_NOOP, R_MOV, + R_LDP, R_STP, + R_BL, R_BLR, R_RET, }; const char *kRawOpTable[] = { "mov", + "ldp", + "stp", + "bl", "blr", "ret", NULL, }; @@ -77,6 +82,7 @@ inline bool is_reg64(enum RegType reg) { #define R64 (1 << 1) #define IMM (1 << 2) #define IND (1 << 3) +#define EXP (1 << 4) static enum RegType find_register(const char **pp, unsigned int flag) { const char *p = *pp; @@ -99,6 +105,70 @@ static enum RegType find_register(const char **pp, unsigned int flag) { return NOREG; } +static bool parse_indirect_register(ParseInfo *info, Operand *operand) { + const char *p = skip_whitespaces(info->p); + enum RegType reg = find_register(&p, R64); + if (reg == NOREG) { + parse_error(info, "Base register expected"); + return false; + } + if (is_reg64(reg)) { + operand->indirect.reg.size = REG64; + operand->indirect.reg.no = reg - X0; + } else { + parse_error(info, "Base register expected"); + } + + p = skip_whitespaces(p); + Expr *offset = NULL; + int prepost = 0; + if (*p == ',') { + p = skip_whitespaces(p + 1); + if (*p == '#') { + ++p; + int64_t imm; + if (immediate(&p, &imm)) { + offset = new_expr(EX_FIXNUM); + offset->fixnum = imm; + } else { + parse_error(info, "Offset expected"); + } + } + if (*p == ']') { + if (*++p == '!') { + prepost = 1; + ++p; + } + } else { + parse_error(info, "`]' expected"); + } + } else if (*p == ']') { + p = skip_whitespaces(p + 1); + if (*p == ',') { + const char *q = skip_whitespaces(p + 1); + if (*q == '#') { + p = q + 1; + int64_t imm; + if (immediate(&p, &imm)) { + offset = new_expr(EX_FIXNUM); + offset->fixnum = imm; + prepost = 2; + } else { + parse_error(info, "Offset expected"); + } + } + } + } else { + parse_error(info, "`,` or `]' expected"); + } + + operand->type = INDIRECT; + operand->indirect.offset = offset; + operand->indirect.prepost = prepost; + info->p = p; + return true; +} + unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *operand) { const char *p = info->p; if (opr_flag & IMM) { @@ -111,6 +181,14 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper } } + if (opr_flag & IND) { + if (*p == '[') { + info->p = p + 1; + if (parse_indirect_register(info, operand)) + return IND; + } + } + if (opr_flag & (R32 | R64)) { enum RegType reg = find_register(&info->p, opr_flag); if (reg != NOREG) { @@ -134,10 +212,23 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper } } + if (opr_flag & EXP) { + Expr *expr = parse_expr(info); + if (expr != NULL) { + operand->type = DIRECT; + operand->direct.expr = expr; + return EXP; + } + } + return 0; } const ParseInstTable kParseInstTable[] = { [R_MOV] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){MOV, {R32 | R64, IMM}} } }, + [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, + [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, + [R_BL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BL, {EXP}} } }, + [R_BLR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLR, {R64}} } }, [R_RET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){RET} } }, }; diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index fade137f3..90b958065 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -321,7 +321,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_CALL; + info->kind = UNRES_CALL; info->label = value.label; info->src_section = sec; info->offset = address - start_address; diff --git a/src/as/as.c b/src/as/as.c index 04b356f36..dbaa26cce 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -268,16 +268,24 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add; } break; - case UNRES_RISCV_CALL: + + case UNRES_CALL: { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; +#if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 rela->r_info = ELF64_R_INFO(symidx, R_RISCV_CALL); +#elif XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + rela->r_info = ELF64_R_INFO(symidx, R_AARCH64_CALL26); +#else + assert(false); +#endif rela->r_addend = u->add; } break; + case UNRES_RISCV_PCREL_HI20: case UNRES_RISCV_PCREL_LO12_I: { diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index f02c0dba2..186a6154b 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -17,10 +17,10 @@ enum UnresolvedKind { UNRES_EXTERN_PC32, UNRES_OTHER_SECTION, UNRES_ABS64, + UNRES_CALL, UNRES_RISCV_BRANCH, UNRES_RISCV_JAL, - UNRES_RISCV_CALL, UNRES_RISCV_PCREL_HI20, UNRES_RISCV_PCREL_LO12_I, UNRES_RISCV_RVC_BRANCH, From 5fc1762a7ea9dc1ae4935b629c5f0b095f28a8c9 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 11 May 2024 08:45:52 +0900 Subject: [PATCH 02/11] Access global variable Output relocation for data. --- include/elf.h | 6 +- src/as/arch/aarch64/aarch64_code.h | 25 ++++++++- src/as/arch/aarch64/asm_code.c | 85 ++++++++++++++++++++++++++++- src/as/arch/aarch64/inst.h | 4 ++ src/as/arch/aarch64/ir_asm.c | 44 +++++++++++++++ src/as/arch/aarch64/parse_aarch64.c | 26 ++++++++- src/as/arch/riscv64/ir_asm.c | 6 +- src/as/as.c | 42 +++++++++++++- src/as/ir_asm.h | 6 +- src/as/parse_asm.c | 65 ++++++++++++++++++++-- src/as/parse_asm.h | 11 +++- 11 files changed, 298 insertions(+), 22 deletions(-) diff --git a/include/elf.h b/include/elf.h index 9f0e4ab5f..bc823a8c0 100644 --- a/include/elf.h +++ b/include/elf.h @@ -147,7 +147,11 @@ typedef struct { #define R_X86_64_PC32 (2) /* PC relative 32 bit signed */ #define R_X86_64_PLT32 (4) /* 32 bit PLT address */ -#define R_AARCH64_CALL26 283 +#define R_AARCH64_ABS64 257 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_CALL26 283 #define R_RISCV_64 (2) #define R_RISCV_BRANCH (16) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 687ccc26f..6f2d20095 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -1,15 +1,34 @@ #pragma once +#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) + #define W_MOVK(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x72800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) #define W_MOVZ(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x52800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) #define W_MOVN(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x12800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) +#define W_ADD_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x11000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_SUB_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x51000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) + +#define W_LDUR(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) +#define W_LDR_UIMM(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x39400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) +#define W_LDR(b, s, rt, ofs, base, prepost) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((prepost) << 10) | ((base) << 5) | (rt)) +#define W_STUR(b, rt, ofs, base) MAKE_CODE32(inst, code, 0x38000000U | ((b) << 30) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) +#define W_STR_UIMM(b, rt, ofs, base) MAKE_CODE32(inst, code, 0x39000000U | ((b) << 30) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) +#define W_STR(b, rt, ofs, base, prepost) MAKE_CODE32(inst, code, 0x38000000U | ((b) << 30) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((prepost) << 10) | ((base) << 5) | (rt)) #define W_LDP(sz, rs1, rs2, ofs, base, prepost) MAKE_CODE32(inst, code, 0x28400000U | ((sz) << 31) | ((prepost) << 23) | (((((ofs) >> 3) & ((1U << 7) - 1))) << 15) | ((rs2) << 10) | ((base) << 5) | (rs1)) #define W_STP(sz, rs1, rs2, ofs, base, prepost) MAKE_CODE32(inst, code, 0x28000000U | ((sz) << 31) | ((prepost) << 23) | (((((ofs) >> 3) & ((1U << 7) - 1))) << 15) | ((rs2) << 10) | ((base) << 5) | (rs1)) +#define W_LDR_R(sz, rt, base, rm, sz2, s, option) MAKE_CODE32(inst, code, 0xb8600800U | ((sz) << 30) | ((rm) << 16) | ((option) << 13) | ((s) << 12) | ((base) << 5) | (rt)) +#define W_LDRB_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x38400000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) +#define W_LDRSB_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x38c00000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) +#define W_LDRH_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x78400000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) +#define W_LDRSH_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x78c00000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) +#define W_STR_R(sz, rt, base, rm, option) MAKE_CODE32(inst, code, 0xb8200800U | ((sz) << 30) | ((rm) << 16) | ((option) << 13) | ((base) << 5) | (rt)) +#define W_STRB_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x38000000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) +#define W_STRH_R(rt, base, rm, option) MAKE_CODE32(inst, code, 0x78000000U | ((((ofs) & ((1U << 9) - 1))) << 12) | ((option) << 10) | ((base) << 5) | (rt)) + +#define W_ADRP(rd, imm) MAKE_CODE32(inst, code, 0x90000000U | (IMM(imm, 31, 30) << 29) | (IMM(imm, 29, 12) << 5) | (rd)) + #define W_BL(offset) MAKE_CODE32(inst, code, 0x94000000U | ((offset) & ((1U << 26) - 1))) #define W_BLR(rn) MAKE_CODE32(inst, code, 0xd63f0000U | ((rn) << 5)) #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) - - - diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 93aa062d5..333569682 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -32,6 +32,8 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { return false; } +static const uint32_t kPrePost[] = { 2, 3, 1 }; + static unsigned char *asm_noop(Inst *inst, Code *code) { UNUSED(inst); unsigned char *p = code->buf; @@ -49,8 +51,75 @@ static unsigned char *asm_mov(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_2ri(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + Operand *opr3 = &inst->opr[2]; + assert(opr1->reg.size == opr2->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + int64_t imm = 0; + if (opr3->type == IMMEDIATE) { + if (opr3->immediate < -(1 << 12) || opr3->immediate >= (1 << 12)) + return NULL; + imm = opr3->immediate; + } + + switch (inst->op) { + case ADD_I: + if (imm >= 0) W_ADD_I(sz, opr1->reg.no, opr2->reg.no, imm); + else W_SUB_I(sz, opr1->reg.no, opr2->reg.no, -imm); + break; + default: assert(false); return NULL; + } + return code->buf; +} + +static unsigned char *asm_ldrstr(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + Operand *opr2 = &inst->opr[1]; + assert(opr2->indirect.reg.size == REG64); + assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); + int64_t offset = opr2->indirect.offset != NULL ? opr2->indirect.offset->fixnum : 0; + assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); + uint32_t base = opr2->indirect.reg.no; + uint32_t prepost = kPrePost[opr2->indirect.prepost]; + switch (inst->op) { + case LDRB: case LDRH: case LDR: + case LDRSB: case LDRSH: + { + uint32_t b = inst->op - LDRB, s = 0; + if (b >= 3) { + b -= 3; + s = 1; + } + b |= sz; + if (opr2->indirect.prepost == 0) { + if (offset >= 0) + W_LDR_UIMM(b, s, opr1->reg.no, offset >> (2 + sz), base); + else + W_LDUR(b, s, opr1->reg.no, offset, base); + } else { + W_LDR(b, s, opr1->reg.no, offset, base, prepost); + } + } + break; + case STRB: case STRH: case STR: + if (opr2->indirect.prepost == 0) { + if (offset >= 0) + W_STR_UIMM((inst->op - STRB) | sz, opr1->reg.no, 0, base); + else + W_STUR((inst->op - STRB) | sz, opr1->reg.no, offset, base); + } else { + W_STR((inst->op - STRB) | sz, opr1->reg.no, offset, base, prepost); + } + break; + default: assert(false); break; + } + return code->buf; +} + static unsigned char *asm_ldpstp(Inst *inst, Code *code) { - static const uint32_t kPrePost[] = { 2 , 3, 1 }; Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; assert(opr1->reg.size == opr2->reg.size); @@ -70,6 +139,15 @@ static unsigned char *asm_ldpstp(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_adrp(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + if (opr1->reg.size == REG64) { + W_ADRP(opr1->reg.no, 0); + return code->buf; + } + return NULL; +} + static unsigned char *asm_bl(Inst *inst, Code *code) { W_BL(0); return code->buf; @@ -96,8 +174,13 @@ typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); static const AsmInstFunc table[] = { [NOOP] = asm_noop, [MOV] = asm_mov, + [ADD_I] = asm_2ri, + [LDRB] = asm_ldrstr, [LDRSB] = asm_ldrstr, [LDR] = asm_ldrstr, + [LDRH] = asm_ldrstr, [LDRSH] = asm_ldrstr, [LDRSW] = asm_ldrstr, + [STRB] = asm_ldrstr, [STRH] = asm_ldrstr, [STR] = asm_ldrstr, [LDP] = asm_ldpstp, [STP] = asm_ldpstp, + [ADRP] = asm_adrp, [BL] = asm_bl, [BLR] = asm_blr, [RET] = asm_ret, diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index 8bbed620c..9d6d5da6c 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -9,7 +9,11 @@ typedef struct Expr Expr; enum Opcode { NOOP, MOV, + ADD_I, + LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW, + STRB, STRH, STR, LDP, STP, + ADRP, BL, BLR, RET, }; diff --git a/src/as/arch/aarch64/ir_asm.c b/src/as/arch/aarch64/ir_asm.c index 058c3377b..813900e55 100644 --- a/src/as/arch/aarch64/ir_asm.c +++ b/src/as/arch/aarch64/ir_asm.c @@ -129,6 +129,38 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * { Inst *inst = ir->code.inst; switch (inst->op) { + case ADD_I: + if (inst->opr[2].type == DIRECT) { + Value value = calc_expr(label_table, inst->opr[2].direct.expr); + if (value.label != NULL) { + if (value.flag == LF_PAGEOFF || value.flag == LF_LO12) { + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = value.flag == LF_PAGEOFF ? UNRES_AARCH64_PAGEOFF : UNRES_PCREL_LO; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + } + } + break; + case ADRP: + if (inst->opr[1].type == DIRECT) { + Value value = calc_expr(label_table, inst->opr[1].direct.expr); + if (value.label != NULL) { + if (value.flag == 0 || value.flag == LF_PAGE) { + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = value.flag == LF_PAGE ? UNRES_AARCH64_PAGE : UNRES_PCREL_HI; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + } + } + break; case BL: if (inst->opr[0].type == DIRECT) { Value value = calc_expr(label_table, inst->opr[0].direct.expr); @@ -152,6 +184,18 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * case IR_EXPR_SHORT: case IR_EXPR_LONG: case IR_EXPR_QUAD: + { + Value value = calc_expr(label_table, ir->expr); + assert(value.label != NULL); + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = UNRES_ABS64; // TODO: + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + break; case IR_LABEL: case IR_DATA: case IR_BSS: diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index c82789fab..1521e45ea 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -11,15 +11,22 @@ enum RawOpcode { R_NOOP, R_MOV, + R_ADD, + R_LDRB, R_LDRH, R_LDR, R_LDRSB, R_LDRSH, R_LDRSW, + R_STRB, R_STRH, R_STR, R_LDP, R_STP, + R_ADRP, R_BL, R_BLR, R_RET, }; const char *kRawOpTable[] = { "mov", - "ldp", - "stp", + "add", + "ldrb", "ldrh", "ldr", "ldrsb", "ldrsh", "ldrsw", + "strb", "strh", "str", + "ldp", "stp", + "adrp", "bl", "blr", "ret", NULL, @@ -226,8 +233,23 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper const ParseInstTable kParseInstTable[] = { [R_MOV] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){MOV, {R32 | R64, IMM}} } }, + [R_ADD] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){ADD_I, {R32, R32, IMM}}, + &(ParseOpArray){ADD_I, {R32, R32, EXP}}, + &(ParseOpArray){ADD_I, {R64, R64, IMM}}, + &(ParseOpArray){ADD_I, {R64, R64, EXP}}, + } }, + [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND}} } }, + [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND}} } }, + [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND}} } }, + [R_LDRSB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSB, {R32 | R64, IND}} } }, + [R_LDRSH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSH, {R32 | R64, IND}} } }, + [R_STRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRB, {R32, IND}} } }, + [R_STRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRH, {R32, IND}} } }, + [R_STR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STR, {R32 | R64, IND}} } }, [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, + [R_ADRP] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){ADRP, {R64, EXP}} } }, [R_BL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BL, {EXP}} } }, [R_BLR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLR, {R64}} } }, [R_RET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){RET} } }, diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 90b958065..e4d39d0d1 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -176,7 +176,7 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * uintptr_t offset = address - start_address; UnresolvedInfo *info; info = calloc_or_die(sizeof(*info)); - info->kind = UNRES_RISCV_PCREL_HI20; + info->kind = UNRES_PCREL_HI; info->label = value.label; info->src_section = sec; info->offset = offset; @@ -193,9 +193,9 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * // hilabel points to AUIPC instruction, just above one. assert(inst->opr[2].direct.expr->kind == EX_LABEL); - const Name *hilabel = inst->opr[2].direct.expr->label; + const Name *hilabel = inst->opr[2].direct.expr->label.name; info = calloc_or_die(sizeof(*info)); - info->kind = UNRES_RISCV_PCREL_LO12_I; + info->kind = UNRES_PCREL_LO; info->label = hilabel; info->src_section = sec; info->offset = offset + 4; diff --git a/src/as/as.c b/src/as/as.c index dbaa26cce..632fb79b1 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -22,6 +22,14 @@ #define LOAD_ADDRESS START_ADDRESS #define DATA_ALIGN (0x1000) +#if XCC_TARGET_PLATFORM == XCC_PLATFORM_APPLE +// MachoArm64RelocationType +#define ARM64_RELOC_PAGE21 3 +#define ARM64_RELOC_PAGEOFF12 4 +#define ARM64_RELOC_GOT_LOAD_PAGE21 5 +#define ARM64_RELOC_GOT_LOAD_PAGEOFF12 6 +#endif + static void parse_file(FILE *fp, const char *filename, Vector **section_irs, Table *label_table) { ParseInfo info; info.filename = filename; @@ -238,6 +246,8 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { { #if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 const int type = R_RISCV_64; +#elif XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + const int type = R_AARCH64_ABS64; #else // #elif XCC_TARGET_ARCH == XCC_ARCH_X64 const int type = R_X86_64_64; #endif @@ -286,14 +296,40 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { } break; - case UNRES_RISCV_PCREL_HI20: - case UNRES_RISCV_PCREL_LO12_I: + case UNRES_AARCH64_PAGE: + case UNRES_AARCH64_PAGEOFF: + { +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); + + rela->r_offset = u->offset; +#if XCC_TARGET_PLATFORM == XCC_PLATFORM_APPLE + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_AARCH64_PAGE ? ARM64_RELOC_PAGE21 : ARM64_RELOC_PAGEOFF12); +#else + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_AARCH64_PAGE ? R_AARCH64_ADR_PREL_PG_HI21 : R_AARCH64_ADD_ABS_LO12_NC); +#endif + rela->r_addend = u->add; +#else + assert(false); +#endif + } + break; + + case UNRES_PCREL_HI: + case UNRES_PCREL_LO: { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_PCREL_HI20 ? R_RISCV_PCREL_HI20 : R_RISCV_PCREL_LO12_I); +#if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_PCREL_HI ? R_RISCV_PCREL_HI20 : R_RISCV_PCREL_LO12_I); +#elif XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_PCREL_HI ? R_AARCH64_ADR_PREL_PG_HI21 : R_AARCH64_ADD_ABS_LO12_NC); +#else + assert(false); +#endif rela->r_addend = u->add; } break; diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index 186a6154b..cfaded43a 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -18,11 +18,13 @@ enum UnresolvedKind { UNRES_OTHER_SECTION, UNRES_ABS64, UNRES_CALL, + UNRES_PCREL_HI, + UNRES_PCREL_LO, + UNRES_AARCH64_PAGE, // HI21 + UNRES_AARCH64_PAGEOFF, // LO12 UNRES_RISCV_BRANCH, UNRES_RISCV_JAL, - UNRES_RISCV_PCREL_HI20, - UNRES_RISCV_PCREL_LO12_I, UNRES_RISCV_RVC_BRANCH, UNRES_RISCV_RVC_JUMP, UNRES_RISCV_RELAX, diff --git a/src/as/parse_asm.c b/src/as/parse_asm.c index 219439ec6..b64f017bc 100644 --- a/src/as/parse_asm.c +++ b/src/as/parse_asm.c @@ -223,7 +223,10 @@ enum TokenKind { typedef struct Token { enum TokenKind kind; union { - const Name *label; + struct { + const Name *name; + int flag; + } label; int64_t fixnum; #ifndef __NO_FLONUM Flonum flonum; @@ -268,6 +271,29 @@ static Token *read_flonum(ParseInfo *info, int base) { } #endif +static int parse_label_postfix(ParseInfo *info) { + UNUSED(info); +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + static struct { + const char *name; + int flag; + } const kPostfixes[] = { + {"@page", LF_PAGE}, + {"@pageoff", LF_PAGEOFF}, + }; + const char *p = info->p; + for (size_t i = 0; i < ARRAY_SIZE(kPostfixes); ++i) { + const char *name = kPostfixes[i].name; + size_t n = strlen(name); + if (strncasecmp(p, name, n) == 0 && !is_label_chr(p[n])) { + info->p = p + n; + return kPostfixes[i].flag; + } + } +#endif + return 0; +} + static const Token *fetch_token(ParseInfo *info) { static const Token kTokEOF = {.kind = TK_EOF}; const char *start = skip_whitespaces(info->p); @@ -308,7 +334,8 @@ static const Token *fetch_token(ParseInfo *info) { const Name *label = parse_label(info); if (label != NULL) { Token *token = new_token(TK_LABEL); - token->label = label; + token->label.name = label; + token->label.flag = parse_label_postfix(info); return token; } } @@ -337,12 +364,37 @@ static const Token *fetch_token(ParseInfo *info) { default: break; } + int flag = 0; +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 + { + static struct { + const char *name; + int flag; + } const kPrefixes[] = { + {":lo12:", LF_LO12}, + {":got:", LF_GOT}, + {":got_lo12:", LF_GOT | LF_LO12}, + }; + for (size_t i = 0; i < ARRAY_SIZE(kPrefixes); ++i) { + const char *name = kPrefixes[i].name; + size_t n = strlen(name); + if (strncasecmp(p, name, n) == 0) { + flag = kPrefixes[i].flag; + p += n; + c = *p; + break; + } + } + } +#endif if (is_label_first_chr(c)) { + const char *label = p; while (c = *++p, is_label_chr(c)) ; Token *token = new_token(TK_LABEL); - token->label = alloc_name(start, p, false); + token->label.name = alloc_name(label, p, false); info->p = p; + token->label.flag = parse_label_postfix(info) | flag; return token; } @@ -374,7 +426,8 @@ static Expr *prim(ParseInfo *info) { const Token *tok; if ((tok = match(info, TK_LABEL)) != NULL) { expr = new_expr(EX_LABEL); - expr->label = tok->label; + expr->label.name = tok->label.name; + expr->label.flag = tok->label.flag; } else if ((tok = match(info, TK_FIXNUM)) != NULL) { expr = new_expr(EX_FIXNUM); expr->fixnum = tok->fixnum; @@ -614,7 +667,7 @@ void parse_inst(ParseInfo *info, Line *line) { } if (inst->opr[2].type == NOOPERAND) { Expr *expr = new_expr(EX_LABEL); - expr->label = line->label; + expr->label.name = line->label; Operand *opr = &inst->opr[2]; opr->type = DIRECT; @@ -934,7 +987,7 @@ Value calc_expr(Table *label_table, const Expr *expr) { assert(expr != NULL); switch (expr->kind) { case EX_LABEL: - return (Value){.label = expr->label, .offset = 0}; + return (Value){.label = expr->label.name, .offset = 0, .flag = expr->label.flag}; case EX_FIXNUM: return (Value){.label = NULL, .offset = expr->fixnum}; case EX_ADD: diff --git a/src/as/parse_asm.h b/src/as/parse_asm.h index 463c668e1..344e0f4c1 100644 --- a/src/as/parse_asm.h +++ b/src/as/parse_asm.h @@ -64,10 +64,18 @@ enum ExprKind { typedef long double Flonum; #endif +#define LF_PAGE (1 << 0) +#define LF_PAGEOFF (1 << 1) +#define LF_LO12 (1 << 2) +#define LF_GOT (1 << 3) + typedef struct Expr { enum ExprKind kind; union { - const Name *label; + struct { + const Name *name; + int flag; + } label; int64_t fixnum; struct { struct Expr *lhs; @@ -113,6 +121,7 @@ Expr *new_expr(enum ExprKind kind); typedef struct { const Name *label; int64_t offset; + int flag; } Value; Value calc_expr(Table *label_table, const Expr *expr); From 2ff1eef8e302b566b1de4a0b878faf4b780bcb7f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 14 May 2024 09:34:35 +0900 Subject: [PATCH 03/11] add, sub, conditional branch --- src/as/arch/aarch64/aarch64_code.h | 11 ++++ src/as/arch/aarch64/asm_code.c | 87 +++++++++++++++++++++++++++-- src/as/arch/aarch64/inst.h | 6 +- src/as/arch/aarch64/ir_asm.c | 43 ++++++++++++++ src/as/arch/aarch64/parse_aarch64.c | 46 +++++++++++++-- 5 files changed, 182 insertions(+), 11 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 6f2d20095..a17c43b86 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -7,7 +7,11 @@ #define W_MOVN(sz, rd, imm, sft) MAKE_CODE32(inst, code, 0x12800000U | ((sz) << 31) | ((sft) << 21) | (((imm) & ((1U << 16) - 1)) << 5) | (rd)) #define W_ADD_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x11000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_ADD_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x0b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUB_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x51000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_SUB_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_SUBS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x71000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_ORR_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x2a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_LDUR(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) #define W_LDR_UIMM(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x39400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) @@ -29,6 +33,13 @@ #define W_ADRP(rd, imm) MAKE_CODE32(inst, code, 0x90000000U | (IMM(imm, 31, 30) << 29) | (IMM(imm, 29, 12) << 5) | (rd)) +#define W_B() MAKE_CODE32(inst, code, 0x14000000U) +#define W_BR(rn) MAKE_CODE32(inst, code, 0xd61f0000U | ((rn) << 5)) +#define W_BCC(cond) MAKE_CODE32(inst, code, 0x54000000U | (cond)) + #define W_BL(offset) MAKE_CODE32(inst, code, 0x94000000U | ((offset) & ((1U << 26) - 1))) #define W_BLR(rn) MAKE_CODE32(inst, code, 0xd63f0000U | ((rn) << 5)) #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) + +#define P_MOV(sz, rd, rs) W_ORR_S(sz, rd, ZERO, rs, 0) +#define P_CMP_I(sz, rd, imm) W_SUBS_I(sz, ZERO, rd, imm) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 333569682..25ff4b1f3 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -43,14 +43,41 @@ static unsigned char *asm_noop(Inst *inst, Code *code) { static unsigned char *asm_mov(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; - if (opr2->type == IMMEDIATE) { - uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; - W_MOVZ(sz, opr1->reg.no, opr2->immediate, 0); - return code->buf; + switch (opr2->type) { + case REG: + { + assert(opr1->reg.size == opr2->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + P_MOV(sz, opr1->reg.no, opr2->reg.no); + return code->buf; + } + case IMMEDIATE: + { + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + W_MOVZ(sz, opr1->reg.no, opr2->immediate, 0); + return code->buf; + } + default: assert(false); break; } return NULL; } +static unsigned char *asm_3r(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + Operand *opr3 = &inst->opr[2]; + assert(opr1->reg.size == opr2->reg.size); + assert(opr1->reg.size == opr3->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + + switch (inst->op) { + case ADD_R: W_ADD_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case SUB_R: W_SUB_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_2ri(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; @@ -69,6 +96,28 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { if (imm >= 0) W_ADD_I(sz, opr1->reg.no, opr2->reg.no, imm); else W_SUB_I(sz, opr1->reg.no, opr2->reg.no, -imm); break; + case SUB_I: + if (imm >= 0) W_SUB_I(sz, opr1->reg.no, opr2->reg.no, imm); + else W_ADD_I(sz, opr1->reg.no, opr2->reg.no, -imm); + break; + default: assert(false); return NULL; + } + return code->buf; +} + +static unsigned char *asm_ri(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + uint32_t imm = 0; + if (opr2->type == IMMEDIATE) { + if (opr2->immediate < 0 || opr2->immediate >= (1 << 12)) + return NULL; + imm = opr2->immediate; + } + + switch (inst->op) { + case CMP: P_CMP_I(sz, opr1->reg.no, imm); break; default: assert(false); return NULL; } return code->buf; @@ -148,6 +197,26 @@ static unsigned char *asm_adrp(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_b(Inst *inst, Code *code) { + W_B(); + return code->buf; +} + +static unsigned char *asm_br(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + if (opr1->reg.size == REG64) { + W_BR(opr1->reg.no); + return code->buf; + } + return NULL; +} + +static unsigned char *asm_bcc(Inst *inst, Code *code) { + uint32_t cond = inst->op == B ? BAL - BEQ : inst->op - BEQ; + W_BCC(cond); + return code->buf; +} + static unsigned char *asm_bl(Inst *inst, Code *code) { W_BL(0); return code->buf; @@ -174,13 +243,21 @@ typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); static const AsmInstFunc table[] = { [NOOP] = asm_noop, [MOV] = asm_mov, - [ADD_I] = asm_2ri, + [ADD_R] = asm_3r, [ADD_I] = asm_2ri, + [SUB_R] = asm_3r, [SUB_I] = asm_2ri, + [CMP] = asm_ri, [LDRB] = asm_ldrstr, [LDRSB] = asm_ldrstr, [LDR] = asm_ldrstr, [LDRH] = asm_ldrstr, [LDRSH] = asm_ldrstr, [LDRSW] = asm_ldrstr, [STRB] = asm_ldrstr, [STRH] = asm_ldrstr, [STR] = asm_ldrstr, [LDP] = asm_ldpstp, [STP] = asm_ldpstp, [ADRP] = asm_adrp, + [B] = asm_b, + [BR] = asm_br, + [BEQ] = asm_bcc, [BNE] = asm_bcc, [BHS] = asm_bcc, [BLO] = asm_bcc, + [BMI] = asm_bcc, [BPL] = asm_bcc, [BVS] = asm_bcc, [BVC] = asm_bcc, + [BHI] = asm_bcc, [BLS] = asm_bcc, [BGE] = asm_bcc, [BLT] = asm_bcc, + [BGT] = asm_bcc, [BLE] = asm_bcc, [BAL] = asm_bcc, [BNV] = asm_bcc, [BL] = asm_bl, [BLR] = asm_blr, [RET] = asm_ret, diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index 9d6d5da6c..fbac3729e 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -9,11 +9,15 @@ typedef struct Expr Expr; enum Opcode { NOOP, MOV, - ADD_I, + ADD_R, ADD_I, SUB_R, SUB_I, + CMP, LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW, STRB, STRH, STR, LDP, STP, ADRP, + B, BR, + BEQ, BNE, BHS, BLO, BMI, BPL, BVS, BVC, + BHI, BLS, BGE, BLT, BGT, BLE, BAL, BNV, BL, BLR, RET, }; diff --git a/src/as/arch/aarch64/ir_asm.c b/src/as/arch/aarch64/ir_asm.c index 813900e55..9641f3d2a 100644 --- a/src/as/arch/aarch64/ir_asm.c +++ b/src/as/arch/aarch64/ir_asm.c @@ -161,6 +161,49 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * } } break; + case B: + case BEQ: case BNE: case BHS: case BLO: + case BMI: case BPL: case BVS: case BVC: + case BHI: case BLS: case BGE: case BLT: + case BGT: case BLE: case BAL: case BNV: + if (inst->opr[0].type == DIRECT) { + Value value = calc_expr(label_table, inst->opr[0].direct.expr); + if (value.label != NULL) { + LabelInfo *label_info = table_get(label_table, value.label); + if (label_info == NULL) { + /*UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = UNRES_EXTERN; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset - 4; + vec_push(unresolved, info); + break;*/ + assert(false); + } else { + value.offset += label_info->address; + } + } + + intptr_t offset = value.offset - VOIDP2INT(address); + if (inst->op == B) { + if (offset >= (1L << 27) || offset < -(1L << 27) || (offset & 3) != 0) + error("Jump offset too far (over 32bit)"); + + Code *code = &ir->code; + uint32_t *buf = (uint32_t*)code->buf; + *buf = (*buf & 0xfc000000) | ((offset >> 2) & ((1U << 26) - 1)); + } else { + if (offset >= (1L << 20) || offset < -(1L << 20) || (offset & 3) != 0) + error("Jump offset too far (over 32bit)"); + + Code *code = &ir->code; + uint32_t *buf = (uint32_t*)code->buf; + *buf = (*buf & 0xff00001f) | ((offset & ((1U << 21) - 1)) << (5 - 2)); + } + } + break; + case BL: if (inst->opr[0].type == DIRECT) { Value value = calc_expr(label_table, inst->opr[0].direct.expr); diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 1521e45ea..e5f0268cb 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -11,22 +11,30 @@ enum RawOpcode { R_NOOP, R_MOV, - R_ADD, + R_ADD, R_SUB, + R_CMP, R_LDRB, R_LDRH, R_LDR, R_LDRSB, R_LDRSH, R_LDRSW, R_STRB, R_STRH, R_STR, R_LDP, R_STP, R_ADRP, + R_B, R_BR, + R_BEQ, R_BNE, R_BHS, R_BLO, R_BMI, R_BPL, R_BVS, R_BVC, + R_BHI, R_BLS, R_BGE, R_BLT, R_BGT, R_BLE, R_BAL, R_BNV, R_BL, R_BLR, R_RET, }; const char *kRawOpTable[] = { "mov", - "add", + "add", "sub", + "cmp", "ldrb", "ldrh", "ldr", "ldrsb", "ldrsh", "ldrsw", "strb", "strh", "str", "ldp", "stp", "adrp", + "b", "br", + "beq", "bne", "bhs", "blo", "bmi", "bpl", "bvs", "bvc", + "bhi", "bls", "bge", "blt", "bgt", "ble", "bal", "bnv", "bl", "blr", "ret", NULL, @@ -52,6 +60,8 @@ typedef struct { #define FP X29 #define LR X30 #define SP X31 +#define XZR X31 +#define WZR W31 static const RegisterTable kRegisters32[] = { {"w0", W0}, {"w1", W1}, {"w2", W2}, {"w3", W3}, @@ -62,6 +72,8 @@ static const RegisterTable kRegisters32[] = { {"w20", W20}, {"w21", W21}, {"w22", W22}, {"w23", W23}, {"w24", W24}, {"w25", W25}, {"w26", W26}, {"w27", W27}, {"w28", W28}, {"w29", W29}, {"w30", W30}, {"w31", W31}, + // Alias + {"wzr", WZR}, }; static const RegisterTable kRegisters64[] = { @@ -74,7 +86,7 @@ static const RegisterTable kRegisters64[] = { {"x24", X24}, {"x25", X25}, {"x26", X26}, {"x27", X27}, {"x28", X28}, {"x29", X29}, {"x30", X30}, {"x31", X31}, // Alias - {"fp", FP}, {"lr", LR}, {"sp", SP}, + {"fp", FP}, {"lr", LR}, {"sp", SP}, {"xzr", XZR}, }; inline bool is_reg32(enum RegType reg) { @@ -232,10 +244,16 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper } const ParseInstTable kParseInstTable[] = { - [R_MOV] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){MOV, {R32 | R64, IMM}} } }, - [R_ADD] = { 4, (const ParseOpArray*[]){ + [R_MOV] = { 3, (const ParseOpArray*[]){ + &(ParseOpArray){MOV, {R32, R32}}, + &(ParseOpArray){MOV, {R64, R64}}, + &(ParseOpArray){MOV, {R32 | R64, IMM}}, + } }, + [R_ADD] = { 6, (const ParseOpArray*[]){ + &(ParseOpArray){ADD_R, {R32, R32, R32}}, &(ParseOpArray){ADD_I, {R32, R32, IMM}}, &(ParseOpArray){ADD_I, {R32, R32, EXP}}, + &(ParseOpArray){ADD_R, {R64, R64, R64}}, &(ParseOpArray){ADD_I, {R64, R64, IMM}}, &(ParseOpArray){ADD_I, {R64, R64, EXP}}, } }, @@ -250,6 +268,24 @@ const ParseInstTable kParseInstTable[] = { [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, [R_ADRP] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){ADRP, {R64, EXP}} } }, + [R_B] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){B, {EXP}} } }, + [R_BR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BR, {R64}} } }, + [R_BEQ] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BEQ, {EXP}} } }, + [R_BNE] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BNE, {EXP}} } }, + [R_BHS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BHS, {EXP}} } }, + [R_BLO] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLO, {EXP}} } }, + [R_BMI] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BMI, {EXP}} } }, + [R_BPL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BPL, {EXP}} } }, + [R_BVS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BVS, {EXP}} } }, + [R_BVC] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BVC, {EXP}} } }, + [R_BHI] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BHI, {EXP}} } }, + [R_BLS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLS, {EXP}} } }, + [R_BGE] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BGE, {EXP}} } }, + [R_BLT] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLT, {EXP}} } }, + [R_BGT] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BGT, {EXP}} } }, + [R_BLE] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLE, {EXP}} } }, + [R_BAL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BAL, {EXP}} } }, + [R_BNV] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BNV, {EXP}} } }, [R_BL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BL, {EXP}} } }, [R_BLR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLR, {R64}} } }, [R_RET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){RET} } }, From 5fbd5ef989d762582c0b50a5ab3b122fba7e1858 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 20 May 2024 09:41:26 +0900 Subject: [PATCH 04/11] mul, div, bit operation, cmp --- src/as/arch/aarch64/aarch64_code.h | 12 ++++++++++ src/as/arch/aarch64/asm_code.c | 29 ++++++++++++++++++++++-- src/as/arch/aarch64/inst.h | 4 +++- src/as/arch/aarch64/parse_aarch64.c | 34 ++++++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index a17c43b86..2296a8c32 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -8,10 +8,19 @@ #define W_ADD_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x11000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_ADD_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x0b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_ADDS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x31000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_ADDS_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x2b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUB_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x51000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUB_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUBS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x71000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_SUBS_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x6b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_MUL(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1b007c00U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_SDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac00c00U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_UDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac00800U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_AND_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x0a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_ORR_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x2a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_EOR_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_EON_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4a200000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_LDUR(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) #define W_LDR_UIMM(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x39400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) @@ -42,4 +51,7 @@ #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) #define P_MOV(sz, rd, rs) W_ORR_S(sz, rd, ZERO, rs, 0) +#define P_CMP(sz, rm, rn) W_SUBS_S(sz, ZERO, rm, rn, 0) #define P_CMP_I(sz, rd, imm) W_SUBS_I(sz, ZERO, rd, imm) +#define P_CMN(sz, rn, rm) W_ADDS_S(sz, ZERO, rn, rm, 0) +#define P_CMN_I(sz, rd, imm) W_ADDS_I(sz, ZERO, rd, imm) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 25ff4b1f3..6808a78c4 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -73,6 +73,13 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { switch (inst->op) { case ADD_R: W_ADD_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; case SUB_R: W_SUB_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case MUL: W_MUL(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case SDIV: W_SDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case UDIV: W_UDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case AND: W_AND_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case ORR: W_ORR_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case EOR: W_EOR_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case EON: W_EON_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; default: assert(false); return NULL; } return code->buf; @@ -105,6 +112,20 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_2r(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + assert(opr1->reg.size == opr2->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + + switch (inst->op) { + case CMP_R: P_CMP(sz, opr1->reg.no, opr2->reg.no); break; + case CMN_R: P_CMN(sz, opr1->reg.no, opr2->reg.no); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_ri(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; @@ -117,7 +138,8 @@ static unsigned char *asm_ri(Inst *inst, Code *code) { } switch (inst->op) { - case CMP: P_CMP_I(sz, opr1->reg.no, imm); break; + case CMP_I: P_CMP_I(sz, opr1->reg.no, imm); break; + case CMN_I: P_CMN_I(sz, opr1->reg.no, imm); break; default: assert(false); return NULL; } return code->buf; @@ -245,7 +267,10 @@ static const AsmInstFunc table[] = { [MOV] = asm_mov, [ADD_R] = asm_3r, [ADD_I] = asm_2ri, [SUB_R] = asm_3r, [SUB_I] = asm_2ri, - [CMP] = asm_ri, + [MUL] = asm_3r, [SDIV] = asm_3r, [UDIV] = asm_3r, + [AND] = asm_3r, [ORR] = asm_3r, [EOR] = asm_3r, [EON] = asm_3r, + [CMP_R] = asm_2r, [CMP_I] = asm_ri, + [CMN_R] = asm_2r, [CMN_I] = asm_ri, [LDRB] = asm_ldrstr, [LDRSB] = asm_ldrstr, [LDR] = asm_ldrstr, [LDRH] = asm_ldrstr, [LDRSH] = asm_ldrstr, [LDRSW] = asm_ldrstr, [STRB] = asm_ldrstr, [STRH] = asm_ldrstr, [STR] = asm_ldrstr, diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index fbac3729e..50cca169a 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -10,7 +10,9 @@ enum Opcode { NOOP, MOV, ADD_R, ADD_I, SUB_R, SUB_I, - CMP, + MUL, SDIV, UDIV, + AND, ORR, EOR, EON, + CMP_R, CMP_I, CMN_R, CMN_I, LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW, STRB, STRH, STR, LDP, STP, diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index e5f0268cb..126e956bf 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -12,7 +12,9 @@ enum RawOpcode { R_NOOP, R_MOV, R_ADD, R_SUB, - R_CMP, + R_MUL, R_SDIV, R_UDIV, + R_AND, R_ORR, R_EOR, R_EON, + R_CMP, R_CMN, R_LDRB, R_LDRH, R_LDR, R_LDRSB, R_LDRSH, R_LDRSW, R_STRB, R_STRH, R_STR, R_LDP, R_STP, @@ -26,8 +28,9 @@ enum RawOpcode { const char *kRawOpTable[] = { "mov", - "add", "sub", - "cmp", + "add", "sub", "mul", "sdiv", "udiv", + "and", "orr", "eor", "eon", + "cmp", "cmn", "ldrb", "ldrh", "ldr", "ldrsb", "ldrsh", "ldrsw", "strb", "strh", "str", "ldp", "stp", @@ -257,6 +260,31 @@ const ParseInstTable kParseInstTable[] = { &(ParseOpArray){ADD_I, {R64, R64, IMM}}, &(ParseOpArray){ADD_I, {R64, R64, EXP}}, } }, + [R_SUB] = { 6, (const ParseOpArray*[]){ + &(ParseOpArray){SUB_R, {R32, R32, R32}}, + &(ParseOpArray){SUB_I, {R32, R32, IMM}}, + &(ParseOpArray){SUB_I, {R32, R32, EXP}}, + &(ParseOpArray){SUB_R, {R64, R64, R64}}, + &(ParseOpArray){SUB_I, {R64, R64, IMM}}, + &(ParseOpArray){SUB_I, {R64, R64, EXP}}, + } }, + [R_MUL] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){MUL, {R32, R32, R32}}, &(ParseOpArray){MUL, {R64, R64, R64}} } }, + [R_SDIV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){SDIV, {R32, R32, R32}}, &(ParseOpArray){SDIV, {R64, R64, R64}} } }, + [R_UDIV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){UDIV, {R32, R32, R32}}, &(ParseOpArray){UDIV, {R64, R64, R64}} } }, + [R_AND] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){AND, {R32, R32, R32}}, &(ParseOpArray){AND, {R64, R64, R64}} } }, + [R_ORR] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){ORR, {R32, R32, R32}}, &(ParseOpArray){ORR, {R64, R64, R64}} } }, + [R_EOR] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){EOR, {R32, R32, R32}}, &(ParseOpArray){EOR, {R64, R64, R64}} } }, + [R_EON] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){EON, {R32, R32, R32}}, &(ParseOpArray){EON, {R64, R64, R64}} } }, + [R_CMP] = { 3, (const ParseOpArray*[]){ + &(ParseOpArray){CMP_R, {R32, R32}}, + &(ParseOpArray){CMP_R, {R64, R64}}, + &(ParseOpArray){CMP_I, {R32 | R64, IMM}}, + } }, + [R_CMN] = { 3, (const ParseOpArray*[]){ + &(ParseOpArray){CMN_R, {R32, R32}}, + &(ParseOpArray){CMN_R, {R64, R64}}, + &(ParseOpArray){CMN_I, {R32 | R64, IMM}}, + } }, [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND}} } }, [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND}} } }, [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND}} } }, From cfc36dafc41b9804988eca90836c675c9eaefa93 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 21 May 2024 18:55:18 +0900 Subject: [PATCH 05/11] Handle GOT --- include/elf.h | 2 + src/as/arch/aarch64/asm_code.c | 5 +- src/as/arch/aarch64/ir_asm.c | 56 ++++++++++++++++++---- src/as/arch/aarch64/parse_aarch64.c | 10 +++- src/as/as.c | 19 ++++++++ src/as/ir_asm.h | 2 + src/as/parse_asm.c | 74 ++++++++++++++++++++--------- src/as/parse_asm.h | 5 ++ 8 files changed, 139 insertions(+), 34 deletions(-) diff --git a/include/elf.h b/include/elf.h index bc823a8c0..b1903aa30 100644 --- a/include/elf.h +++ b/include/elf.h @@ -152,6 +152,8 @@ typedef struct { #define R_AARCH64_ADR_PREL_PG_HI21_NC 276 #define R_AARCH64_ADD_ABS_LO12_NC 277 #define R_AARCH64_CALL26 283 +#define R_AARCH64_ADR_GOT_PAGE 311 +#define R_AARCH64_LD64_GOT_LO12_NC 312 #define R_RISCV_64 (2) #define R_RISCV_BRANCH (16) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 6808a78c4..c66e9f208 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -150,8 +150,9 @@ static unsigned char *asm_ldrstr(Inst *inst, Code *code) { uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; Operand *opr2 = &inst->opr[1]; assert(opr2->indirect.reg.size == REG64); - assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); - int64_t offset = opr2->indirect.offset != NULL ? opr2->indirect.offset->fixnum : 0; + // assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); + Expr *offset_expr = opr2->indirect.offset; + int64_t offset = offset_expr != NULL && offset_expr->kind == EX_FIXNUM ? offset_expr->fixnum : 0; assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); uint32_t base = opr2->indirect.reg.no; uint32_t prepost = kPrePost[opr2->indirect.prepost]; diff --git a/src/as/arch/aarch64/ir_asm.c b/src/as/arch/aarch64/ir_asm.c index 9641f3d2a..1c2287802 100644 --- a/src/as/arch/aarch64/ir_asm.c +++ b/src/as/arch/aarch64/ir_asm.c @@ -145,19 +145,59 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * } } break; + case LDR: + case STR: + if (inst->opr[1].type == INDIRECT && inst->opr[1].indirect.offset != NULL) { + Value value = calc_expr(label_table, inst->opr[1].indirect.offset); + if (value.label != NULL) { + static const int table[][2] = { + { LF_GOT, UNRES_AARCH64_GOT }, + { LF_GOT | LF_LO12, UNRES_AARCH64_GOT_LO12 }, + }; + size_t i; + for (i = 0; i < ARRAY_SIZE(table); ++i) { + if (table[i][0] == value.flag) + break; + } + if (i >= ARRAY_SIZE(table)) { + break; + } + + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = table[i][1]; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + } + break; case ADRP: if (inst->opr[1].type == DIRECT) { Value value = calc_expr(label_table, inst->opr[1].direct.expr); if (value.label != NULL) { - if (value.flag == 0 || value.flag == LF_PAGE) { - UnresolvedInfo *info = malloc_or_die(sizeof(*info)); - info->kind = value.flag == LF_PAGE ? UNRES_AARCH64_PAGE : UNRES_PCREL_HI; - info->label = value.label; - info->src_section = sec; - info->offset = address - start_address; - info->add = value.offset; - vec_push(unresolved, info); + static const int table[][2] = { + { 0, UNRES_PCREL_HI }, + { LF_PAGE, UNRES_AARCH64_PAGE }, + { LF_GOT, UNRES_AARCH64_GOT }, + }; + size_t i; + for (i = 0; i < ARRAY_SIZE(table); ++i) { + if (table[i][0] == value.flag) + break; + } + if (i >= ARRAY_SIZE(table)) { + break; } + + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = table[i][1]; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); } } break; diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 126e956bf..3875634a0 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -153,7 +153,13 @@ static bool parse_indirect_register(ParseInfo *info, Operand *operand) { offset = new_expr(EX_FIXNUM); offset->fixnum = imm; } else { - parse_error(info, "Offset expected"); + parse_set_p(info, p); + offset = parse_got_label(info); + if (offset != NULL) { + p = info->p; + } else { + parse_error(info, "Offset expected"); + } } } if (*p == ']') { @@ -187,7 +193,7 @@ static bool parse_indirect_register(ParseInfo *info, Operand *operand) { operand->type = INDIRECT; operand->indirect.offset = offset; operand->indirect.prepost = prepost; - info->p = p; + parse_set_p(info, p); return true; } diff --git a/src/as/as.c b/src/as/as.c index 632fb79b1..6a1ec178d 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -315,6 +315,25 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { #endif } break; + case UNRES_AARCH64_GOT: + case UNRES_AARCH64_GOT_LO12: + { + LabelInfo *label = table_get(label_table, u->label); + int type = u->kind == UNRES_AARCH64_GOT ? R_AARCH64_ADR_GOT_PAGE : R_AARCH64_LD64_GOT_LO12_NC; + if (label == NULL || label->flag & (LF_GLOBAL | LF_REFERRED)) { + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); + + rela->r_offset = u->offset; + rela->r_info = ELF64_R_INFO(symidx, type); + rela->r_addend = u->add; + } else { + rela->r_offset = u->offset; + rela->r_info = ELF64_R_INFO(label->section + 1, type); + rela->r_addend = u->add + (label->address - section_start_addresses[label->section]); + } + } + break; case UNRES_PCREL_HI: case UNRES_PCREL_LO: diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index cfaded43a..472773ed5 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -22,6 +22,8 @@ enum UnresolvedKind { UNRES_PCREL_LO, UNRES_AARCH64_PAGE, // HI21 UNRES_AARCH64_PAGEOFF, // LO12 + UNRES_AARCH64_GOT, // HI21 + UNRES_AARCH64_GOT_LO12, // LO12 UNRES_RISCV_BRANCH, UNRES_RISCV_JAL, diff --git a/src/as/parse_asm.c b/src/as/parse_asm.c index b64f017bc..f8a76f794 100644 --- a/src/as/parse_asm.c +++ b/src/as/parse_asm.c @@ -90,6 +90,30 @@ static enum DirectiveType find_directive(const char *p, size_t n) { return NODIRECTIVE; } +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 +static int find_aarch_label_flag(const char **pp) { + static struct { + const char *name; + int flag; + } const kPrefixes[] = { + {":lo12:", LF_LO12}, + {":got:", LF_GOT}, + {":got_lo12:", LF_GOT | LF_LO12}, + }; + + const char *p = *pp; + for (size_t i = 0; i < ARRAY_SIZE(kPrefixes); ++i) { + const char *name = kPrefixes[i].name; + size_t n = strlen(name); + if (strncasecmp(p, name, n) == 0) { + *pp = p + n; + return kPrefixes[i].flag; + } + } + return 0; +} +#endif + bool immediate(const char **pp, int64_t *value) { const char *p = *pp; bool negative = false; @@ -366,26 +390,9 @@ static const Token *fetch_token(ParseInfo *info) { int flag = 0; #if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 - { - static struct { - const char *name; - int flag; - } const kPrefixes[] = { - {":lo12:", LF_LO12}, - {":got:", LF_GOT}, - {":got_lo12:", LF_GOT | LF_LO12}, - }; - for (size_t i = 0; i < ARRAY_SIZE(kPrefixes); ++i) { - const char *name = kPrefixes[i].name; - size_t n = strlen(name); - if (strncasecmp(p, name, n) == 0) { - flag = kPrefixes[i].flag; - p += n; - c = *p; - break; - } - } - } + flag = find_aarch_label_flag(&p); + if (flag != 0) + c = *p; #endif if (is_label_first_chr(c)) { const char *label = p; @@ -421,6 +428,24 @@ Expr *new_expr(enum ExprKind kind) { return expr; } +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 +Expr *parse_got_label(ParseInfo *info) { + const char *p = info->p; + int flag = find_aarch_label_flag(&p); + if (flag != 0) { + parse_set_p(info, p); + const Token *tok; + if ((tok = match(info, TK_LABEL)) != NULL) { + Expr *offset = new_expr(EX_LABEL); + offset->label.name = tok->label.name; + offset->label.flag = flag; + return offset; + } + } + return NULL; +} +#endif + static Expr *prim(ParseInfo *info) { Expr *expr = NULL; const Token *tok; @@ -718,6 +743,11 @@ Line *parse_line(ParseInfo *info) { return line; } +void parse_set_p(ParseInfo *info, const char *p) { + info->p = p; + info->prefetched = NULL; +} + static char unescape_char(ParseInfo *info) { const char *p = info->p; char c = *p++; @@ -1011,14 +1041,14 @@ Value calc_expr(Table *label_table, const Expr *expr) { error("Illegal expression"); } // offset + label - return (Value){.label = rhs.label, .offset = lhs.offset + rhs.offset}; + return (Value){.label = rhs.label, .offset = lhs.offset + rhs.offset, .flag = rhs.flag}; } if (lhs.label != NULL) { if (expr->kind != EX_ADD) { error("Illegal expression"); } // label + offset - return (Value){.label = lhs.label, .offset = lhs.offset + rhs.offset}; + return (Value){.label = lhs.label, .offset = lhs.offset + rhs.offset, .flag = lhs.flag}; } assert(lhs.label == NULL && rhs.label == NULL); diff --git a/src/as/parse_asm.h b/src/as/parse_asm.h index 344e0f4c1..acb481d16 100644 --- a/src/as/parse_asm.h +++ b/src/as/parse_asm.h @@ -94,6 +94,7 @@ extern int current_section; // enum SectionType extern bool err; Line *parse_line(ParseInfo *info); +void parse_set_p(ParseInfo *info, const char *p); void handle_directive(ParseInfo *info, enum DirectiveType dir, Vector **section_irs, Table *label_table); void parse_error(const ParseInfo *info, const char *message); @@ -118,6 +119,10 @@ const Name *unquote_label(const char *p, const char *q); Expr *parse_expr(ParseInfo *info); Expr *new_expr(enum ExprKind kind); +#if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 +Expr *parse_got_label(ParseInfo *info); +#endif + typedef struct { const Name *label; int64_t offset; From 6b49483487f078beea4b8946e50fb15b3c93968d Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 25 May 2024 09:14:08 +0900 Subject: [PATCH 06/11] sxtw, uxtw, MADD, MSUB, cset, shift, movk * cset => csinc * lsl, lsr, asr * Negative constant --- src/as/arch/aarch64/aarch64_code.h | 17 +++++- src/as/arch/aarch64/asm_code.c | 80 +++++++++++++++++++++++++-- src/as/arch/aarch64/inst.h | 17 +++++- src/as/arch/aarch64/parse_aarch64.c | 86 ++++++++++++++++++++++++++++- 4 files changed, 192 insertions(+), 8 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 2296a8c32..6296584fa 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -14,7 +14,8 @@ #define W_SUB_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUBS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x71000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUBS_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x6b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) -#define W_MUL(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1b007c00U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_MADD(sz, rd, rn, rm, ra) MAKE_CODE32(inst, code, 0x1b000000U | ((sz) << 31) | ((rm) << 16) | ((ra) << 10) | ((rn) << 5) | (rd)) +#define W_MSUB(sz, rd, rn, rm, ra) MAKE_CODE32(inst, code, 0x1b008000U | ((sz) << 31) | ((rm) << 16) | ((ra) << 10) | ((rn) << 5) | (rd)) #define W_SDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac00c00U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) #define W_UDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac00800U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) #define W_AND_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x0a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) @@ -22,6 +23,13 @@ #define W_EOR_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4a000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_EON_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4a200000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_LSLV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac02000U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_LSRV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac02400U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define W_ASRV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac02800U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) + +#define W_SBFM(sz, rd, sn, rn, immr, imms) MAKE_CODE32(inst, code, 0x13000000U | ((sz) << 31) | ((sn) << 22) | ((immr) << 16) | ((imms) << 10) | ((rn) << 5) | (rd)) +#define W_UBFM(sz, rd, sn, rn, immr, imms) MAKE_CODE32(inst, code, 0x53000000U | ((sz) << 31) | ((sn) << 22) | ((immr) << 16) | ((imms) << 10) | ((rn) << 5) | (rd)) + #define W_LDUR(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) #define W_LDR_UIMM(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0x39400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) #define W_LDR(b, s, rt, ofs, base, prepost) MAKE_CODE32(inst, code, 0x38400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((prepost) << 10) | ((base) << 5) | (rt)) @@ -42,6 +50,8 @@ #define W_ADRP(rd, imm) MAKE_CODE32(inst, code, 0x90000000U | (IMM(imm, 31, 30) << 29) | (IMM(imm, 29, 12) << 5) | (rd)) +#define W_CSINC(sz, rd, rn, rm, cond) MAKE_CODE32(inst, code, 0x1a800400U | ((sz) << 31) | ((rm) << 16) | ((cond) << 12) | ((rn) << 5) | (rd)) + #define W_B() MAKE_CODE32(inst, code, 0x14000000U) #define W_BR(rn) MAKE_CODE32(inst, code, 0xd61f0000U | ((rn) << 5)) #define W_BCC(cond) MAKE_CODE32(inst, code, 0x54000000U | (cond)) @@ -51,7 +61,12 @@ #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) #define P_MOV(sz, rd, rs) W_ORR_S(sz, rd, ZERO, rs, 0) +#define P_MUL(sz, rd, rn, rm) W_MADD(sz, rd, rn, rm, ZERO) #define P_CMP(sz, rm, rn) W_SUBS_S(sz, ZERO, rm, rn, 0) #define P_CMP_I(sz, rd, imm) W_SUBS_I(sz, ZERO, rd, imm) #define P_CMN(sz, rn, rm) W_ADDS_S(sz, ZERO, rn, rm, 0) #define P_CMN_I(sz, rd, imm) W_ADDS_I(sz, ZERO, rd, imm) +#define P_LSL_I(sz, rd, rn, imm) W_UBFM(sz, opr1->reg.no, sz, opr2->reg.no, -(imm) & (63>>(1-(sz))), (63>>(1-(sz))) - (imm)) +#define P_LSR_I(sz, rd, rn, imm) W_UBFM(sz, opr1->reg.no, sz, opr2->reg.no, imm, 63>>(1-(sz))) +#define P_ASR_I(sz, rd, rn, imm) W_SBFM(sz, opr1->reg.no, sz, opr2->reg.no, imm, 63>>(1-(sz))) +#define P_CSET(sz, rd, cond) W_CSINC(sz, rd, ZERO, ZERO, (cond) ^ 1) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index c66e9f208..440c93bde 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -54,7 +54,11 @@ static unsigned char *asm_mov(Inst *inst, Code *code) { case IMMEDIATE: { uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; - W_MOVZ(sz, opr1->reg.no, opr2->immediate, 0); + int64_t imm = opr2->immediate; + if (imm >= 0) + W_MOVZ(sz, opr1->reg.no, imm, 0); + else + W_MOVN(sz, opr1->reg.no, ~imm, 0); return code->buf; } default: assert(false); break; @@ -62,6 +66,16 @@ static unsigned char *asm_mov(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_movk(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + Operand *opr3 = &inst->opr[2]; + assert(opr3->type == IMMEDIATE && (opr3->immediate & 15) == 0); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + W_MOVK(sz, opr1->reg.no, opr2->immediate, opr3->immediate >> 4); + return code->buf; +} + static unsigned char *asm_3r(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; @@ -73,13 +87,16 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { switch (inst->op) { case ADD_R: W_ADD_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; case SUB_R: W_SUB_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; - case MUL: W_MUL(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case MUL: P_MUL(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; case SDIV: W_SDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; case UDIV: W_UDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; case AND: W_AND_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; case ORR: W_ORR_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; case EOR: W_EOR_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; case EON: W_EON_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case LSL_R: W_LSLV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case LSR_R: W_LSRV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case ASR_R: W_ASRV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; default: assert(false); return NULL; } return code->buf; @@ -107,6 +124,9 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { if (imm >= 0) W_SUB_I(sz, opr1->reg.no, opr2->reg.no, imm); else W_ADD_I(sz, opr1->reg.no, opr2->reg.no, -imm); break; + case LSL_I: P_LSL_I(sz, opr1->reg.no, opr2->reg.no, imm); break; + case LSR_I: P_LSR_I(sz, opr1->reg.no, opr2->reg.no, imm); break; + case ASR_I: P_ASR_I(sz, opr1->reg.no, opr2->reg.no, imm); break; default: assert(false); return NULL; } return code->buf; @@ -115,12 +135,31 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { static unsigned char *asm_2r(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; Operand *opr2 = &inst->opr[1]; - assert(opr1->reg.size == opr2->reg.size); uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; switch (inst->op) { case CMP_R: P_CMP(sz, opr1->reg.no, opr2->reg.no); break; case CMN_R: P_CMN(sz, opr1->reg.no, opr2->reg.no); break; + case SXTB: + case SXTH: + case SXTW: + { + uint32_t imms = (8U << (inst->op - SXTB)) - 1U; + assert(opr2->reg.size == REG32); + W_SBFM(sz, opr1->reg.no, sz, opr2->reg.no, 0, imms); + } + break; + case UXTB: + case UXTH: + { + uint32_t imms = (8U << (inst->op - UXTB)) - 1U; + assert(opr2->reg.size == REG32); + W_UBFM(0, opr1->reg.no, 0, opr2->reg.no, 0, imms); + } + break; + case UXTW: + P_MOV(0, opr1->reg.no, opr2->reg.no); + break; default: assert(false); return NULL; } return code->buf; @@ -145,6 +184,24 @@ static unsigned char *asm_ri(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_4r(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + Operand *opr3 = &inst->opr[2]; + Operand *opr4 = &inst->opr[3]; + assert(opr1->reg.size == opr2->reg.size); + assert(opr1->reg.size == opr3->reg.size); + assert(opr1->reg.size == opr4->reg.size); + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + + switch (inst->op) { + case MADD: W_MADD(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, opr4->reg.no); break; + case MSUB: W_MSUB(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, opr4->reg.no); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_ldrstr(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; @@ -220,6 +277,14 @@ static unsigned char *asm_adrp(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_cset(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + P_CSET(sz, opr1->reg.no, opr2->cond); + return code->buf; +} + static unsigned char *asm_b(Inst *inst, Code *code) { W_B(); return code->buf; @@ -265,19 +330,26 @@ typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); static const AsmInstFunc table[] = { [NOOP] = asm_noop, - [MOV] = asm_mov, + [MOV] = asm_mov, [MOVK] = asm_movk, [ADD_R] = asm_3r, [ADD_I] = asm_2ri, [SUB_R] = asm_3r, [SUB_I] = asm_2ri, [MUL] = asm_3r, [SDIV] = asm_3r, [UDIV] = asm_3r, + [MADD] = asm_4r, [MSUB] = asm_4r, [AND] = asm_3r, [ORR] = asm_3r, [EOR] = asm_3r, [EON] = asm_3r, [CMP_R] = asm_2r, [CMP_I] = asm_ri, [CMN_R] = asm_2r, [CMN_I] = asm_ri, + [LSL_R] = asm_3r, [LSL_I] = asm_2ri, + [LSR_R] = asm_3r, [LSR_I] = asm_2ri, + [ASR_R] = asm_3r, [ASR_I] = asm_2ri, + [SXTB] = asm_2r, [SXTH] = asm_2r, [SXTW] = asm_2r, + [UXTB] = asm_2r, [UXTH] = asm_2r, [UXTW] = asm_2r, [LDRB] = asm_ldrstr, [LDRSB] = asm_ldrstr, [LDR] = asm_ldrstr, [LDRH] = asm_ldrstr, [LDRSH] = asm_ldrstr, [LDRSW] = asm_ldrstr, [STRB] = asm_ldrstr, [STRH] = asm_ldrstr, [STR] = asm_ldrstr, [LDP] = asm_ldpstp, [STP] = asm_ldpstp, [ADRP] = asm_adrp, + [CSET] = asm_cset, [B] = asm_b, [BR] = asm_br, [BEQ] = asm_bcc, [BNE] = asm_bcc, [BHS] = asm_bcc, [BLO] = asm_bcc, diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index 50cca169a..c6bce0a76 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -8,15 +8,22 @@ typedef struct Expr Expr; enum Opcode { NOOP, - MOV, + MOV, MOVK, ADD_R, ADD_I, SUB_R, SUB_I, MUL, SDIV, UDIV, + MADD, MSUB, AND, ORR, EOR, EON, CMP_R, CMP_I, CMN_R, CMN_I, + LSL_R, LSL_I, + LSR_R, LSR_I, + ASR_R, ASR_I, + SXTB, SXTH, SXTW, + UXTB, UXTH, UXTW, LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW, STRB, STRH, STR, LDP, STP, ADRP, + CSET, B, BR, BEQ, BNE, BHS, BLO, BMI, BPL, BVS, BVC, BHI, BLS, BGE, BLT, BGT, BLE, BAL, BNV, @@ -34,6 +41,12 @@ typedef struct { char no; // 0~31 } Reg; +enum CondType { + NOCOND = -1, + EQ, NE, HS, LO, MI, PL, VS, VC, + HI, LS, GE, LT, GT, LE, AL, NV, +}; + enum OperandType { NOOPERAND, REG, // reg @@ -42,6 +55,7 @@ enum OperandType { INDIRECT, // indirect: [reg,#12] // pre-index: [reg,#34]! // post-index: [reg],#34 + COND, }; typedef struct { @@ -57,6 +71,7 @@ typedef struct { Reg reg; int prepost; // 0=none, 1=pre, 2=post } indirect; + enum CondType cond; }; } Operand; diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 3875634a0..e6585d6e5 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -10,15 +10,20 @@ enum RawOpcode { R_NOOP, - R_MOV, + R_MOV, R_MOVK, R_ADD, R_SUB, R_MUL, R_SDIV, R_UDIV, + R_MADD, R_MSUB, R_AND, R_ORR, R_EOR, R_EON, R_CMP, R_CMN, + R_LSL, R_LSR, R_ASR, + R_SXTB, R_SXTH, R_SXTW, + R_UXTB, R_UXTH, R_UXTW, R_LDRB, R_LDRH, R_LDR, R_LDRSB, R_LDRSH, R_LDRSW, R_STRB, R_STRH, R_STR, R_LDP, R_STP, R_ADRP, + R_CSET, R_B, R_BR, R_BEQ, R_BNE, R_BHS, R_BLO, R_BMI, R_BPL, R_BVS, R_BVC, R_BHI, R_BLS, R_BGE, R_BLT, R_BGT, R_BLE, R_BAL, R_BNV, @@ -27,14 +32,19 @@ enum RawOpcode { }; const char *kRawOpTable[] = { - "mov", + "mov", "movk", "add", "sub", "mul", "sdiv", "udiv", + "madd", "msub", "and", "orr", "eor", "eon", "cmp", "cmn", + "lsl", "lsr", "asr", + "sxtb", "sxth", "sxtw", + "uxtb", "uxth", "uxtw", "ldrb", "ldrh", "ldr", "ldrsb", "ldrsh", "ldrsw", "strb", "strh", "str", "ldp", "stp", "adrp", + "cset", "b", "br", "beq", "bne", "bhs", "blo", "bmi", "bpl", "bvs", "bvc", "bhi", "bls", "bge", "blt", "bgt", "ble", "bal", "bnv", @@ -92,6 +102,11 @@ static const RegisterTable kRegisters64[] = { {"fp", FP}, {"lr", LR}, {"sp", SP}, {"xzr", XZR}, }; +static const char kCondTable[][3] = { + "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "nv", +}; + inline bool is_reg32(enum RegType reg) { return reg >= W0 && reg <= W31; } @@ -105,6 +120,8 @@ inline bool is_reg64(enum RegType reg) { #define IMM (1 << 2) #define IND (1 << 3) #define EXP (1 << 4) +#define CND (1 << 5) +#define SFT (1 << 6) // lsl #nn static enum RegType find_register(const char **pp, unsigned int flag) { const char *p = *pp; @@ -127,6 +144,19 @@ static enum RegType find_register(const char **pp, unsigned int flag) { return NOREG; } +static enum CondType find_cond(const char **pp) { + const char *p = *pp; + for (int i = 0; i < (int)ARRAY_SIZE(kCondTable); ++i) { + const char *name = kCondTable[i]; + size_t n = strlen(name); + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { + *pp = p + n; + return i; + } + } + return NOCOND; +} + static bool parse_indirect_register(ParseInfo *info, Operand *operand) { const char *p = skip_whitespaces(info->p); enum RegType reg = find_register(&p, R64); @@ -240,6 +270,28 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper } } + if (opr_flag & CND) { + enum CondType cond = find_cond(&info->p); + if (cond != NOCOND) { + operand->type = COND; + operand->cond = cond; + return CND; + } + } + + if (opr_flag & SFT) { + if (strncmp(p, "lsl #", 5) == 0) { + p += 5; + int64_t imm; + if (immediate(&p, &imm) && imm >= 0 && imm <= 48 && (imm & 15) == 0) { + info->p = p; + operand->type = IMMEDIATE; + operand->immediate = imm; + return SFT; + } + } + } + if (opr_flag & EXP) { Expr *expr = parse_expr(info); if (expr != NULL) { @@ -258,6 +310,9 @@ const ParseInstTable kParseInstTable[] = { &(ParseOpArray){MOV, {R64, R64}}, &(ParseOpArray){MOV, {R32 | R64, IMM}}, } }, + [R_MOVK] = { 1, (const ParseOpArray*[]){ + &(ParseOpArray){MOVK, {R32 | R64, IMM, SFT}}, + } }, [R_ADD] = { 6, (const ParseOpArray*[]){ &(ParseOpArray){ADD_R, {R32, R32, R32}}, &(ParseOpArray){ADD_I, {R32, R32, IMM}}, @@ -277,6 +332,8 @@ const ParseInstTable kParseInstTable[] = { [R_MUL] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){MUL, {R32, R32, R32}}, &(ParseOpArray){MUL, {R64, R64, R64}} } }, [R_SDIV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){SDIV, {R32, R32, R32}}, &(ParseOpArray){SDIV, {R64, R64, R64}} } }, [R_UDIV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){UDIV, {R32, R32, R32}}, &(ParseOpArray){UDIV, {R64, R64, R64}} } }, + [R_MADD] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){MADD, {R32, R32, R32, R32}}, &(ParseOpArray){MADD, {R64, R64, R64, R64}} } }, + [R_MSUB] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){MSUB, {R32, R32, R32, R32}}, &(ParseOpArray){MSUB, {R64, R64, R64, R64}} } }, [R_AND] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){AND, {R32, R32, R32}}, &(ParseOpArray){AND, {R64, R64, R64}} } }, [R_ORR] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){ORR, {R32, R32, R32}}, &(ParseOpArray){ORR, {R64, R64, R64}} } }, [R_EOR] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){EOR, {R32, R32, R32}}, &(ParseOpArray){EOR, {R64, R64, R64}} } }, @@ -291,6 +348,30 @@ const ParseInstTable kParseInstTable[] = { &(ParseOpArray){CMN_R, {R64, R64}}, &(ParseOpArray){CMN_I, {R32 | R64, IMM}}, } }, + [R_LSL] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){LSL_R, {R32, R32, R32}}, + &(ParseOpArray){LSL_I, {R32, R32, IMM}}, + &(ParseOpArray){LSL_R, {R64, R64, R64}}, + &(ParseOpArray){LSL_I, {R64, R64, IMM}}, + } }, + [R_LSR] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){LSR_R, {R32, R32, R32}}, + &(ParseOpArray){LSR_I, {R32, R32, IMM}}, + &(ParseOpArray){LSR_R, {R64, R64, R64}}, + &(ParseOpArray){LSR_I, {R64, R64, IMM}}, + } }, + [R_ASR] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){ASR_R, {R32, R32, R32}}, + &(ParseOpArray){ASR_I, {R32, R32, IMM}}, + &(ParseOpArray){ASR_R, {R64, R64, R64}}, + &(ParseOpArray){ASR_I, {R64, R64, IMM}}, + } }, + [R_SXTB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){SXTB, {R32 | R64, R32}} } }, + [R_SXTH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){SXTH, {R32 | R64, R32}} } }, + [R_SXTW] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){SXTW, {R64, R32}} } }, + [R_UXTB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTB, {R32 | R64, R32}} } }, + [R_UXTH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTH, {R32 | R64, R32}} } }, + [R_UXTW] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTW, {R64, R32}} } }, [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND}} } }, [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND}} } }, [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND}} } }, @@ -302,6 +383,7 @@ const ParseInstTable kParseInstTable[] = { [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, [R_ADRP] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){ADRP, {R64, EXP}} } }, + [R_CSET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){CSET, {R32 | R64, CND}} } }, [R_B] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){B, {EXP}} } }, [R_BR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BR, {R64}} } }, [R_BEQ] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BEQ, {EXP}} } }, From 0a70adad0b071baebd37b5c9d60c0e389d32604e Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 5 Jun 2024 10:17:52 +0900 Subject: [PATCH 07/11] Additional indirect addressing base + index * scale --- src/as/arch/aarch64/asm_code.c | 84 ++++++++++++-------- src/as/arch/aarch64/inst.h | 18 ++++- src/as/arch/aarch64/parse_aarch64.c | 118 ++++++++++++++++++++-------- 3 files changed, 153 insertions(+), 67 deletions(-) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 440c93bde..66f7835aa 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -206,46 +206,68 @@ static unsigned char *asm_ldrstr(Inst *inst, Code *code) { Operand *opr1 = &inst->opr[0]; uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; Operand *opr2 = &inst->opr[1]; - assert(opr2->indirect.reg.size == REG64); - // assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); - Expr *offset_expr = opr2->indirect.offset; - int64_t offset = offset_expr != NULL && offset_expr->kind == EX_FIXNUM ? offset_expr->fixnum : 0; - assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); - uint32_t base = opr2->indirect.reg.no; - uint32_t prepost = kPrePost[opr2->indirect.prepost]; - switch (inst->op) { - case LDRB: case LDRH: case LDR: - case LDRSB: case LDRSH: - { - uint32_t b = inst->op - LDRB, s = 0; - if (b >= 3) { - b -= 3; - s = 1; + if (opr2->type == INDIRECT) { + assert(opr2->indirect.reg.size == REG64); + // assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); + Expr *offset_expr = opr2->indirect.offset; + int64_t offset = offset_expr != NULL && offset_expr->kind == EX_FIXNUM ? offset_expr->fixnum : 0; + assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); + uint32_t base = opr2->indirect.reg.no; + uint32_t prepost = kPrePost[opr2->indirect.prepost]; + switch (inst->op) { + case LDRB: case LDRH: case LDR: + case LDRSB: case LDRSH: + { + uint32_t b = inst->op - LDRB, s = 0; + if (b >= 3) { + b -= 3; + s = 1; + } + b |= sz; + if (opr2->indirect.prepost == 0) { + if (offset >= 0) + W_LDR_UIMM(b, s, opr1->reg.no, offset >> (2 + sz), base); + else + W_LDUR(b, s, opr1->reg.no, offset, base); + } else { + W_LDR(b, s, opr1->reg.no, offset, base, prepost); + } } - b |= sz; + break; + case STRB: case STRH: case STR: if (opr2->indirect.prepost == 0) { if (offset >= 0) - W_LDR_UIMM(b, s, opr1->reg.no, offset >> (2 + sz), base); + W_STR_UIMM((inst->op - STRB) | sz, opr1->reg.no, 0, base); else - W_LDUR(b, s, opr1->reg.no, offset, base); + W_STUR((inst->op - STRB) | sz, opr1->reg.no, offset, base); } else { - W_LDR(b, s, opr1->reg.no, offset, base, prepost); + W_STR((inst->op - STRB) | sz, opr1->reg.no, offset, base, prepost); } + break; + default: assert(false); break; } - break; - case STRB: case STRH: case STR: - if (opr2->indirect.prepost == 0) { - if (offset >= 0) - W_STR_UIMM((inst->op - STRB) | sz, opr1->reg.no, 0, base); - else - W_STUR((inst->op - STRB) | sz, opr1->reg.no, offset, base); - } else { - W_STR((inst->op - STRB) | sz, opr1->reg.no, offset, base, prepost); + return code->buf; + } else { + assert(opr2->type == REGISTER_OFFSET); + assert(opr2->register_offset.scale == NULL || opr2->register_offset.scale->kind == EX_FIXNUM); + + static const uint32_t opts[] = {3, 6, 2, 3, 3}; + uint32_t opt = opts[opr2->register_offset.extend]; + uint32_t s = opr2->register_offset.extend > 0 ? 1 : 0; + + switch (inst->op) { + case LDR: W_LDR_R(sz, opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, sz2, s, opt); break; + // case LDRB: W_LDRB_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + // case LDRSB: W_LDRSB_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + // case LDRH: W_LDRH_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + // case LDRSH: W_LDRSH_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + case STR: W_STR_R(sz, opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opt); break; + // case STRB: W_STRB_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + // case STRH: W_STRH_R(opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opr2->register_offset.extend); break; + default: assert(false); break; } - break; - default: assert(false); break; + return code->buf; } - return code->buf; } static unsigned char *asm_ldpstp(Inst *inst, Code *code) { diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index c6bce0a76..889c5637c 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -47,14 +47,20 @@ enum CondType { HI, LS, GE, LT, GT, LE, AL, NV, }; +enum ExtendType { + NOEXTEND, + E_SXTW, E_UXTW, E_LSL, E_SXTX, +}; + enum OperandType { NOOPERAND, REG, // reg IMMEDIATE, // 1234 DIRECT, // foobar + 345 - INDIRECT, // indirect: [reg,#12] - // pre-index: [reg,#34]! - // post-index: [reg],#34 + INDIRECT, // indirect: [reg,#nn] + // pre-index: [reg,#nn]! + // post-index: [reg],#nn + REGISTER_OFFSET, // [reg,reg,#nn] COND, }; @@ -71,6 +77,12 @@ typedef struct { Reg reg; int prepost; // 0=none, 1=pre, 2=post } indirect; + struct { + Expr *scale; + Reg base_reg; + Reg index_reg; + enum ExtendType extend; + } register_offset; enum CondType cond; }; } Operand; diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index e6585d6e5..20811c4ca 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -119,9 +119,10 @@ inline bool is_reg64(enum RegType reg) { #define R64 (1 << 1) #define IMM (1 << 2) #define IND (1 << 3) -#define EXP (1 << 4) -#define CND (1 << 5) -#define SFT (1 << 6) // lsl #nn +#define ROI (1 << 4) // Register Offset Indirect +#define EXP (1 << 5) +#define CND (1 << 6) +#define SFT (1 << 7) // lsl #nn static enum RegType find_register(const char **pp, unsigned int flag) { const char *p = *pp; @@ -157,12 +158,14 @@ static enum CondType find_cond(const char **pp) { return NOCOND; } -static bool parse_indirect_register(ParseInfo *info, Operand *operand) { +static unsigned int parse_indirect_register(ParseInfo *info, Operand *operand) { const char *p = skip_whitespaces(info->p); + enum RegType reg2 = NOREG; + enum ExtendType extend = NOEXTEND; enum RegType reg = find_register(&p, R64); if (reg == NOREG) { parse_error(info, "Base register expected"); - return false; + return 0; } if (is_reg64(reg)) { operand->indirect.reg.size = REG64; @@ -171,9 +174,9 @@ static bool parse_indirect_register(ParseInfo *info, Operand *operand) { parse_error(info, "Base register expected"); } - p = skip_whitespaces(p); - Expr *offset = NULL; + Expr *offset = NULL, *scale = NULL; int prepost = 0; + p = skip_whitespaces(p); if (*p == ',') { p = skip_whitespaces(p + 1); if (*p == '#') { @@ -191,18 +194,54 @@ static bool parse_indirect_register(ParseInfo *info, Operand *operand) { parse_error(info, "Offset expected"); } } + } else { + reg2 = find_register(&p, R32 | R64); + if (reg2 == NOREG) + return 0; // Error + + p = skip_whitespaces(p); + if (*p == ',') { + p = skip_whitespaces(p + 1); + static const char kExtendTable[][5] = { "sxtw", "uxtw", "lsl", "sxtx" }; + for (int i = 0; i < (int)ARRAY_SIZE(kExtendTable); ++i) { + const char *name = kExtendTable[i]; + size_t n = strlen(name); + if (strncmp(p, name, n) == 0 && isspace(p[n])) { + extend = i + 1; + p = skip_whitespaces(p + n + 1); + + if (*p == '#') { + p = p + 1; + int64_t imm; + if (immediate(&p, &imm)) { + scale = new_expr(EX_FIXNUM); + scale->fixnum = imm; + } else { + // parse_error(info, "Offset expected"); + return 0; // Error + } + } + break; + } + } + } } - if (*p == ']') { - if (*++p == '!') { + + p = skip_whitespaces(p); + } + + if (*p != ']') + // parse_error(info, "`]' expected"); + return 0; // Error + + p = skip_whitespaces(p + 1); + if (reg2 == NOREG) { + if (offset != NULL) { + if (*p == '!') { prepost = 1; ++p; } - } else { - parse_error(info, "`]' expected"); - } - } else if (*p == ']') { - p = skip_whitespaces(p + 1); - if (*p == ',') { + } else if (*p == ',') { const char *q = skip_whitespaces(p + 1); if (*q == '#') { p = q + 1; @@ -212,19 +251,33 @@ static bool parse_indirect_register(ParseInfo *info, Operand *operand) { offset->fixnum = imm; prepost = 2; } else { - parse_error(info, "Offset expected"); + // parse_error(info, "Offset expected"); + return 0; // Error } } } + + operand->type = INDIRECT; + operand->indirect.offset = offset; + operand->indirect.prepost = prepost; + parse_set_p(info, p); + return IND; } else { - parse_error(info, "`,` or `]' expected"); + operand->type = REGISTER_OFFSET; + operand->register_offset.base_reg.size = REG64; + operand->register_offset.base_reg.no = reg - X0; + if (is_reg64(reg2)) { + operand->register_offset.index_reg.size = REG64; + operand->register_offset.index_reg.no = reg2 - X0; + } else { + operand->register_offset.index_reg.size = REG32; + operand->register_offset.index_reg.no = reg2 - W0; + } + operand->register_offset.extend = extend; + operand->register_offset.scale = scale; + parse_set_p(info, p); + return ROI; } - - operand->type = INDIRECT; - operand->indirect.offset = offset; - operand->indirect.prepost = prepost; - parse_set_p(info, p); - return true; } unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *operand) { @@ -242,8 +295,7 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper if (opr_flag & IND) { if (*p == '[') { info->p = p + 1; - if (parse_indirect_register(info, operand)) - return IND; + return parse_indirect_register(info, operand); } } @@ -372,14 +424,14 @@ const ParseInstTable kParseInstTable[] = { [R_UXTB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTB, {R32 | R64, R32}} } }, [R_UXTH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTH, {R32 | R64, R32}} } }, [R_UXTW] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTW, {R64, R32}} } }, - [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND}} } }, - [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND}} } }, - [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND}} } }, - [R_LDRSB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSB, {R32 | R64, IND}} } }, - [R_LDRSH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSH, {R32 | R64, IND}} } }, - [R_STRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRB, {R32, IND}} } }, - [R_STRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRH, {R32, IND}} } }, - [R_STR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STR, {R32 | R64, IND}} } }, + [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND | ROI}} } }, + [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND | ROI}} } }, + [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND | ROI}} } }, + [R_LDRSB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSB, {R32 | R64, IND | ROI}} } }, + [R_LDRSH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSH, {R32 | R64, IND | ROI}} } }, + [R_STRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRB, {R32, IND | ROI}} } }, + [R_STRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRH, {R32, IND | ROI}} } }, + [R_STR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STR, {R32 | R64, IND | ROI}} } }, [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, [R_ADRP] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){ADRP, {R64, EXP}} } }, From 7977116bb89d79a228b0b0d5a4cf158b8fe0d09f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 6 Jun 2024 10:17:23 +0900 Subject: [PATCH 08/11] Handle zero register and stack pointer separately --- src/as/arch/aarch64/aarch64_code.h | 1 + src/as/arch/aarch64/asm_code.c | 7 +++- src/as/arch/aarch64/inst.h | 3 +- src/as/arch/aarch64/parse_aarch64.c | 61 +++++++++++++++++------------ 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 6296584fa..929815ced 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -61,6 +61,7 @@ #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) #define P_MOV(sz, rd, rs) W_ORR_S(sz, rd, ZERO, rs, 0) +#define P_MOV_SP(sz, rd, rs) W_ADD_I(sz, rd, rs, 0) #define P_MUL(sz, rd, rn, rm) W_MADD(sz, rd, rn, rm, ZERO) #define P_CMP(sz, rm, rn) W_SUBS_S(sz, ZERO, rm, rn, 0) #define P_CMP_I(sz, rd, imm) W_SUBS_I(sz, ZERO, rd, imm) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 66f7835aa..17a68d599 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -48,9 +48,12 @@ static unsigned char *asm_mov(Inst *inst, Code *code) { { assert(opr1->reg.size == opr2->reg.size); uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; - P_MOV(sz, opr1->reg.no, opr2->reg.no); - return code->buf; + if (opr1->reg.sp || opr2->reg.sp) + P_MOV_SP(sz, opr1->reg.no, opr2->reg.no); + else + P_MOV(sz, opr1->reg.no, opr2->reg.no); } + return code->buf; case IMMEDIATE: { uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index 889c5637c..3fbf482bc 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -38,7 +38,8 @@ enum RegSize { typedef struct { char size; // RegSize - char no; // 0~31 + char no; // 0~31 + char sp; } Reg; enum CondType { diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 20811c4ca..5d84b83bd 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -58,11 +58,12 @@ enum RegType { // 32bit W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, - W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30, W31, + W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30, WZR, // 64bit X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, - X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, + X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, XZR, + SP, }; typedef struct { @@ -72,9 +73,6 @@ typedef struct { #define FP X29 #define LR X30 -#define SP X31 -#define XZR X31 -#define WZR W31 static const RegisterTable kRegisters32[] = { {"w0", W0}, {"w1", W1}, {"w2", W2}, {"w3", W3}, @@ -84,9 +82,7 @@ static const RegisterTable kRegisters32[] = { {"w16", W16}, {"w17", W17}, {"w18", W18}, {"w19", W19}, {"w20", W20}, {"w21", W21}, {"w22", W22}, {"w23", W23}, {"w24", W24}, {"w25", W25}, {"w26", W26}, {"w27", W27}, - {"w28", W28}, {"w29", W29}, {"w30", W30}, {"w31", W31}, - // Alias - {"wzr", WZR}, + {"w28", W28}, {"w29", W29}, {"w30", W30}, {"wzr", WZR}, }; static const RegisterTable kRegisters64[] = { @@ -97,9 +93,11 @@ static const RegisterTable kRegisters64[] = { {"x16", X16}, {"x17", X17}, {"x18", X18}, {"x19", X19}, {"x20", X20}, {"x21", X21}, {"x22", X22}, {"x23", X23}, {"x24", X24}, {"x25", X25}, {"x26", X26}, {"x27", X27}, - {"x28", X28}, {"x29", X29}, {"x30", X30}, {"x31", X31}, + {"x28", X28}, {"x29", X29}, {"x30", X30}, {"xzr", XZR}, // Alias - {"fp", FP}, {"lr", LR}, {"sp", SP}, {"xzr", XZR}, + {"fp", FP}, {"lr", LR}, + // Stack pointer + {"sp", SP}, }; static const char kCondTable[][3] = { @@ -108,7 +106,7 @@ static const char kCondTable[][3] = { }; inline bool is_reg32(enum RegType reg) { - return reg >= W0 && reg <= W31; + return reg >= W0 && reg <= WZR; } inline bool is_reg64(enum RegType reg) { @@ -117,12 +115,14 @@ inline bool is_reg64(enum RegType reg) { #define R32 (1 << 0) #define R64 (1 << 1) -#define IMM (1 << 2) -#define IND (1 << 3) -#define ROI (1 << 4) // Register Offset Indirect -#define EXP (1 << 5) -#define CND (1 << 6) -#define SFT (1 << 7) // lsl #nn +#define RSP (1 << 2) +#define RZR (1 << 3) +#define IMM (1 << 4) +#define IND (1 << 5) +#define ROI (1 << 6) // Register Offset Indirect +#define EXP (1 << 7) +#define CND (1 << 8) +#define SFT (1 << 9) // lsl #nn static enum RegType find_register(const char **pp, unsigned int flag) { const char *p = *pp; @@ -167,7 +167,10 @@ static unsigned int parse_indirect_register(ParseInfo *info, Operand *operand) { parse_error(info, "Base register expected"); return 0; } - if (is_reg64(reg)) { + if (reg == SP) { + operand->indirect.reg.size = REG64; + operand->indirect.reg.no = 31; + } else if (is_reg64(reg) && reg != XZR) { operand->indirect.reg.size = REG64; operand->indirect.reg.no = reg - X0; } else { @@ -304,12 +307,19 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper if (reg != NOREG) { enum RegSize size; int no; - if (is_reg32(reg)) { + unsigned int result; + if (reg == SP) { + size = REG64; + no = 31; + result = RSP; + } else if (is_reg32(reg)) { size = REG32; no = reg - W0; + result = R32; } else if (is_reg64(reg)) { size = REG64; no = reg - X0; + result = R64; } else { assert(false); return 0; @@ -318,7 +328,8 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper operand->type = REG; operand->reg.size = size; operand->reg.no = no; - return size == REG32 ? R32 : R64; + operand->reg.sp = reg == SP; + return result; } } @@ -359,7 +370,7 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper const ParseInstTable kParseInstTable[] = { [R_MOV] = { 3, (const ParseOpArray*[]){ &(ParseOpArray){MOV, {R32, R32}}, - &(ParseOpArray){MOV, {R64, R64}}, + &(ParseOpArray){MOV, {R64 | RSP, R64 | RSP}}, &(ParseOpArray){MOV, {R32 | R64, IMM}}, } }, [R_MOVK] = { 1, (const ParseOpArray*[]){ @@ -370,16 +381,16 @@ const ParseInstTable kParseInstTable[] = { &(ParseOpArray){ADD_I, {R32, R32, IMM}}, &(ParseOpArray){ADD_I, {R32, R32, EXP}}, &(ParseOpArray){ADD_R, {R64, R64, R64}}, - &(ParseOpArray){ADD_I, {R64, R64, IMM}}, - &(ParseOpArray){ADD_I, {R64, R64, EXP}}, + &(ParseOpArray){ADD_I, {R64 | RSP, R64 | RSP, IMM}}, + &(ParseOpArray){ADD_I, {R64 | RSP, R64 | RSP, EXP}}, } }, [R_SUB] = { 6, (const ParseOpArray*[]){ &(ParseOpArray){SUB_R, {R32, R32, R32}}, &(ParseOpArray){SUB_I, {R32, R32, IMM}}, &(ParseOpArray){SUB_I, {R32, R32, EXP}}, &(ParseOpArray){SUB_R, {R64, R64, R64}}, - &(ParseOpArray){SUB_I, {R64, R64, IMM}}, - &(ParseOpArray){SUB_I, {R64, R64, EXP}}, + &(ParseOpArray){SUB_I, {R64 | RSP, R64 | RSP, IMM}}, + &(ParseOpArray){SUB_I, {R64 | RSP, R64 | RSP, EXP}}, } }, [R_MUL] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){MUL, {R32, R32, R32}}, &(ParseOpArray){MUL, {R64, R64, R64}} } }, [R_SDIV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){SDIV, {R32, R32, R32}}, &(ParseOpArray){SDIV, {R64, R64, R64}} } }, From 9f2e88d4c36b1135aad62be375d20c987aac1793 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 10 Jun 2024 09:12:32 +0900 Subject: [PATCH 09/11] Floating point instructions --- src/as/arch/aarch64/aarch64_code.h | 26 +++++ src/as/arch/aarch64/asm_code.c | 127 +++++++++++++++++++++++ src/as/arch/aarch64/inst.h | 10 ++ src/as/arch/aarch64/parse_aarch64.c | 151 +++++++++++++++++++++++++--- 4 files changed, 298 insertions(+), 16 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 929815ced..7e1c10146 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -71,3 +71,29 @@ #define P_LSR_I(sz, rd, rn, imm) W_UBFM(sz, opr1->reg.no, sz, opr2->reg.no, imm, 63>>(1-(sz))) #define P_ASR_I(sz, rd, rn, imm) W_SBFM(sz, opr1->reg.no, sz, opr2->reg.no, imm, 63>>(1-(sz))) #define P_CSET(sz, rd, cond) W_CSINC(sz, rd, ZERO, ZERO, (cond) ^ 1) + +// FP instructions. + +#define F_LDUR(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0xbc400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) +#define F_LDR_UIMM(b, s, rt, ofs, base) MAKE_CODE32(inst, code, 0xbd400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) +#define F_LDR(b, s, rt, ofs, base, prepost) MAKE_CODE32(inst, code, 0xbc400000U | ((b) << 30) | ((s) << 23) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((prepost) << 10) | ((base) << 5) | (rt)) +#define F_STUR(b, rt, ofs, base) MAKE_CODE32(inst, code, 0xbc000000U | ((b) << 30) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((base) << 5) | (rt)) +#define F_STR_UIMM(b, rt, ofs, base) MAKE_CODE32(inst, code, 0xbd000000U | ((b) << 30) | ((((ofs) & ((1U << 12) - 1))) << 10) | ((base) << 5) | (rt)) +#define F_STR(b, rt, ofs, base, prepost) MAKE_CODE32(inst, code, 0xbc000000U | ((b) << 30) | ((((ofs) & ((1U << 9) - 1))) << 12) | ((prepost) << 10) | ((base) << 5) | (rt)) +#define F_LDP(b, rt, ru, base, ofs, prepost) MAKE_CODE32(inst, code, 0x2c400000U | ((b) << 30) | ((prepost) << 23) | ((((ofs) & ((1U << 10) - (1 << 3)))) << (15 - 3)) | ((ru) << 10) | ((base) << 5) | (rt)) +#define F_STP(b, rt, ru, base, ofs, prepost) MAKE_CODE32(inst, code, 0x2c000000U | ((b) << 30) | ((prepost) << 23) | ((((ofs) & ((1U << 10) - (1 << 3)))) << (15 - 3)) | ((ru) << 10) | ((base) << 5) | (rt)) + +#define FMOV(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e204000U | ((sz) << 22) | ((rn) << 5) | (rd)) +#define FADD(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e202800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define FSUB(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e203800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define FMUL(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e200800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define FDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e201800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd)) +#define FCMP(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e602000U | ((sz) << 22) | ((rn) << 16) | ((rd) << 5)) +#define FNEG(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e214000U | ((sz) << 22) | ((rn) << 5) | (rd)) +#define FSQRT(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e21c000U | ((sz) << 22) | ((rn) << 5) | (rd)) + +#define SCVTF(dsz, rt, ssz, rn) MAKE_CODE32(inst, code, 0x1e220000 | ((dsz) << 31) | ((ssz) << 22) | ((rn) << 5) | (rt)) +#define UCVTF(dsz, rt, ssz, rn) MAKE_CODE32(inst, code, 0x1e230000 | ((dsz) << 31) | ((ssz) << 22) | ((rn) << 5) | (rt)) +#define FCVT(dsz, rt, rn) MAKE_CODE32(inst, code, 0x1e224000 | ((1 - (dsz)) << 22) | ((dsz) << 15) | ((rn) << 5) | (rt)) +#define FCVTZS(dsz, rt, ssz, rn) MAKE_CODE32(inst, code, 0x1e380000 | ((dsz) << 31) | ((ssz) << 22) | ((rn) << 5) | (rt)) +#define FCVTZU(dsz, rt, ssz, rn) MAKE_CODE32(inst, code, 0x1e390000 | ((dsz) << 31) | ((ssz) << 22) | ((rn) << 5) | (rt)) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 17a68d599..d7b618a25 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -349,6 +349,122 @@ static unsigned char *asm_ret(Inst *inst, Code *code) { return code->buf; } + +// FP instructions. + +static unsigned char *asm_f_ldrstr(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + if (opr2->type == INDIRECT) { + assert(opr2->indirect.reg.size == REG64); + // assert(opr2->indirect.offset == NULL || opr2->indirect.offset->kind == EX_FIXNUM); + Expr *offset_expr = opr2->indirect.offset; + int64_t offset = offset_expr != NULL && offset_expr->kind == EX_FIXNUM ? offset_expr->fixnum : 0; + assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); + uint32_t base = opr2->indirect.reg.no; + uint32_t prepost = kPrePost[opr2->indirect.prepost]; + + switch (inst->op) { + case F_LDR: + { + uint32_t s = 0; + if (opr2->indirect.prepost == 0) { + if (offset >= 0) + F_LDR_UIMM(sz, s, opr1->reg.no, offset >> (2 + sz), base); + else + F_LDUR(sz, s, opr1->reg.no, offset, base); + } else { + F_LDR(sz, s, opr1->reg.no, offset, base, prepost); + } + } + break; + case F_STR: + if (opr2->indirect.prepost == 0) { + if (offset >= 0) + F_STR_UIMM((inst->op - STRB) | sz, opr1->reg.no, 0, base); + else + F_STUR((inst->op - STRB) | sz, opr1->reg.no, offset, base); + } else { + F_STR((inst->op - STRB) | sz, opr1->reg.no, offset, base, prepost); + } + break; + default: assert(false); break; + } + return code->buf; + } else { + assert(opr2->type == REGISTER_OFFSET); + assert(opr2->register_offset.scale == NULL || opr2->register_offset.scale->kind == EX_FIXNUM); + + static const uint32_t opts[] = {3, 6, 2, 3, 3}; + uint32_t opt = opts[opr2->register_offset.extend]; + uint32_t s = opr2->register_offset.extend > 0 ? 1 : 0; + + switch (inst->op) { + case LDR: W_LDR_R(sz, opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, sz2, s, opt); break; + case STR: W_STR_R(sz, opr1->reg.no, opr2->register_offset.base_reg.no, opr2->register_offset.index_reg.no, opt); break; + default: assert(false); break; + } + return code->buf; + } +} + +static unsigned char *asm_f_ldpstp(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + Operand *opr3 = &inst->opr[2]; + assert(opr3->indirect.reg.size == REG64); + assert(opr3->indirect.offset->kind == EX_FIXNUM); + int64_t offset = opr3->indirect.offset->fixnum; + assert(offset < (1 << (6 + 3)) && offset >= -(1 << (6 + 3))); + uint32_t base = opr3->indirect.reg.no; + uint32_t prepost = kPrePost[opr3->indirect.prepost]; + switch (inst->op) { + case F_LDP: F_LDP(sz, opr1->reg.no, opr2->reg.no, base, offset, prepost); break; + case F_STP: F_STP(sz, opr1->reg.no, opr2->reg.no, base, offset, prepost); break; + default: assert(false); break; + } + return code->buf; +} + +static unsigned char *asm_f_3r(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + Operand *opr3 = &inst->opr[2]; + uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; + + switch (inst->op) { + case FADD: FADD(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case FSUB: FSUB(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case FMUL: FMUL(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + case FDIV: FDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; + default: assert(false); break; + } + return code->buf; +} + +static unsigned char *asm_f_2r(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + Operand *opr2 = &inst->opr[1]; + uint32_t dsz = opr1->reg.size == REG64 ? 1 : 0; + uint32_t ssz = opr2->reg.size == REG64 ? 1 : 0; + + switch (inst->op) { + case FMOV: FMOV(dsz, opr1->reg.no, opr2->reg.no); break; + case FCMP: FCMP(dsz, opr1->reg.no, opr2->reg.no); break; + case FNEG: FNEG(dsz, opr1->reg.no, opr2->reg.no); break; + case FSQRT: FSQRT(dsz, opr1->reg.no, opr2->reg.no); break; + case SCVTF: SCVTF(ssz, opr1->reg.no, dsz, opr2->reg.no); break; + case UCVTF: UCVTF(ssz, opr1->reg.no, dsz, opr2->reg.no); break; + case FCVT: FCVT(dsz, opr1->reg.no, opr2->reg.no); break; + case FCVTZS: FCVTZS(dsz, opr1->reg.no, ssz, opr2->reg.no); break; + case FCVTZU: FCVTZU(dsz, opr1->reg.no, ssz, opr2->reg.no); break; + default: assert(false); break; + } + return code->buf; +} + //////////////////////////////////////////////// typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); @@ -384,6 +500,17 @@ static const AsmInstFunc table[] = { [BL] = asm_bl, [BLR] = asm_blr, [RET] = asm_ret, + + [F_LDR] = asm_f_ldrstr, + [F_STR] = asm_f_ldrstr, + [F_LDP] = asm_f_ldpstp, + [F_STP] = asm_f_ldpstp, + [FMOV] = asm_f_2r, + [FADD] = asm_f_3r, [FSUB] = asm_f_3r, [FMUL] = asm_f_3r, [FDIV] = asm_f_3r, + [FCMP] = asm_f_2r, [FNEG] = asm_f_2r, + [FSQRT] = asm_f_2r, + [SCVTF] = asm_f_2r, [UCVTF] = asm_f_2r, + [FCVT] = asm_f_2r, [FCVTZS] = asm_f_2r, [FCVTZU] = asm_f_2r, }; void assemble_inst(Inst *inst, const ParseInfo *info, Code *code) { diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index 3fbf482bc..b4bad08cd 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -29,6 +29,15 @@ enum Opcode { BHI, BLS, BGE, BLT, BGT, BLE, BAL, BNV, BL, BLR, RET, + + F_LDR, F_STR, + F_LDP, F_STP, + FMOV, + FADD, FSUB, FMUL, FDIV, + FCMP, FNEG, + FSQRT, + SCVTF, UCVTF, + FCVT, FCVTZS, FCVTZU, }; enum RegSize { @@ -63,6 +72,7 @@ enum OperandType { // post-index: [reg],#nn REGISTER_OFFSET, // [reg,reg,#nn] COND, + FREG, // freg }; typedef struct { diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 5d84b83bd..d53560432 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -29,6 +29,13 @@ enum RawOpcode { R_BHI, R_BLS, R_BGE, R_BLT, R_BGT, R_BLE, R_BAL, R_BNV, R_BL, R_BLR, R_RET, + + R_FMOV, + R_FADD, R_FSUB, R_FMUL, R_FDIV, + R_FCMP, R_FNEG, + R_FSQRT, + R_SCVTF, R_UCVTF, + R_FCVT, R_FCVTZS, R_FCVTZU, }; const char *kRawOpTable[] = { @@ -50,6 +57,13 @@ const char *kRawOpTable[] = { "bhi", "bls", "bge", "blt", "bgt", "ble", "bal", "bnv", "bl", "blr", "ret", + + "fmov", + "fadd", "fsub", "fmul", "fdiv", + "fcmp", "fneg", + "fsqrt", + "scvtf", "ucvtf", + "fcvt", "fcvtzs", "fcvtzu", NULL, }; @@ -64,6 +78,14 @@ enum RegType { X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, XZR, SP, + + // FP32bit + S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, + S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, + + // FP64bit + D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, }; typedef struct { @@ -100,6 +122,28 @@ static const RegisterTable kRegisters64[] = { {"sp", SP}, }; +static const RegisterTable kFRegisters32[] = { + {"s0", S0}, {"s1", S1}, {"s2", S2}, {"s3", S3}, + {"s4", S4}, {"s5", S5}, {"s6", S6}, {"s7", S7}, + {"s8", S8}, {"s9", S9}, {"s10", S10}, {"s11", S11}, + {"s12", S12}, {"s13", S13}, {"s14", S14}, {"s15", S15}, + {"s16", S16}, {"s17", S17}, {"s18", S18}, {"s19", S19}, + {"s20", S20}, {"s21", S21}, {"s22", S22}, {"s23", S23}, + {"s24", S24}, {"s25", S25}, {"s26", S26}, {"s27", S27}, + {"s28", S28}, {"s29", S29}, {"s30", S30}, {"s31", S31}, +}; + +static const RegisterTable kFRegisters64[] = { + {"d0", D0}, {"d1", D1}, {"d2", D2}, {"d3", D3}, + {"d4", D4}, {"d5", D5}, {"d6", D6}, {"d7", D7}, + {"d8", D8}, {"d9", D9}, {"d10", D10}, {"d11", D11}, + {"d12", D12}, {"d13", D13}, {"d14", D14}, {"d15", D15}, + {"d16", D16}, {"d17", D17}, {"d18", D18}, {"d19", D19}, + {"d20", D20}, {"d21", D21}, {"d22", D22}, {"d23", D23}, + {"d24", D24}, {"d25", D25}, {"d26", D26}, {"d27", D27}, + {"d28", D28}, {"d29", D29}, {"d30", D30}, {"d31", D31}, +}; + static const char kCondTable[][3] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "nv", @@ -113,21 +157,31 @@ inline bool is_reg64(enum RegType reg) { return reg >= X0 && reg <= SP; } +inline bool is_freg32(enum RegType reg) { + return reg >= S0 && reg <= S31; +} + +inline bool is_freg64(enum RegType reg) { + return reg >= D0 && reg <= D31; +} + #define R32 (1 << 0) #define R64 (1 << 1) -#define RSP (1 << 2) -#define RZR (1 << 3) -#define IMM (1 << 4) -#define IND (1 << 5) -#define ROI (1 << 6) // Register Offset Indirect -#define EXP (1 << 7) -#define CND (1 << 8) -#define SFT (1 << 9) // lsl #nn +#define F32 (1 << 2) +#define F64 (1 << 3) +#define RSP (1 << 4) +#define RZR (1 << 5) +#define IMM (1 << 6) +#define IND (1 << 7) +#define ROI (1 << 8) // Register Offset Indirect +#define EXP (1 << 9) +#define CND (1 << 10) +#define SFT (1 << 11) // lsl #nn static enum RegType find_register(const char **pp, unsigned int flag) { const char *p = *pp; - static const RegisterTable *kRegisters[] = { kRegisters32, kRegisters64 }; - static const int kRegistersCount[] = { ARRAY_SIZE(kRegisters32), ARRAY_SIZE(kRegisters64) }; + static const RegisterTable *kRegisters[] = { kRegisters32, kRegisters64, kFRegisters32, kFRegisters64 }; + static const int kRegistersCount[] = { ARRAY_SIZE(kRegisters32), ARRAY_SIZE(kRegisters64), ARRAY_SIZE(kFRegisters32), ARRAY_SIZE(kFRegisters64) }; for (int i = 0; i < (int)ARRAY_SIZE(kRegisters); ++i) { if ((flag & (R32 << i)) == 0) continue; @@ -302,7 +356,7 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper } } - if (opr_flag & (R32 | R64)) { + if (opr_flag & (R32 | R64 | F32 | F64)) { enum RegType reg = find_register(&info->p, opr_flag); if (reg != NOREG) { enum RegSize size; @@ -320,12 +374,20 @@ unsigned int parse_operand(ParseInfo *info, unsigned int opr_flag, Operand *oper size = REG64; no = reg - X0; result = R64; + } else if (is_freg32(reg)) { + size = REG32; + no = reg - S0; + result = F32; + } else if (is_freg64(reg)) { + size = REG64; + no = reg - D0; + result = F64; } else { assert(false); return 0; } - operand->type = REG; + operand->type = (result & (F32 | F64)) != 0 ? FREG : REG; operand->reg.size = size; operand->reg.no = no; operand->reg.sp = reg == SP; @@ -437,14 +499,30 @@ const ParseInstTable kParseInstTable[] = { [R_UXTW] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UXTW, {R64, R32}} } }, [R_LDRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRB, {R32 | R64, IND | ROI}} } }, [R_LDRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRH, {R32 | R64, IND | ROI}} } }, - [R_LDR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDR, {R32 | R64, IND | ROI}} } }, + [R_LDR] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){LDR, {R32 | R64, IND | ROI}}, + &(ParseOpArray){F_LDR, {F32 | F64, IND | ROI}}, + } }, [R_LDRSB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSB, {R32 | R64, IND | ROI}} } }, [R_LDRSH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){LDRSH, {R32 | R64, IND | ROI}} } }, [R_STRB] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRB, {R32, IND | ROI}} } }, [R_STRH] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STRH, {R32, IND | ROI}} } }, - [R_STR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){STR, {R32 | R64, IND | ROI}} } }, - [R_LDP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){LDP, {R32, R32, IND}}, &(ParseOpArray){LDP, {R64, R64, IND}} } }, - [R_STP] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){STP, {R32, R32, IND}}, &(ParseOpArray){STP, {R64, R64, IND}} } }, + [R_STR] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){STR, {R32 | R64, IND | ROI}}, + &(ParseOpArray){F_STR, {F32 | F64, IND | ROI}}, + } }, + [R_LDP] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){LDP, {R32, R32, IND}}, + &(ParseOpArray){LDP, {R64, R64, IND}}, + &(ParseOpArray){F_LDP, {F32, F32, IND}}, + &(ParseOpArray){F_LDP, {F64, F64, IND}}, + } }, + [R_STP] = { 4, (const ParseOpArray*[]){ + &(ParseOpArray){STP, {R32, R32, IND}}, + &(ParseOpArray){STP, {R64, R64, IND}}, + &(ParseOpArray){F_STP, {F32, F32, IND}}, + &(ParseOpArray){F_STP, {F64, F64, IND}}, + } }, [R_ADRP] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){ADRP, {R64, EXP}} } }, [R_CSET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){CSET, {R32 | R64, CND}} } }, [R_B] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){B, {EXP}} } }, @@ -468,4 +546,45 @@ const ParseInstTable kParseInstTable[] = { [R_BL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BL, {EXP}} } }, [R_BLR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLR, {R64}} } }, [R_RET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){RET} } }, + + [R_FMOV] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FMOV, {F32, F32}}, + &(ParseOpArray){FMOV, {F64, F64}}, + } }, + [R_FADD] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FADD, {F32, F32, F32}}, + &(ParseOpArray){FADD, {F64, F64, F64}}, + } }, + [R_FSUB] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FSUB, {F32, F32, F32}}, + &(ParseOpArray){FSUB, {F64, F64, F64}}, + } }, + [R_FMUL] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FMUL, {F32, F32, F32}}, + &(ParseOpArray){FMUL, {F64, F64, F64}}, + } }, + [R_FDIV] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FDIV, {F32, F32, F32}}, + &(ParseOpArray){FDIV, {F64, F64, F64}}, + } }, + [R_FCMP] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FCMP, {F32, F32}}, + &(ParseOpArray){FCMP, {F64, F64}}, + } }, + [R_FNEG] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FNEG, {F32, F32}}, + &(ParseOpArray){FNEG, {F64, F64}}, + } }, + [R_FSQRT] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FSQRT, {F32, F32}}, + &(ParseOpArray){FSQRT, {F64, F64}}, + } }, + [R_SCVTF] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){SCVTF, {F32 | F64, R32 | R64}} } }, + [R_UCVTF] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UCVTF, {F32 | F64, R32 | R64}} } }, + [R_FCVT] = { 2, (const ParseOpArray*[]){ + &(ParseOpArray){FCVT, {F64, F32}}, + &(ParseOpArray){FCVT, {F32, F64}}, + } }, + [R_FCVTZS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){FCVTZS, {R32 | R64, F32 | F64}} } }, + [R_FCVTZU] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){FCVTZU, {R32 | R64, F32 | F64}} } }, }; From 1bf66277377be67c78a692cc58e2cb628e8c3275 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 13 Jun 2024 09:21:15 +0900 Subject: [PATCH 10/11] Add/sub with sp register Fix for alloca. --- src/as/arch/aarch64/aarch64_code.h | 2 ++ src/as/arch/aarch64/asm_code.c | 18 ++++++++++++++++-- src/as/arch/aarch64/parse_aarch64.c | 6 ++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index 7e1c10146..e85c2fd04 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -8,12 +8,14 @@ #define W_ADD_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x11000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_ADD_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x0b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_ADD_E(sz, rd, rn, rm, option, ov) MAKE_CODE32(inst, code, 0x4b200000U | ((sz) << 31) | ((rm) << 16) | ((option) << 13) | ((ov) << 10) | ((rn) << 5) | (rd)) #define W_ADDS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x31000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_ADDS_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x2b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUB_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x51000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUB_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x4b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUBS_I(sz, rd, rn, imm) MAKE_CODE32(inst, code, 0x71000000U | ((sz) << 31) | (((imm) & ((1U << 12) - 1)) << 10) | ((rn) << 5) | (rd)) #define W_SUBS_S(sz, rd, rn, rm, imm) MAKE_CODE32(inst, code, 0x6b000000U | ((sz) << 31) | ((rm) << 16) | (((imm) & ((1U << 6) - 1)) << 10) | ((rn) << 5) | (rd)) +#define W_SUB_E(sz, rd, rn, rm, option, ov) MAKE_CODE32(inst, code, 0x4b200000U | ((sz) << 31) | ((rm) << 16) | ((option) << 13) | ((ov) << 10) | ((rn) << 5) | (rd)) #define W_MADD(sz, rd, rn, rm, ra) MAKE_CODE32(inst, code, 0x1b000000U | ((sz) << 31) | ((rm) << 16) | ((ra) << 10) | ((rn) << 5) | (rd)) #define W_MSUB(sz, rd, rn, rm, ra) MAKE_CODE32(inst, code, 0x1b008000U | ((sz) << 31) | ((rm) << 16) | ((ra) << 10) | ((rn) << 5) | (rd)) #define W_SDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1ac00c00U | ((sz) << 31) | ((rm) << 16) | ((rn) << 5) | (rd)) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index d7b618a25..2d4d43e16 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -88,8 +88,22 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { uint32_t sz = opr1->reg.size == REG64 ? 1 : 0; switch (inst->op) { - case ADD_R: W_ADD_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; - case SUB_R: W_SUB_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); break; + case ADD_R: + if (!opr1->reg.sp && !opr2->reg.sp) { + W_ADD_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); + } else { + const uint32_t option = 3; // LSL 0 + W_ADD_E(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, option, 0); + } + break; + case SUB_R: + if (!opr1->reg.sp && !opr2->reg.sp) { + W_SUB_S(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, 0); + } else { + const uint32_t option = 3; // LSL 0 + W_SUB_E(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no, option, 0); + } + break; case MUL: P_MUL(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; case SDIV: W_SDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; case UDIV: W_UDIV(sz, opr1->reg.no, opr2->reg.no, opr3->reg.no); break; diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index d53560432..4547cc2ce 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -438,19 +438,21 @@ const ParseInstTable kParseInstTable[] = { [R_MOVK] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){MOVK, {R32 | R64, IMM, SFT}}, } }, - [R_ADD] = { 6, (const ParseOpArray*[]){ + [R_ADD] = { 7, (const ParseOpArray*[]){ &(ParseOpArray){ADD_R, {R32, R32, R32}}, &(ParseOpArray){ADD_I, {R32, R32, IMM}}, &(ParseOpArray){ADD_I, {R32, R32, EXP}}, &(ParseOpArray){ADD_R, {R64, R64, R64}}, + &(ParseOpArray){ADD_R, {R64 | RSP, R64 | RSP, R64}}, &(ParseOpArray){ADD_I, {R64 | RSP, R64 | RSP, IMM}}, &(ParseOpArray){ADD_I, {R64 | RSP, R64 | RSP, EXP}}, } }, - [R_SUB] = { 6, (const ParseOpArray*[]){ + [R_SUB] = { 7, (const ParseOpArray*[]){ &(ParseOpArray){SUB_R, {R32, R32, R32}}, &(ParseOpArray){SUB_I, {R32, R32, IMM}}, &(ParseOpArray){SUB_I, {R32, R32, EXP}}, &(ParseOpArray){SUB_R, {R64, R64, R64}}, + &(ParseOpArray){SUB_R, {R64 | RSP, R64 | RSP, R64}}, &(ParseOpArray){SUB_I, {R64 | RSP, R64 | RSP, IMM}}, &(ParseOpArray){SUB_I, {R64 | RSP, R64 | RSP, EXP}}, } }, From 5ec6086dd464b2276177c52e7eadda9c50379aa3 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 12 Jun 2024 10:14:05 +0900 Subject: [PATCH 11/11] Test succeeded --- include/math.h | 2 +- libsrc/crt0/_start.c | 2 +- libsrc/misc/longjmp.c | 22 +++++++++++----------- libsrc/misc/setjmp.c | 20 ++++++++++---------- libsrc/stdlib/environ.c | 1 + libsrc/stdlib/getenv.c | 2 +- src/as/arch/aarch64/aarch64_code.h | 1 + src/as/arch/aarch64/asm_code.c | 6 ++++++ src/as/arch/aarch64/inst.h | 1 + src/as/arch/aarch64/parse_aarch64.c | 3 +++ src/config.h | 1 - 11 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 libsrc/stdlib/environ.c diff --git a/include/math.h b/include/math.h index 506357d1c..992cfd733 100644 --- a/include/math.h +++ b/include/math.h @@ -51,7 +51,7 @@ int isinf(double x); int signbit(double x); double copysign(double x, double f); -#if defined(__APPLE__) || defined(__GNUC__) || defined(__riscv) +#if defined(__APPLE__) || defined(__GNUC__) || defined(__aarch64__) || defined(__riscv) // isfinite, isinf and isnan is defined by macro and not included in lib file, // so it will be link error. #include diff --git a/libsrc/crt0/_start.c b/libsrc/crt0/_start.c index e8f87ca73..1f014cf58 100644 --- a/libsrc/crt0/_start.c +++ b/libsrc/crt0/_start.c @@ -4,7 +4,7 @@ #pragma GCC diagnostic ignored "-Wunused-function" #endif -char **environ; +extern char **environ; #if defined(__linux__) diff --git a/libsrc/misc/longjmp.c b/libsrc/misc/longjmp.c index 93c41b794..5bf90f3a2 100644 --- a/libsrc/misc/longjmp.c +++ b/libsrc/misc/longjmp.c @@ -41,23 +41,23 @@ void longjmp(jmp_buf env, int result) { #define RESTORE_FREGS // Empty #else #define RESTORE_FREGS \ - "ldp d8, d9, [x0, 112]\n" \ - "ldp d10, d11, [x0, 128]\n" \ - "ldp d12, d13, [x0, 144]\n" \ - "ldp d14, d15, [x0, 160]\n" + "ldp d8, d9, [x0, #112]\n" \ + "ldp d10, d11, [x0, #128]\n" \ + "ldp d12, d13, [x0, #144]\n" \ + "ldp d14, d15, [x0, #160]\n" #endif __asm("ldp fp, lr, [x0]\n" - "ldp x9, x19, [x0, 16]\n" - "ldp x20, x21, [x0, 32]\n" - "ldp x22, x23, [x0, 48]\n" - "ldp x24, x25, [x0, 64]\n" - "ldp x26, x27, [x0, 80]\n" - "ldp x28, x29, [x0, 96]\n" + "ldp x9, x19, [x0, #16]\n" + "ldp x20, x21, [x0, #32]\n" + "ldp x22, x23, [x0, #48]\n" + "ldp x24, x25, [x0, #64]\n" + "ldp x26, x27, [x0, #80]\n" + "ldp x28, x29, [x0, #96]\n" RESTORE_FREGS "mov sp, x9\n" "mov w0, w1\n" // Result value. "cmp w0, wzr\n" - "b.ne .longjmp_0\n" + "bne .longjmp_0\n" "mov w0, #1\n" ".longjmp_0:"); } diff --git a/libsrc/misc/setjmp.c b/libsrc/misc/setjmp.c index bbfd44180..ac9ad5051 100644 --- a/libsrc/misc/setjmp.c +++ b/libsrc/misc/setjmp.c @@ -37,19 +37,19 @@ int setjmp(jmp_buf env) { #define SAVE_FREGS // Empty #else #define SAVE_FREGS \ - "stp d8, d9, [x0, 112]\n" \ - "stp d10, d11, [x0, 128]\n" \ - "stp d12, d13, [x0, 144]\n" \ - "stp d14, d15, [x0, 160]\n" + "stp d8, d9, [x0, #112]\n" \ + "stp d10, d11, [x0, #128]\n" \ + "stp d12, d13, [x0, #144]\n" \ + "stp d14, d15, [x0, #160]\n" #endif __asm("stp fp, lr, [x0]\n" "mov x9, sp\n" - "stp x9, x19, [x0, 16]\n" - "stp x20, x21, [x0, 32]\n" - "stp x22, x23, [x0, 48]\n" - "stp x24, x25, [x0, 64]\n" - "stp x26, x27, [x0, 80]\n" - "stp x28, x29, [x0, 96]\n" + "stp x9, x19, [x0, #16]\n" + "stp x20, x21, [x0, #32]\n" + "stp x22, x23, [x0, #48]\n" + "stp x24, x25, [x0, #64]\n" + "stp x26, x27, [x0, #80]\n" + "stp x28, x29, [x0, #96]\n" SAVE_FREGS "mov w0, wzr"); } diff --git a/libsrc/stdlib/environ.c b/libsrc/stdlib/environ.c new file mode 100644 index 000000000..9109d7fb0 --- /dev/null +++ b/libsrc/stdlib/environ.c @@ -0,0 +1 @@ +char **environ; diff --git a/libsrc/stdlib/getenv.c b/libsrc/stdlib/getenv.c index 06a8bca44..397a62005 100644 --- a/libsrc/stdlib/getenv.c +++ b/libsrc/stdlib/getenv.c @@ -1,7 +1,7 @@ #include "stdlib.h" #include "string.h" -char **environ; +extern char **environ; char *getenv(const char *varname) { if (environ != NULL) { diff --git a/src/as/arch/aarch64/aarch64_code.h b/src/as/arch/aarch64/aarch64_code.h index e85c2fd04..0ffa33976 100644 --- a/src/as/arch/aarch64/aarch64_code.h +++ b/src/as/arch/aarch64/aarch64_code.h @@ -61,6 +61,7 @@ #define W_BL(offset) MAKE_CODE32(inst, code, 0x94000000U | ((offset) & ((1U << 26) - 1))) #define W_BLR(rn) MAKE_CODE32(inst, code, 0xd63f0000U | ((rn) << 5)) #define W_RET(rn) MAKE_CODE32(inst, code, 0xd65f0000U | ((rn) << 5)) +#define W_SVC(imm) MAKE_CODE32(inst, code, 0xd4000001U | ((imm) << 5)) #define P_MOV(sz, rd, rs) W_ORR_S(sz, rd, ZERO, rs, 0) #define P_MOV_SP(sz, rd, rs) W_ADD_I(sz, rd, rs, 0) diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 2d4d43e16..ecb74276c 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -363,6 +363,11 @@ static unsigned char *asm_ret(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_svc(Inst *inst, Code *code) { + Operand *opr1 = &inst->opr[0]; + W_SVC(opr1->immediate); + return code->buf; +} // FP instructions. @@ -514,6 +519,7 @@ static const AsmInstFunc table[] = { [BL] = asm_bl, [BLR] = asm_blr, [RET] = asm_ret, + [SVC] = asm_svc, [F_LDR] = asm_f_ldrstr, [F_STR] = asm_f_ldrstr, diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index b4bad08cd..57fa0536c 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -29,6 +29,7 @@ enum Opcode { BHI, BLS, BGE, BLT, BGT, BLE, BAL, BNV, BL, BLR, RET, + SVC, F_LDR, F_STR, F_LDP, F_STP, diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 4547cc2ce..6deaed62e 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -29,6 +29,7 @@ enum RawOpcode { R_BHI, R_BLS, R_BGE, R_BLT, R_BGT, R_BLE, R_BAL, R_BNV, R_BL, R_BLR, R_RET, + R_SVC, R_FMOV, R_FADD, R_FSUB, R_FMUL, R_FDIV, @@ -57,6 +58,7 @@ const char *kRawOpTable[] = { "bhi", "bls", "bge", "blt", "bgt", "ble", "bal", "bnv", "bl", "blr", "ret", + "svc", "fmov", "fadd", "fsub", "fmul", "fdiv", @@ -548,6 +550,7 @@ const ParseInstTable kParseInstTable[] = { [R_BL] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BL, {EXP}} } }, [R_BLR] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){BLR, {R64}} } }, [R_RET] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){RET} } }, + [R_SVC] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){SVC, {IMM}} } }, [R_FMOV] = { 2, (const ParseOpArray*[]){ &(ParseOpArray){FMOV, {F32, F32}}, diff --git a/src/config.h b/src/config.h index db234050d..995fbd8ad 100644 --- a/src/config.h +++ b/src/config.h @@ -46,7 +46,6 @@ // Posix # if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 -# define USE_SYS_AS # define USE_SYS_LD # define NO_STD_LIB # endif