~ubuntu-branches/ubuntu/trusty/luajit/trusty

« back to all changes in this revision

Viewing changes to src/buildvm.c

  • Committer: Package Import Robot
  • Author(s): Enrico Tassi
  • Date: 2012-11-03 14:07:56 UTC
  • mfrom: (1.2.1) (15.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20121103140756-z0zcnyrwqlvuc2m5
Tags: 2.0.0+dfsg-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
** LuaJIT VM builder.
3
 
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4
 
**
5
 
** This is a tool to build the hand-tuned assembler code required for
6
 
** LuaJIT's bytecode interpreter. It supports a variety of output formats
7
 
** to feed different toolchains (see usage() below).
8
 
**
9
 
** This tool is not particularly optimized because it's only used while
10
 
** _building_ LuaJIT. There's no point in distributing or installing it.
11
 
** Only the object code generated by this tool is linked into LuaJIT.
12
 
**
13
 
** Caveat: some memory is not free'd, error handling is lazy.
14
 
** It's a one-shot tool -- any effort fixing this would be wasted.
15
 
*/
16
 
 
17
 
#include "buildvm.h"
18
 
#include "lj_obj.h"
19
 
#include "lj_gc.h"
20
 
#include "lj_bc.h"
21
 
#include "lj_ir.h"
22
 
#include "lj_ircall.h"
23
 
#include "lj_frame.h"
24
 
#include "lj_dispatch.h"
25
 
#if LJ_HASFFI
26
 
#include "lj_ctype.h"
27
 
#include "lj_ccall.h"
28
 
#endif
29
 
#include "luajit.h"
30
 
 
31
 
#if defined(_WIN32)
32
 
#include <fcntl.h>
33
 
#include <io.h>
34
 
#endif
35
 
 
36
 
/* ------------------------------------------------------------------------ */
37
 
 
38
 
/* DynASM glue definitions. */
39
 
#define Dst             ctx
40
 
#define Dst_DECL        BuildCtx *ctx
41
 
#define Dst_REF         (ctx->D)
42
 
#define DASM_CHECKS     1
43
 
 
44
 
#include "../dynasm/dasm_proto.h"
45
 
 
46
 
/* Glue macros for DynASM. */
47
 
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
48
 
 
49
 
#define DASM_EXTERN(ctx, addr, idx, type) \
50
 
  collect_reloc(ctx, addr, idx, type)
51
 
 
52
 
/* ------------------------------------------------------------------------ */
53
 
 
54
 
/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
55
 
#define DASM_ALIGNED_WRITES     1
56
 
 
57
 
/* Embed architecture-specific DynASM encoder and backend. */
58
 
#if LJ_TARGET_X86
59
 
#include "../dynasm/dasm_x86.h"
60
 
#include "buildvm_x86.h"
61
 
#elif LJ_TARGET_X64
62
 
#include "../dynasm/dasm_x86.h"
63
 
#if LJ_ABI_WIN
64
 
#include "buildvm_x64win.h"
65
 
#else
66
 
#include "buildvm_x64.h"
67
 
#endif
68
 
#elif LJ_TARGET_ARM
69
 
#include "../dynasm/dasm_arm.h"
70
 
#include "buildvm_arm.h"
71
 
#elif LJ_TARGET_PPC
72
 
#include "../dynasm/dasm_ppc.h"
73
 
#include "buildvm_ppc.h"
74
 
#elif LJ_TARGET_PPCSPE
75
 
#include "../dynasm/dasm_ppc.h"
76
 
#include "buildvm_ppcspe.h"
77
 
#else
78
 
#error "No support for this architecture (yet)"
79
 
#endif
80
 
 
81
 
/* ------------------------------------------------------------------------ */
82
 
 
83
 
void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
84
 
{
85
 
  if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
86
 
    fprintf(stderr, "Error: cannot write to output file: %s\n",
87
 
            strerror(errno));
88
 
    exit(1);
89
 
  }
90
 
}
91
 
 
92
 
/* ------------------------------------------------------------------------ */
93
 
 
94
 
/* Emit code as raw bytes. Only used for DynASM debugging. */
95
 
static void emit_raw(BuildCtx *ctx)
96
 
{
97
 
  owrite(ctx, ctx->code, ctx->codesz);
98
 
}
99
 
 
100
 
/* -- Build machine code -------------------------------------------------- */
101
 
 
102
 
static const char *sym_decorate(BuildCtx *ctx,
103
 
                                const char *prefix, const char *suffix)
104
 
{
105
 
  char name[256];
106
 
  char *p;
107
 
#if LJ_64
108
 
  const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
109
 
#else
110
 
  const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
111
 
#endif
112
 
  sprintf(name, "%s%s%s", symprefix, prefix, suffix);
113
 
  p = strchr(name, '@');
114
 
  if (p) {
115
 
    if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
116
 
      name[0] = '@';
117
 
    else
118
 
      *p = '\0';
119
 
  }
120
 
  p = (char *)malloc(strlen(name)+1);  /* MSVC doesn't like strdup. */
121
 
  strcpy(p, name);
122
 
  return p;
123
 
}
124
 
 
125
 
#define NRELOCSYM       (sizeof(extnames)/sizeof(extnames[0])-1)
126
 
 
127
 
static int relocmap[NRELOCSYM];
128
 
 
129
 
/* Collect external relocations. */
130
 
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
131
 
{
132
 
  if (ctx->nreloc >= BUILD_MAX_RELOC) {
133
 
    fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
134
 
    exit(1);
135
 
  }
136
 
  if (relocmap[idx] < 0) {
137
 
    relocmap[idx] = ctx->nrelocsym;
138
 
    ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
139
 
    ctx->nrelocsym++;
140
 
  }
141
 
  ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code);
142
 
  ctx->reloc[ctx->nreloc].sym = relocmap[idx];
143
 
  ctx->reloc[ctx->nreloc].type = type;
144
 
  ctx->nreloc++;
145
 
  return 0;  /* Encode symbol offset of 0. */
146
 
}
147
 
 
148
 
/* Naive insertion sort. Performance doesn't matter here. */
149
 
static void sym_insert(BuildCtx *ctx, int32_t ofs,
150
 
                       const char *prefix, const char *suffix)
151
 
{
152
 
  ptrdiff_t i = ctx->nsym++;
153
 
  while (i > 0) {
154
 
    if (ctx->sym[i-1].ofs <= ofs)
155
 
      break;
156
 
    ctx->sym[i] = ctx->sym[i-1];
157
 
    i--;
158
 
  }
159
 
  ctx->sym[i].ofs = ofs;
160
 
  ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
161
 
}
162
 
 
163
 
/* Build the machine code. */
164
 
static int build_code(BuildCtx *ctx)
165
 
{
166
 
  int status;
167
 
  int i;
168
 
 
169
 
  /* Initialize DynASM structures. */
170
 
  ctx->nglob = GLOB__MAX;
171
 
  ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *));
172
 
  memset(ctx->glob, 0, ctx->nglob*sizeof(void *));
173
 
  ctx->nreloc = 0;
174
 
 
175
 
  ctx->globnames = globnames;
176
 
  ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
177
 
  ctx->nrelocsym = 0;
178
 
  for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
179
 
 
180
 
  ctx->dasm_ident = DASM_IDENT;
181
 
  ctx->dasm_arch = DASM_ARCH;
182
 
 
183
 
  dasm_init(Dst, DASM_MAXSECTION);
184
 
  dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
185
 
  dasm_setup(Dst, build_actionlist);
186
 
 
187
 
  /* Call arch-specific backend to emit the code. */
188
 
  ctx->npc = build_backend(ctx);
189
 
 
190
 
  /* Finalize the code. */
191
 
  (void)dasm_checkstep(Dst, -1);
192
 
  if ((status = dasm_link(Dst, &ctx->codesz))) return status;
193
 
  ctx->code = (uint8_t *)malloc(ctx->codesz);
194
 
  if ((status = dasm_encode(Dst, (void *)ctx->code))) return status;
195
 
 
196
 
  /* Allocate symbol table and bytecode offsets. */
197
 
  ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin");
198
 
  ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym));
199
 
  ctx->nsym = 0;
200
 
  ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
201
 
 
202
 
  /* Collect the opcodes (PC labels). */
203
 
  for (i = 0; i < ctx->npc; i++) {
204
 
    int32_t ofs = dasm_getpclabel(Dst, i);
205
 
    if (ofs < 0) return 0x22000000|i;
206
 
    ctx->bc_ofs[i] = ofs;
207
 
    if ((LJ_HASJIT ||
208
 
         !(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP ||
209
 
           i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) &&
210
 
        (LJ_HASFFI || i != BC_KCDATA))
211
 
      sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]);
212
 
  }
213
 
 
214
 
  /* Collect the globals (named labels). */
215
 
  for (i = 0; i < ctx->nglob; i++) {
216
 
    const char *gl = globnames[i];
217
 
    int len = (int)strlen(gl);
218
 
    if (!ctx->glob[i]) {
219
 
      fprintf(stderr, "Error: undefined global %s\n", gl);
220
 
      exit(2);
221
 
    }
222
 
    /* Skip the _Z symbols. */
223
 
    if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z'))
224
 
      sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code),
225
 
                 LABEL_PREFIX, globnames[i]);
226
 
  }
227
 
 
228
 
  /* Close the address range. */
229
 
  sym_insert(ctx, (int32_t)ctx->codesz, "", "");
230
 
  ctx->nsym--;
231
 
 
232
 
  dasm_free(Dst);
233
 
 
234
 
  return 0;
235
 
}
236
 
 
237
 
/* -- Generate VM enums --------------------------------------------------- */
238
 
 
239
 
const char *const bc_names[] = {
240
 
#define BCNAME(name, ma, mb, mc, mt)       #name,
241
 
BCDEF(BCNAME)
242
 
#undef BCNAME
243
 
  NULL
244
 
};
245
 
 
246
 
const char *const ir_names[] = {
247
 
#define IRNAME(name, m, m1, m2) #name,
248
 
IRDEF(IRNAME)
249
 
#undef IRNAME
250
 
  NULL
251
 
};
252
 
 
253
 
const char *const irt_names[] = {
254
 
#define IRTNAME(name)   #name,
255
 
IRTDEF(IRTNAME)
256
 
#undef IRTNAME
257
 
  NULL
258
 
};
259
 
 
260
 
const char *const irfpm_names[] = {
261
 
#define FPMNAME(name)           #name,
262
 
IRFPMDEF(FPMNAME)
263
 
#undef FPMNAME
264
 
  NULL
265
 
};
266
 
 
267
 
const char *const irfield_names[] = {
268
 
#define FLNAME(name, ofs)       #name,
269
 
IRFLDEF(FLNAME)
270
 
#undef FLNAME
271
 
  NULL
272
 
};
273
 
 
274
 
const char *const ircall_names[] = {
275
 
#define IRCALLNAME(cond, name, nargs, kind, type, flags)        #name,
276
 
IRCALLDEF(IRCALLNAME)
277
 
#undef IRCALLNAME
278
 
  NULL
279
 
};
280
 
 
281
 
static const char *const trace_errors[] = {
282
 
#define TREDEF(name, msg)       msg,
283
 
#include "lj_traceerr.h"
284
 
  NULL
285
 
};
286
 
 
287
 
static const char *lower(char *buf, const char *s)
288
 
{
289
 
  char *p = buf;
290
 
  while (*s) {
291
 
    *p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
292
 
    s++;
293
 
  }
294
 
  *p = '\0';
295
 
  return buf;
296
 
}
297
 
 
298
 
/* Emit C source code for bytecode-related definitions. */
299
 
static void emit_bcdef(BuildCtx *ctx)
300
 
{
301
 
  int i;
302
 
  fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
303
 
  fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
304
 
  for (i = 0; i < ctx->npc; i++) {
305
 
    if (i != 0)
306
 
      fprintf(ctx->fp, ",\n");
307
 
    fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
308
 
  }
309
 
}
310
 
 
311
 
/* Emit VM definitions as Lua code for debug modules. */
312
 
static void emit_vmdef(BuildCtx *ctx)
313
 
{
314
 
  char buf[80];
315
 
  int i;
316
 
  fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
317
 
  fprintf(ctx->fp, "module(...)\n\n");
318
 
 
319
 
  fprintf(ctx->fp, "bcnames = \"");
320
 
  for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
321
 
  fprintf(ctx->fp, "\"\n\n");
322
 
 
323
 
  fprintf(ctx->fp, "irnames = \"");
324
 
  for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
325
 
  fprintf(ctx->fp, "\"\n\n");
326
 
 
327
 
  fprintf(ctx->fp, "irfpm = { [0]=");
328
 
  for (i = 0; irfpm_names[i]; i++)
329
 
    fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
330
 
  fprintf(ctx->fp, "}\n\n");
331
 
 
332
 
  fprintf(ctx->fp, "irfield = { [0]=");
333
 
  for (i = 0; irfield_names[i]; i++) {
334
 
    char *p;
335
 
    lower(buf, irfield_names[i]);
336
 
    p = strchr(buf, '_');
337
 
    if (p) *p = '.';
338
 
    fprintf(ctx->fp, "\"%s\", ", buf);
339
 
  }
340
 
  fprintf(ctx->fp, "}\n\n");
341
 
 
342
 
  fprintf(ctx->fp, "ircall = {\n[0]=");
343
 
  for (i = 0; ircall_names[i]; i++)
344
 
    fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
345
 
  fprintf(ctx->fp, "}\n\n");
346
 
 
347
 
  fprintf(ctx->fp, "traceerr = {\n[0]=");
348
 
  for (i = 0; trace_errors[i]; i++)
349
 
    fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
350
 
  fprintf(ctx->fp, "}\n\n");
351
 
}
352
 
 
353
 
/* -- Argument parsing ---------------------------------------------------- */
354
 
 
355
 
/* Build mode names. */
356
 
static const char *const modenames[] = {
357
 
#define BUILDNAME(name)         #name,
358
 
BUILDDEF(BUILDNAME)
359
 
#undef BUILDNAME
360
 
  NULL
361
 
};
362
 
 
363
 
/* Print usage information and exit. */
364
 
static void usage(void)
365
 
{
366
 
  int i;
367
 
  fprintf(stderr, LUAJIT_VERSION " VM builder.\n");
368
 
  fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n");
369
 
  fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n");
370
 
  fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
371
 
  fprintf(stderr, "Available modes:\n");
372
 
  for (i = 0; i < BUILD__MAX; i++)
373
 
    fprintf(stderr, "  %s\n", modenames[i]);
374
 
  exit(1);
375
 
}
376
 
 
377
 
/* Parse the output mode name. */
378
 
static BuildMode parsemode(const char *mode)
379
 
{
380
 
  int i;
381
 
  for (i = 0; modenames[i]; i++)
382
 
    if (!strcmp(mode, modenames[i]))
383
 
      return (BuildMode)i;
384
 
  usage();
385
 
  return (BuildMode)-1;
386
 
}
387
 
 
388
 
/* Parse arguments. */
389
 
static void parseargs(BuildCtx *ctx, char **argv)
390
 
{
391
 
  const char *a;
392
 
  int i;
393
 
  ctx->mode = (BuildMode)-1;
394
 
  ctx->outname = "-";
395
 
  for (i = 1; (a = argv[i]) != NULL; i++) {
396
 
    if (a[0] != '-')
397
 
      break;
398
 
    switch (a[1]) {
399
 
    case '-':
400
 
      if (a[2]) goto err;
401
 
      i++;
402
 
      goto ok;
403
 
    case '\0':
404
 
      goto ok;
405
 
    case 'm':
406
 
      i++;
407
 
      if (a[2] || argv[i] == NULL) goto err;
408
 
      ctx->mode = parsemode(argv[i]);
409
 
      break;
410
 
    case 'o':
411
 
      i++;
412
 
      if (a[2] || argv[i] == NULL) goto err;
413
 
      ctx->outname = argv[i];
414
 
      break;
415
 
    default: err:
416
 
      usage();
417
 
      break;
418
 
    }
419
 
  }
420
 
ok:
421
 
  ctx->args = argv+i;
422
 
  if (ctx->mode == (BuildMode)-1) goto err;
423
 
}
424
 
 
425
 
int main(int argc, char **argv)
426
 
{
427
 
  BuildCtx ctx_;
428
 
  BuildCtx *ctx = &ctx_;
429
 
  int status, binmode;
430
 
 
431
 
  if (sizeof(void *) != 4*LJ_32+8*LJ_64) {
432
 
    fprintf(stderr,"Error: pointer size mismatch in cross-build.\n");
433
 
    fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=... TARGET=...\n\n");
434
 
    return 1;
435
 
  }
436
 
 
437
 
  UNUSED(argc);
438
 
  parseargs(ctx, argv);
439
 
 
440
 
  if ((status = build_code(ctx))) {
441
 
    fprintf(stderr,"Error: DASM error %08x\n", status);
442
 
    return 1;
443
 
  }
444
 
 
445
 
  switch (ctx->mode) {
446
 
  case BUILD_peobj:
447
 
  case BUILD_raw:
448
 
    binmode = 1;
449
 
    break;
450
 
  default:
451
 
    binmode = 0;
452
 
    break;
453
 
  }
454
 
 
455
 
  if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
456
 
    ctx->fp = stdout;
457
 
#if defined(_WIN32)
458
 
    if (binmode)
459
 
      _setmode(_fileno(stdout), _O_BINARY);  /* Yuck. */
460
 
#endif
461
 
  } else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) {
462
 
    fprintf(stderr, "Error: cannot open output file '%s': %s\n",
463
 
            ctx->outname, strerror(errno));
464
 
    exit(1);
465
 
  }
466
 
 
467
 
  switch (ctx->mode) {
468
 
  case BUILD_elfasm:
469
 
  case BUILD_coffasm:
470
 
  case BUILD_machasm:
471
 
    emit_asm(ctx);
472
 
    emit_asm_debug(ctx);
473
 
    break;
474
 
  case BUILD_peobj:
475
 
    emit_peobj(ctx);
476
 
    break;
477
 
  case BUILD_raw:
478
 
    emit_raw(ctx);
479
 
    break;
480
 
  case BUILD_bcdef:
481
 
    emit_bcdef(ctx);
482
 
    emit_lib(ctx);
483
 
    break;
484
 
  case BUILD_vmdef:
485
 
    emit_vmdef(ctx);
486
 
    emit_lib(ctx);
487
 
    break;
488
 
  case BUILD_ffdef:
489
 
  case BUILD_libdef:
490
 
  case BUILD_recdef:
491
 
    emit_lib(ctx);
492
 
    break;
493
 
  case BUILD_folddef:
494
 
    emit_fold(ctx);
495
 
    break;
496
 
  default:
497
 
    break;
498
 
  }
499
 
 
500
 
  fflush(ctx->fp);
501
 
  if (ferror(ctx->fp)) {
502
 
    fprintf(stderr, "Error: cannot write to output file: %s\n",
503
 
            strerror(errno));
504
 
    exit(1);
505
 
  }
506
 
  fclose(ctx->fp);
507
 
 
508
 
  return 0;
509
 
}
510