buildvm_asm.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. ** LuaJIT VM builder: Assembler source code emitter.
  3. ** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h
  4. */
  5. #include "buildvm.h"
  6. #include "lj_bc.h"
  7. /* ------------------------------------------------------------------------ */
  8. #if LJ_TARGET_X86ORX64
  9. /* Emit bytes piecewise as assembler text. */
  10. static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
  11. {
  12. int i;
  13. for (i = 0; i < n; i++) {
  14. if ((i & 15) == 0)
  15. fprintf(ctx->fp, "\t.byte %d", p[i]);
  16. else
  17. fprintf(ctx->fp, ",%d", p[i]);
  18. if ((i & 15) == 15) putc('\n', ctx->fp);
  19. }
  20. if ((n & 15) != 0) putc('\n', ctx->fp);
  21. }
  22. /* Emit relocation */
  23. static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
  24. {
  25. switch (ctx->mode) {
  26. case BUILD_elfasm:
  27. if (type)
  28. fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
  29. else
  30. fprintf(ctx->fp, "\t.long %s\n", sym);
  31. break;
  32. case BUILD_coffasm:
  33. fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
  34. if (type)
  35. fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
  36. else
  37. fprintf(ctx->fp, "\t.long %s\n", sym);
  38. break;
  39. default: /* BUILD_machasm for relative relocations handled below. */
  40. fprintf(ctx->fp, "\t.long %s\n", sym);
  41. break;
  42. }
  43. }
  44. static const char *const jccnames[] = {
  45. "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
  46. "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
  47. };
  48. /* Emit relocation for the incredibly stupid OSX assembler. */
  49. static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n,
  50. const char *sym)
  51. {
  52. const char *opname = NULL;
  53. if (--n < 0) goto err;
  54. if (cp[n] == 0xe8) {
  55. opname = "call";
  56. } else if (cp[n] == 0xe9) {
  57. opname = "jmp";
  58. } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
  59. opname = jccnames[cp[n]-0x80];
  60. n--;
  61. } else {
  62. err:
  63. fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
  64. sym);
  65. exit(1);
  66. }
  67. emit_asm_bytes(ctx, cp, n);
  68. fprintf(ctx->fp, "\t%s %s\n", opname, sym);
  69. }
  70. #else
  71. /* Emit words piecewise as assembler text. */
  72. static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
  73. {
  74. int i;
  75. for (i = 0; i < n; i += 4) {
  76. if ((i & 15) == 0)
  77. fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
  78. else
  79. fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
  80. if ((i & 15) == 12) putc('\n', ctx->fp);
  81. }
  82. if ((n & 15) != 0) putc('\n', ctx->fp);
  83. }
  84. /* Emit relocation as part of an instruction. */
  85. static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
  86. const char *sym)
  87. {
  88. uint32_t ins;
  89. emit_asm_words(ctx, p, n-4);
  90. ins = *(uint32_t *)(p+n-4);
  91. #if LJ_TARGET_ARM
  92. if ((ins & 0xff000000u) == 0xfa000000u) {
  93. fprintf(ctx->fp, "\tblx %s\n", sym);
  94. } else if ((ins & 0x0e000000u) == 0x0a000000u) {
  95. fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
  96. &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
  97. } else {
  98. fprintf(stderr,
  99. "Error: unsupported opcode %08x for %s symbol relocation.\n",
  100. ins, sym);
  101. exit(1);
  102. }
  103. #elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
  104. #if LJ_TARGET_PS3
  105. #define TOCPREFIX "."
  106. #else
  107. #define TOCPREFIX ""
  108. #endif
  109. if ((ins >> 26) == 16) {
  110. fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
  111. (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
  112. } else if ((ins >> 26) == 18) {
  113. fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
  114. } else {
  115. fprintf(stderr,
  116. "Error: unsupported opcode %08x for %s symbol relocation.\n",
  117. ins, sym);
  118. exit(1);
  119. }
  120. #elif LJ_TARGET_MIPS
  121. fprintf(stderr,
  122. "Error: unsupported opcode %08x for %s symbol relocation.\n",
  123. ins, sym);
  124. exit(1);
  125. #else
  126. #error "missing relocation support for this architecture"
  127. #endif
  128. }
  129. #endif
  130. #if LJ_TARGET_ARM
  131. #define ELFASM_PX "%%"
  132. #else
  133. #define ELFASM_PX "@"
  134. #endif
  135. /* Emit an assembler label. */
  136. static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
  137. {
  138. switch (ctx->mode) {
  139. case BUILD_elfasm:
  140. #if LJ_TARGET_PS3
  141. if (!strncmp(name, "lj_vm_", 6) &&
  142. strcmp(name, ctx->beginsym) &&
  143. !strstr(name, "hook")) {
  144. fprintf(ctx->fp,
  145. "\n\t.globl %s\n"
  146. "\t.section \".opd\",\"aw\"\n"
  147. "%s:\n"
  148. "\t.long .%s,.TOC.@tocbase32\n"
  149. "\t.size %s,8\n"
  150. "\t.previous\n"
  151. "\t.globl .%s\n"
  152. "\t.hidden .%s\n"
  153. "\t.type .%s, " ELFASM_PX "function\n"
  154. "\t.size .%s, %d\n"
  155. ".%s:\n",
  156. name, name, name, name, name, name, name, name, size, name);
  157. break;
  158. }
  159. #endif
  160. fprintf(ctx->fp,
  161. "\n\t.globl %s\n"
  162. "\t.hidden %s\n"
  163. "\t.type %s, " ELFASM_PX "%s\n"
  164. "\t.size %s, %d\n"
  165. "%s:\n",
  166. name, name, name, isfunc ? "function" : "object", name, size, name);
  167. break;
  168. case BUILD_coffasm:
  169. fprintf(ctx->fp, "\n\t.globl %s\n", name);
  170. if (isfunc)
  171. fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
  172. fprintf(ctx->fp, "%s:\n", name);
  173. break;
  174. case BUILD_machasm:
  175. fprintf(ctx->fp,
  176. "\n\t.private_extern %s\n"
  177. "%s:\n", name, name);
  178. break;
  179. default:
  180. break;
  181. }
  182. }
  183. /* Emit alignment. */
  184. static void emit_asm_align(BuildCtx *ctx, int bits)
  185. {
  186. switch (ctx->mode) {
  187. case BUILD_elfasm:
  188. case BUILD_coffasm:
  189. fprintf(ctx->fp, "\t.p2align %d\n", bits);
  190. break;
  191. case BUILD_machasm:
  192. fprintf(ctx->fp, "\t.align %d\n", bits);
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. /* ------------------------------------------------------------------------ */
  199. /* Emit assembler source code. */
  200. void emit_asm(BuildCtx *ctx)
  201. {
  202. int i, rel;
  203. fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
  204. fprintf(ctx->fp, "\t.text\n");
  205. emit_asm_align(ctx, 4);
  206. #if LJ_TARGET_PS3
  207. emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
  208. #else
  209. emit_asm_label(ctx, ctx->beginsym, 0, 0);
  210. #endif
  211. if (ctx->mode != BUILD_machasm)
  212. fprintf(ctx->fp, ".Lbegin:\n");
  213. #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
  214. /* This should really be moved into buildvm_arm.dasc. */
  215. fprintf(ctx->fp,
  216. ".fnstart\n"
  217. ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
  218. ".pad #28\n");
  219. #endif
  220. #if LJ_TARGET_MIPS
  221. fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
  222. #endif
  223. for (i = rel = 0; i < ctx->nsym; i++) {
  224. int32_t ofs = ctx->sym[i].ofs;
  225. int32_t next = ctx->sym[i+1].ofs;
  226. #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
  227. if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
  228. fprintf(ctx->fp,
  229. ".globl lj_err_unwind_arm\n"
  230. ".personality lj_err_unwind_arm\n"
  231. ".fnend\n"
  232. ".fnstart\n"
  233. ".save {r4, r5, r11, lr}\n"
  234. ".setfp r11, sp\n");
  235. #endif
  236. emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
  237. while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
  238. BuildReloc *r = &ctx->reloc[rel];
  239. int n = r->ofs - ofs;
  240. #if LJ_TARGET_X86ORX64
  241. if (ctx->mode == BUILD_machasm && r->type != 0) {
  242. emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
  243. } else {
  244. emit_asm_bytes(ctx, ctx->code+ofs, n);
  245. emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
  246. }
  247. ofs += n+4;
  248. #else
  249. emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
  250. ofs += n;
  251. #endif
  252. rel++;
  253. }
  254. #if LJ_TARGET_X86ORX64
  255. emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
  256. #else
  257. emit_asm_words(ctx, ctx->code+ofs, next-ofs);
  258. #endif
  259. }
  260. #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
  261. fprintf(ctx->fp,
  262. #if !LJ_HASFFI
  263. ".globl lj_err_unwind_arm\n"
  264. ".personality lj_err_unwind_arm\n"
  265. #endif
  266. ".fnend\n");
  267. #endif
  268. fprintf(ctx->fp, "\n");
  269. switch (ctx->mode) {
  270. case BUILD_elfasm:
  271. #if !LJ_TARGET_PS3
  272. fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
  273. #endif
  274. #if LJ_TARGET_PPCSPE
  275. /* Soft-float ABI + SPE. */
  276. fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
  277. #elif LJ_TARGET_PPC && !LJ_TARGET_PS3
  278. /* Hard-float ABI. */
  279. fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
  280. #endif
  281. /* fallthrough */
  282. case BUILD_coffasm:
  283. fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
  284. break;
  285. case BUILD_machasm:
  286. fprintf(ctx->fp,
  287. "\t.cstring\n"
  288. "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
  289. break;
  290. default:
  291. break;
  292. }
  293. fprintf(ctx->fp, "\n");
  294. }