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 };