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