kit

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

arch.c (9219B)


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