kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

arch.c (8599B)


      1 #include "arch/arch.h"
      2 
      3 #include <string.h>
      4 
      5 #include "arch/aa64/aa64.h"
      6 #include "arch/aa64/asm.h"
      7 #include "arch/aa64/disasm.h"
      8 #include "arch/aa64/isa.h"
      9 #include "arch/aa64/regs.h"
     10 #include "cg/native_direct_target.h"
     11 #include "core/bytes.h"
     12 #include "link/link_arch.h"
     13 #include "obj/obj.h"
     14 
     15 extern const LinkArchDesc link_arch_aa64;
     16 extern const ArchDbgOps aa64_dbg_ops;
     17 extern const ArchDwarfOps aa64_dwarf_ops;
     18 extern const ArchAsmOps aa64_asm_ops;
     19 
     20 static int aa64_register_at_public(uint32_t idx, KitArchReg* out) {
     21   return arch_register_at_public(idx, out, aa64_register_iter_get);
     22 }
     23 
     24 static void aa64_wr_u64_target(Compiler* c, u8* p, u64 v) {
     25   if (c && c->target.big_endian) {
     26     for (u32 i = 0; i < 8; ++i) p[i] = (u8)(v >> ((7u - i) * 8u));
     27   } else {
     28     wr_u64_le(p, v);
     29   }
     30 }
     31 
     32 static int aa64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) {
     33   const Section* s;
     34   u8 cur[4];
     35   u32 word;
     36 
     37   if (!fx) return 1;
     38   if (fx->kind != R_AARCH64_INTRA_LABEL_ADDR && fx->width != 4) return 1;
     39   if (fx->kind == R_AARCH64_INTRA_LABEL_ADDR && fx->width != 16) return 1;
     40   s = obj_section_get(fx->obj, fx->sec_id);
     41   if (!s) return 0;
     42   buf_read(&s->bytes, fx->offset, cur, 4);
     43   word = rd_u32_le(cur);
     44 
     45   switch (fx->kind) {
     46     case R_AARCH64_JUMP26:
     47     case R_AARCH64_CALL26: {
     48       i64 idisp = fx->disp >> 2;
     49       u32 imm26 = (u32)(idisp & 0x03ffffffu);
     50       word = (word & ~0x03ffffffu) | imm26;
     51       break;
     52     }
     53     case R_AARCH64_CONDBR19: {
     54       i64 idisp = fx->disp >> 2;
     55       u32 imm19 = (u32)(idisp & 0x7ffffu);
     56       word = (word & ~(0x7ffffu << 5)) | (imm19 << 5);
     57       break;
     58     }
     59     case R_AARCH64_ADR_PREL_LO21: {
     60       /* ADR: imm21 (byte displacement) split into immlo (bits 30:29)
     61        * and immhi (bits 23:5). */
     62       if (fx->disp < -(i64)(1 << 20) || fx->disp >= (i64)(1 << 20)) {
     63         compiler_panic(c, (SrcLoc){0, 0, 0},
     64                        "aarch64 label fixup: ADR target out of range "
     65                        "(need +/-1MiB)");
     66       }
     67       u32 imm21 = (u32)(fx->disp & 0x1fffffu);
     68       u32 immlo = imm21 & 0x3u;
     69       u32 immhi = (imm21 >> 2) & 0x7ffffu;
     70       word = (word & ~((0x3u << 29) | (0x7ffffu << 5))) | (immlo << 29) |
     71              (immhi << 5);
     72       break;
     73     }
     74     case R_AARCH64_INTRA_LABEL_ADDR: {
     75       u32 rd = word & 0x1fu;
     76       if (fx->disp >= -(i64)(1 << 20) && fx->disp < (i64)(1 << 20)) {
     77         u32 imm21 = (u32)(fx->disp & 0x1fffffu);
     78         u32 immlo = imm21 & 0x3u;
     79         u32 immhi = (imm21 >> 2) & 0x7ffffu;
     80         word = aa64_adr(rd, immlo, immhi);
     81       } else {
     82         u8 lit[8];
     83         i64 label_offset;
     84         i64 addend;
     85         if (fx->cur_func_sym == OBJ_SYM_NONE) {
     86           compiler_panic(c, (SrcLoc){0, 0, 0},
     87                          "aarch64 label fixup: wide label address resolved "
     88                          "outside a function");
     89         }
     90         label_offset = (i64)fx->offset + fx->disp;
     91         addend = label_offset - (i64)fx->cur_func_start;
     92         word = 0x58000000u | (2u << 5) | rd; /* LDR Xt, [PC + 8] */
     93         aa64_wr_u64_target(c, lit, (u64)addend);
     94         obj_patch(fx->obj, fx->sec_id, fx->offset + 8u, lit, sizeof lit);
     95         obj_reloc_ex(fx->obj, fx->sec_id, fx->offset + 8u, R_ABS64,
     96                      fx->cur_func_sym, addend, 1, 0);
     97       }
     98       break;
     99     }
    100     default:
    101       return 1;
    102   }
    103 
    104   wr_u32_le(cur, word);
    105   obj_patch(fx->obj, fx->sec_id, fx->offset, cur, 4);
    106   return 0;
    107 }
    108 
    109 static CgTarget* aa64_backend_make(Compiler* c, ObjBuilder* o,
    110                                    const KitCodeOptions* opts) {
    111   return native_direct_backend_make(c, o, opts, aa64_native_target_new,
    112                                     aa64_native_direct_ops());
    113 }
    114 
    115 static CgTarget* aa64_semantic_target_new(Compiler* c, ObjBuilder* o,
    116                                           MCEmitter* mc) {
    117   return native_direct_semantic_target_new(c, o, mc, aa64_native_target_new,
    118                                            aa64_native_direct_ops());
    119 }
    120 
    121 static const KitPredefinedMacro aa64_predefined_macros[] = {
    122     {KIT_SLICE_LIT("__aarch64__"), KIT_SLICE_LIT("1")},
    123     {KIT_SLICE_LIT("__AARCH64EL__"), KIT_SLICE_LIT("1")},
    124     {KIT_SLICE_LIT("__arm64"), KIT_SLICE_LIT("1")},
    125     {KIT_SLICE_LIT("__arm64__"), KIT_SLICE_LIT("1")},
    126     {KIT_SLICE_LIT("__LP64__"), KIT_SLICE_LIT("1")},
    127     {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")},
    128     {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")},
    129     {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")},
    130     {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")},
    131 };
    132 
    133 static const ArchTargetFeature aa64_target_features[] = {
    134     {"bti"},
    135     {"pac-ret"},
    136     {"lse"},
    137 };
    138 
    139 static KitStatus aa64_target_feature_apply_isa(const Target* target,
    140                                                KitSlice isa, u64* words,
    141                                                u32 nwords) {
    142   (void)target;
    143   (void)words;
    144   (void)nwords;
    145   if (kit_slice_eq_cstr(isa, "aarch64") || kit_slice_eq_cstr(isa, "arm64") ||
    146       kit_slice_eq_cstr(isa, "armv8-a"))
    147     return KIT_OK;
    148   return KIT_UNSUPPORTED;
    149 }
    150 
    151 /* AArch64 emits AAPCS (and the target-C convention) regardless of OS; it has
    152  * no SysV/Win64/WASM variant. */
    153 static int aa64_supports_call_conv(const Compiler* c, KitCgCallConv cc) {
    154   (void)c;
    155   return cc == KIT_CG_CC_TARGET_C;
    156 }
    157 
    158 /* Capability twin of aa_intrinsic (src/arch/aa64/native.c); keep the two in
    159  * sync. No default case, so a new KitCgIntrinsic trips -Wswitch here. */
    160 static int aa64_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) {
    161   switch (intrin) {
    162     case KIT_CG_INTRIN_TRAP:
    163     case KIT_CG_INTRIN_CLZ:
    164     case KIT_CG_INTRIN_CTZ:
    165     case KIT_CG_INTRIN_POPCOUNT:
    166     case KIT_CG_INTRIN_BSWAP:
    167     case KIT_CG_INTRIN_SADD_OVERFLOW:
    168     case KIT_CG_INTRIN_UADD_OVERFLOW:
    169     case KIT_CG_INTRIN_SSUB_OVERFLOW:
    170     case KIT_CG_INTRIN_USUB_OVERFLOW:
    171     case KIT_CG_INTRIN_SMUL_OVERFLOW:
    172     case KIT_CG_INTRIN_UMUL_OVERFLOW:
    173     case KIT_CG_INTRIN_PREFETCH:
    174     case KIT_CG_INTRIN_EXPECT:
    175     case KIT_CG_INTRIN_ASSUME_ALIGNED:
    176     case KIT_CG_INTRIN_CPU_NOP:
    177     case KIT_CG_INTRIN_CPU_YIELD:
    178     case KIT_CG_INTRIN_ISB:
    179     case KIT_CG_INTRIN_DMB:
    180     case KIT_CG_INTRIN_DSB:
    181     case KIT_CG_INTRIN_WFI:
    182     case KIT_CG_INTRIN_WFE:
    183     case KIT_CG_INTRIN_SEV:
    184     case KIT_CG_INTRIN_IRQ_SAVE:
    185     case KIT_CG_INTRIN_IRQ_RESTORE:
    186     case KIT_CG_INTRIN_IRQ_ENABLE:
    187     case KIT_CG_INTRIN_IRQ_DISABLE:
    188     case KIT_CG_INTRIN_FRAME_ADDRESS:
    189     case KIT_CG_INTRIN_RETURN_ADDRESS:
    190     case KIT_CG_INTRIN_READCYCLECOUNTER: /* MRS CNTVCT_EL0 */
    191     case KIT_CG_INTRIN_SMUL_HIGH:
    192     case KIT_CG_INTRIN_UMUL_HIGH:
    193       return 1;
    194     case KIT_CG_INTRIN_SYSCALL:
    195       return c->target.os == KIT_OS_LINUX ||
    196              c->target.os == KIT_OS_FREESTANDING;
    197     case KIT_CG_INTRIN_SETJMP:
    198     case KIT_CG_INTRIN_LONGJMP:
    199     case KIT_CG_INTRIN_FMA:
    200     case KIT_CG_INTRIN_DCACHE_CLEAN:
    201     case KIT_CG_INTRIN_DCACHE_INVALIDATE:
    202     case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE:
    203     case KIT_CG_INTRIN_ICACHE_INVALIDATE:
    204     case KIT_CG_INTRIN_CORO_SWITCH:
    205       return 0;
    206   }
    207   return 0;
    208 }
    209 
    210 const ArchImpl arch_impl_aa64 = {
    211     .backend = {.name = "aa64", .make = aa64_backend_make},
    212     .kind = KIT_ARCH_ARM_64,
    213     .name = "aa64",
    214     .cgtarget_new = aa64_semantic_target_new,
    215     .asm_new = aa64_arch_asm_new,
    216     .disasm_new = aa64_disasm_new,
    217     .apply_label_fixup = aa64_apply_label_fixup,
    218     .link = &link_arch_aa64,
    219     .dwarf = &aa64_dwarf_ops,
    220     .dbg = &aa64_dbg_ops,
    221     .asm_ops = &aa64_asm_ops,
    222     .predefined_macros = aa64_predefined_macros,
    223     .npredefined_macros =
    224         (u32)(sizeof aa64_predefined_macros / sizeof aa64_predefined_macros[0]),
    225     .target_features = aa64_target_features,
    226     .ntarget_features =
    227         (u32)(sizeof aa64_target_features / sizeof aa64_target_features[0]),
    228     .target_feature_apply_isa = aa64_target_feature_apply_isa,
    229     .register_name = aa64_register_name,
    230     .register_index = aa64_register_index,
    231     .register_count = aa64_register_iter_size,
    232     .register_at = aa64_register_at_public,
    233     /* AArch64 psABI: return address in x30 (LR). 4-byte aligned insns;
    234      * data-align = -8 for doubleword stack stride. CFA = sp at entry. */
    235     .cfi_return_addr_reg = 30u,
    236     .cfi_code_align_factor = 4,
    237     .cfi_data_align_factor = -8,
    238     .cfi_cfa_init_reg = 31u,
    239     .cfi_cfa_init_offset = 0,
    240     .backend_features = KIT_CG_BACKEND_STRICT_ALIGNMENT,
    241     .atomic_lock_free_max = 8u,
    242     .supports_call_conv = aa64_supports_call_conv,
    243     .supports_intrinsic = aa64_supports_intrinsic,
    244 };