Mercurial
comparison third_party/luajit/src/host/buildvm_asm.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 /* | |
| 2 ** LuaJIT VM builder: Assembler source code emitter. | |
| 3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h | |
| 4 */ | |
| 5 | |
| 6 #include "buildvm.h" | |
| 7 #include "lj_bc.h" | |
| 8 | |
| 9 /* ------------------------------------------------------------------------ */ | |
| 10 | |
| 11 #if LJ_TARGET_X86ORX64 | |
| 12 /* Emit bytes piecewise as assembler text. */ | |
| 13 static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n) | |
| 14 { | |
| 15 int i; | |
| 16 for (i = 0; i < n; i++) { | |
| 17 if ((i & 15) == 0) | |
| 18 fprintf(ctx->fp, "\t.byte %d", p[i]); | |
| 19 else | |
| 20 fprintf(ctx->fp, ",%d", p[i]); | |
| 21 if ((i & 15) == 15) putc('\n', ctx->fp); | |
| 22 } | |
| 23 if ((n & 15) != 0) putc('\n', ctx->fp); | |
| 24 } | |
| 25 | |
| 26 /* Emit relocation */ | |
| 27 static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym) | |
| 28 { | |
| 29 switch (ctx->mode) { | |
| 30 case BUILD_elfasm: | |
| 31 if (type) | |
| 32 fprintf(ctx->fp, "\t.long %s-.-4\n", sym); | |
| 33 else | |
| 34 fprintf(ctx->fp, "\t.long %s\n", sym); | |
| 35 break; | |
| 36 case BUILD_coffasm: | |
| 37 fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym); | |
| 38 if (type) | |
| 39 fprintf(ctx->fp, "\t.long %s-.-4\n", sym); | |
| 40 else | |
| 41 fprintf(ctx->fp, "\t.long %s\n", sym); | |
| 42 break; | |
| 43 default: /* BUILD_machasm for relative relocations handled below. */ | |
| 44 fprintf(ctx->fp, "\t.long %s\n", sym); | |
| 45 break; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 static const char *const jccnames[] = { | |
| 50 "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja", | |
| 51 "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg" | |
| 52 }; | |
| 53 | |
| 54 /* Emit x86/x64 text relocations. */ | |
| 55 static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n, | |
| 56 const char *sym) | |
| 57 { | |
| 58 const char *opname = NULL; | |
| 59 if (--n < 0) goto err; | |
| 60 if (cp[n] == 0xe8) { | |
| 61 opname = "call"; | |
| 62 } else if (cp[n] == 0xe9) { | |
| 63 opname = "jmp"; | |
| 64 } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) { | |
| 65 opname = jccnames[cp[n]-0x80]; | |
| 66 n--; | |
| 67 } else { | |
| 68 err: | |
| 69 fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n", | |
| 70 sym); | |
| 71 exit(1); | |
| 72 } | |
| 73 emit_asm_bytes(ctx, cp, n); | |
| 74 if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) { | |
| 75 /* Various fixups for external symbols outside of our binary. */ | |
| 76 if (ctx->mode == BUILD_elfasm) { | |
| 77 if (LJ_32) | |
| 78 fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym); | |
| 79 fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym); | |
| 80 if (LJ_32) | |
| 81 fprintf(ctx->fp, "#endif\n"); | |
| 82 return; | |
| 83 } else if (LJ_32 && ctx->mode == BUILD_machasm) { | |
| 84 fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym); | |
| 85 return; | |
| 86 } | |
| 87 } | |
| 88 fprintf(ctx->fp, "\t%s %s\n", opname, sym); | |
| 89 } | |
| 90 #else | |
| 91 /* Emit words piecewise as assembler text. */ | |
| 92 static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n) | |
| 93 { | |
| 94 int i; | |
| 95 for (i = 0; i < n; i += 4) { | |
| 96 uint32_t ins = *(uint32_t *)(p+i); | |
| 97 #if LJ_TARGET_ARM64 && LJ_BE | |
| 98 ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */ | |
| 99 #endif | |
| 100 if ((i & 15) == 0) | |
| 101 fprintf(ctx->fp, "\t.long 0x%08x", ins); | |
| 102 else | |
| 103 fprintf(ctx->fp, ",0x%08x", ins); | |
| 104 if ((i & 15) == 12) putc('\n', ctx->fp); | |
| 105 } | |
| 106 if ((n & 15) != 0) putc('\n', ctx->fp); | |
| 107 } | |
| 108 | |
| 109 /* Emit relocation as part of an instruction. */ | |
| 110 static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n, | |
| 111 const char *sym) | |
| 112 { | |
| 113 uint32_t ins; | |
| 114 emit_asm_words(ctx, p, n-4); | |
| 115 ins = *(uint32_t *)(p+n-4); | |
| 116 #if LJ_TARGET_ARM | |
| 117 if ((ins & 0xff000000u) == 0xfa000000u) { | |
| 118 fprintf(ctx->fp, "\tblx %s\n", sym); | |
| 119 } else if ((ins & 0x0e000000u) == 0x0a000000u) { | |
| 120 fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b", | |
| 121 &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym); | |
| 122 } else { | |
| 123 fprintf(stderr, | |
| 124 "Error: unsupported opcode %08x for %s symbol relocation.\n", | |
| 125 ins, sym); | |
| 126 exit(1); | |
| 127 } | |
| 128 #elif LJ_TARGET_ARM64 | |
| 129 if ((ins >> 26) == 0x25u) { | |
| 130 fprintf(ctx->fp, "\tbl %s\n", sym); | |
| 131 } else { | |
| 132 fprintf(stderr, | |
| 133 "Error: unsupported opcode %08x for %s symbol relocation.\n", | |
| 134 ins, sym); | |
| 135 exit(1); | |
| 136 } | |
| 137 #elif LJ_TARGET_PPC | |
| 138 #if LJ_TARGET_PS3 | |
| 139 #define TOCPREFIX "." | |
| 140 #else | |
| 141 #define TOCPREFIX "" | |
| 142 #endif | |
| 143 if ((ins >> 26) == 16) { | |
| 144 fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n", | |
| 145 (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym); | |
| 146 } else if ((ins >> 26) == 18) { | |
| 147 fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym); | |
| 148 } else { | |
| 149 fprintf(stderr, | |
| 150 "Error: unsupported opcode %08x for %s symbol relocation.\n", | |
| 151 ins, sym); | |
| 152 exit(1); | |
| 153 } | |
| 154 #elif LJ_TARGET_MIPS | |
| 155 fprintf(stderr, | |
| 156 "Error: unsupported opcode %08x for %s symbol relocation.\n", | |
| 157 ins, sym); | |
| 158 exit(1); | |
| 159 #else | |
| 160 #error "missing relocation support for this architecture" | |
| 161 #endif | |
| 162 } | |
| 163 #endif | |
| 164 | |
| 165 #if LJ_TARGET_ARM | |
| 166 #define ELFASM_PX "%%" | |
| 167 #else | |
| 168 #define ELFASM_PX "@" | |
| 169 #endif | |
| 170 | |
| 171 /* Emit an assembler label. */ | |
| 172 static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc) | |
| 173 { | |
| 174 switch (ctx->mode) { | |
| 175 case BUILD_elfasm: | |
| 176 #if LJ_TARGET_PS3 | |
| 177 if (!strncmp(name, "lj_vm_", 6) && | |
| 178 strcmp(name, ctx->beginsym) && | |
| 179 !strstr(name, "hook")) { | |
| 180 fprintf(ctx->fp, | |
| 181 "\n\t.globl %s\n" | |
| 182 "\t.section \".opd\",\"aw\"\n" | |
| 183 "%s:\n" | |
| 184 "\t.long .%s,.TOC.@tocbase32\n" | |
| 185 "\t.size %s,8\n" | |
| 186 "\t.previous\n" | |
| 187 "\t.globl .%s\n" | |
| 188 "\t.hidden .%s\n" | |
| 189 "\t.type .%s, " ELFASM_PX "function\n" | |
| 190 "\t.size .%s, %d\n" | |
| 191 ".%s:\n", | |
| 192 name, name, name, name, name, name, name, name, size, name); | |
| 193 break; | |
| 194 } | |
| 195 #endif | |
| 196 fprintf(ctx->fp, | |
| 197 "\n\t.globl %s\n" | |
| 198 "\t.hidden %s\n" | |
| 199 "\t.type %s, " ELFASM_PX "%s\n" | |
| 200 "\t.size %s, %d\n" | |
| 201 "%s:\n", | |
| 202 name, name, name, isfunc ? "function" : "object", name, size, name); | |
| 203 break; | |
| 204 case BUILD_coffasm: | |
| 205 fprintf(ctx->fp, "\n\t.globl %s\n", name); | |
| 206 if (isfunc) | |
| 207 fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name); | |
| 208 fprintf(ctx->fp, "%s:\n", name); | |
| 209 break; | |
| 210 case BUILD_machasm: | |
| 211 fprintf(ctx->fp, | |
| 212 "\n\t.private_extern %s\n" | |
| 213 "\t.no_dead_strip %s\n" | |
| 214 "%s:\n", name, name, name); | |
| 215 break; | |
| 216 default: | |
| 217 break; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 /* Emit alignment. */ | |
| 222 static void emit_asm_align(BuildCtx *ctx, int bits) | |
| 223 { | |
| 224 switch (ctx->mode) { | |
| 225 case BUILD_elfasm: | |
| 226 case BUILD_coffasm: | |
| 227 fprintf(ctx->fp, "\t.p2align %d\n", bits); | |
| 228 break; | |
| 229 case BUILD_machasm: | |
| 230 fprintf(ctx->fp, "\t.align %d\n", bits); | |
| 231 break; | |
| 232 default: | |
| 233 break; | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 /* ------------------------------------------------------------------------ */ | |
| 238 | |
| 239 /* Emit assembler source code. */ | |
| 240 void emit_asm(BuildCtx *ctx) | |
| 241 { | |
| 242 int i, rel; | |
| 243 | |
| 244 fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch); | |
| 245 fprintf(ctx->fp, "\t.text\n"); | |
| 246 #if LJ_TARGET_MIPS32 && !LJ_ABI_SOFTFP | |
| 247 fprintf(ctx->fp, "\t.module fp=32\n"); | |
| 248 #endif | |
| 249 #if LJ_TARGET_MIPS | |
| 250 fprintf(ctx->fp, "\t.set nomips16\n\t.abicalls\n\t.set noreorder\n\t.set nomacro\n"); | |
| 251 #endif | |
| 252 emit_asm_align(ctx, 4); | |
| 253 | |
| 254 #if LJ_TARGET_PS3 | |
| 255 emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0); | |
| 256 #else | |
| 257 emit_asm_label(ctx, ctx->beginsym, 0, 0); | |
| 258 #endif | |
| 259 if (ctx->mode != BUILD_machasm) | |
| 260 fprintf(ctx->fp, ".Lbegin:\n"); | |
| 261 | |
| 262 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND | |
| 263 /* This should really be moved into buildvm_arm.dasc. */ | |
| 264 #if LJ_ARCH_HASFPU | |
| 265 fprintf(ctx->fp, | |
| 266 ".fnstart\n" | |
| 267 ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n" | |
| 268 ".vsave {d8-d15}\n" | |
| 269 ".save {r4}\n" | |
| 270 ".pad #28\n"); | |
| 271 #else | |
| 272 fprintf(ctx->fp, | |
| 273 ".fnstart\n" | |
| 274 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" | |
| 275 ".pad #28\n"); | |
| 276 #endif | |
| 277 #endif | |
| 278 | |
| 279 for (i = rel = 0; i < ctx->nsym; i++) { | |
| 280 int32_t ofs = ctx->sym[i].ofs; | |
| 281 int32_t next = ctx->sym[i+1].ofs; | |
| 282 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI | |
| 283 if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call")) | |
| 284 fprintf(ctx->fp, | |
| 285 ".globl lj_err_unwind_arm\n" | |
| 286 ".personality lj_err_unwind_arm\n" | |
| 287 ".fnend\n" | |
| 288 ".fnstart\n" | |
| 289 ".save {r4, r5, r11, lr}\n" | |
| 290 ".setfp r11, sp\n"); | |
| 291 #endif | |
| 292 emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1); | |
| 293 while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) { | |
| 294 BuildReloc *r = &ctx->reloc[rel]; | |
| 295 int n = r->ofs - ofs; | |
| 296 #if LJ_TARGET_X86ORX64 | |
| 297 if (r->type != 0 && | |
| 298 (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) { | |
| 299 emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); | |
| 300 } else { | |
| 301 emit_asm_bytes(ctx, ctx->code+ofs, n); | |
| 302 emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]); | |
| 303 } | |
| 304 ofs += n+4; | |
| 305 #else | |
| 306 emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]); | |
| 307 ofs += n; | |
| 308 #endif | |
| 309 rel++; | |
| 310 } | |
| 311 #if LJ_TARGET_X86ORX64 | |
| 312 emit_asm_bytes(ctx, ctx->code+ofs, next-ofs); | |
| 313 #else | |
| 314 emit_asm_words(ctx, ctx->code+ofs, next-ofs); | |
| 315 #endif | |
| 316 } | |
| 317 | |
| 318 #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND | |
| 319 fprintf(ctx->fp, | |
| 320 #if !LJ_HASFFI | |
| 321 ".globl lj_err_unwind_arm\n" | |
| 322 ".personality lj_err_unwind_arm\n" | |
| 323 #endif | |
| 324 ".fnend\n"); | |
| 325 #endif | |
| 326 | |
| 327 fprintf(ctx->fp, "\n"); | |
| 328 switch (ctx->mode) { | |
| 329 case BUILD_elfasm: | |
| 330 #if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA) | |
| 331 fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n"); | |
| 332 #endif | |
| 333 #if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP | |
| 334 /* Hard-float ABI. */ | |
| 335 fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n"); | |
| 336 #endif | |
| 337 /* fallthrough */ | |
| 338 case BUILD_coffasm: | |
| 339 fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident); | |
| 340 break; | |
| 341 case BUILD_machasm: | |
| 342 fprintf(ctx->fp, | |
| 343 "\t.cstring\n" | |
| 344 "\t.ascii \"%s\\0\"\n", ctx->dasm_ident); | |
| 345 break; | |
| 346 default: | |
| 347 break; | |
| 348 } | |
| 349 fprintf(ctx->fp, "\n"); | |
| 350 } | |
| 351 |