src/host/buildvm_peobj.c - luajit-2.0-src

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. ** LuaJIT VM builder: PE object emitter.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. **
  5. ** Only used for building on Windows, since we cannot assume the presence
  6. ** of a suitable assembler. The host and target byte order must match.
  7. */

  8. #include "buildvm.h"
  9. #include "lj_bc.h"

  10. #if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC

  11. /* Context for PE object emitter. */
  12. static char *strtab;
  13. static size_t strtabofs;

  14. /* -- PE object definitions ----------------------------------------------- */

  15. /* PE header. */
  16. typedef struct PEheader {
  17.   uint16_t arch;
  18.   uint16_t nsects;
  19.   uint32_t time;
  20.   uint32_t symtabofs;
  21.   uint32_t nsyms;
  22.   uint16_t opthdrsz;
  23.   uint16_t flags;
  24. } PEheader;

  25. /* PE section. */
  26. typedef struct PEsection {
  27.   char name[8];
  28.   uint32_t vsize;
  29.   uint32_t vaddr;
  30.   uint32_t size;
  31.   uint32_t ofs;
  32.   uint32_t relocofs;
  33.   uint32_t lineofs;
  34.   uint16_t nreloc;
  35.   uint16_t nline;
  36.   uint32_t flags;
  37. } PEsection;

  38. /* PE relocation. */
  39. typedef struct PEreloc {
  40.   uint32_t vaddr;
  41.   uint32_t symidx;
  42.   uint16_t type;
  43. } PEreloc;

  44. /* Cannot use sizeof, because it pads up to the max. alignment. */
  45. #define PEOBJ_RELOC_SIZE        (4+4+2)

  46. /* PE symbol table entry. */
  47. typedef struct PEsym {
  48.   union {
  49.     char name[8];
  50.     uint32_t nameref[2];
  51.   } n;
  52.   uint32_t value;
  53.   int16_t sect;
  54.   uint16_t type;
  55.   uint8_t scl;
  56.   uint8_t naux;
  57. } PEsym;

  58. /* PE symbol table auxiliary entry for a section. */
  59. typedef struct PEsymaux {
  60.   uint32_t size;
  61.   uint16_t nreloc;
  62.   uint16_t nline;
  63.   uint32_t cksum;
  64.   uint16_t assoc;
  65.   uint8_t comdatsel;
  66.   uint8_t unused[3];
  67. } PEsymaux;

  68. /* Cannot use sizeof, because it pads up to the max. alignment. */
  69. #define PEOBJ_SYM_SIZE        (8+4+2+2+1+1)

  70. /* PE object CPU specific defines. */
  71. #if LJ_TARGET_X86
  72. #define PEOBJ_ARCH_TARGET        0x014c
  73. #define PEOBJ_RELOC_REL32        0x14  /* MS: REL32, GNU: DISP32. */
  74. #define PEOBJ_RELOC_DIR32        0x06
  75. #define PEOBJ_RELOC_OFS                0
  76. #define PEOBJ_TEXT_FLAGS        0x60500020  /* 60=r+x, 50=align16, 20=code. */
  77. #elif LJ_TARGET_X64
  78. #define PEOBJ_ARCH_TARGET        0x8664
  79. #define PEOBJ_RELOC_REL32        0x04  /* MS: REL32, GNU: DISP32. */
  80. #define PEOBJ_RELOC_DIR32        0x02
  81. #define PEOBJ_RELOC_ADDR32NB        0x03
  82. #define PEOBJ_RELOC_OFS                0
  83. #define PEOBJ_TEXT_FLAGS        0x60500020  /* 60=r+x, 50=align16, 20=code. */
  84. #elif LJ_TARGET_PPC
  85. #define PEOBJ_ARCH_TARGET        0x01f2
  86. #define PEOBJ_RELOC_REL32        0x06
  87. #define PEOBJ_RELOC_DIR32        0x02
  88. #define PEOBJ_RELOC_OFS                (-4)
  89. #define PEOBJ_TEXT_FLAGS        0x60400020  /* 60=r+x, 40=align8, 20=code. */
  90. #endif

  91. /* Section numbers (0-based). */
  92. enum {
  93.   PEOBJ_SECT_ABS = -2,
  94.   PEOBJ_SECT_UNDEF = -1,
  95.   PEOBJ_SECT_TEXT,
  96. #if LJ_TARGET_X64
  97.   PEOBJ_SECT_PDATA,
  98.   PEOBJ_SECT_XDATA,
  99. #endif
  100.   PEOBJ_SECT_RDATA_Z,
  101.   PEOBJ_NSECTIONS
  102. };

  103. /* Symbol types. */
  104. #define PEOBJ_TYPE_NULL                0
  105. #define PEOBJ_TYPE_FUNC                0x20

  106. /* Symbol storage class. */
  107. #define PEOBJ_SCL_EXTERN        2
  108. #define PEOBJ_SCL_STATIC        3

  109. /* -- PE object emitter --------------------------------------------------- */

  110. /* Emit PE object symbol. */
  111. static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
  112.                            int sect, int type, int scl)
  113. {
  114.   PEsym sym;
  115.   size_t len = strlen(name);
  116.   if (!strtab) {  /* Pass 1: only calculate string table length. */
  117.     if (len > 8) strtabofs += len+1;
  118.     return;
  119.   }
  120.   if (len <= 8) {
  121.     memcpy(sym.n.name, name, len);
  122.     memset(sym.n.name+len, 0, 8-len);
  123.   } else {
  124.     sym.n.nameref[0] = 0;
  125.     sym.n.nameref[1] = (uint32_t)strtabofs;
  126.     memcpy(strtab + strtabofs, name, len);
  127.     strtab[strtabofs+len] = 0;
  128.     strtabofs += len+1;
  129.   }
  130.   sym.value = value;
  131.   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
  132.   sym.type = (uint16_t)type;
  133.   sym.scl = (uint8_t)scl;
  134.   sym.naux = 0;
  135.   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
  136. }

  137. /* Emit PE object section symbol. */
  138. static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
  139. {
  140.   PEsym sym;
  141.   PEsymaux aux;
  142.   if (!strtab) return/* Pass 1: no output. */
  143.   memcpy(sym.n.name, pesect[sect].name, 8);
  144.   sym.value = 0;
  145.   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
  146.   sym.type = PEOBJ_TYPE_NULL;
  147.   sym.scl = PEOBJ_SCL_STATIC;
  148.   sym.naux = 1;
  149.   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
  150.   memset(&aux, 0, sizeof(PEsymaux));
  151.   aux.size = pesect[sect].size;
  152.   aux.nreloc = pesect[sect].nreloc;
  153.   owrite(ctx, &aux, PEOBJ_SYM_SIZE);
  154. }

  155. /* Emit Windows PE object file. */
  156. void emit_peobj(BuildCtx *ctx)
  157. {
  158.   PEheader pehdr;
  159.   PEsection pesect[PEOBJ_NSECTIONS];
  160.   uint32_t sofs;
  161.   int i, nrsym;
  162.   union { uint8_t b; uint32_t u; } host_endian;

  163.   sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);

  164.   /* Fill in PE sections. */
  165.   memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
  166.   memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
  167.   pesect[PEOBJ_SECT_TEXT].ofs = sofs;
  168.   sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
  169.   pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
  170.   sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
  171.   /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
  172.   pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;

  173. #if LJ_TARGET_X64
  174.   memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
  175.   pesect[PEOBJ_SECT_PDATA].ofs = sofs;
  176.   sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
  177.   pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
  178.   sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
  179.   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
  180.   pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;

  181.   memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
  182.   pesect[PEOBJ_SECT_XDATA].ofs = sofs;
  183.   sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2);  /* See below. */
  184.   pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
  185.   sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
  186.   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
  187.   pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
  188. #endif

  189.   memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
  190.   pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
  191.   sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
  192.   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
  193.   pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;

  194.   /* Fill in PE header. */
  195.   pehdr.arch = PEOBJ_ARCH_TARGET;
  196.   pehdr.nsects = PEOBJ_NSECTIONS;
  197.   pehdr.time = 0/* Timestamp is optional. */
  198.   pehdr.symtabofs = sofs;
  199.   pehdr.opthdrsz = 0;
  200.   pehdr.flags = 0;

  201.   /* Compute the size of the symbol table:
  202.   ** @feat.00 + nsections*2
  203.   ** + asm_start + nsym
  204.   ** + nrsym
  205.   */
  206.   nrsym = ctx->nrelocsym;
  207.   pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
  208. #if LJ_TARGET_X64
  209.   pehdr.nsyms += 1/* Symbol for lj_err_unwind_win64. */
  210. #endif

  211.   /* Write PE object header and all sections. */
  212.   owrite(ctx, &pehdr, sizeof(PEheader));
  213.   owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);

  214.   /* Write .text section. */
  215.   host_endian.u = 1;
  216.   if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
  217. #if LJ_TARGET_PPC
  218.     uint32_t *p = (uint32_t *)ctx->code;
  219.     int n = (int)(ctx->codesz >> 2);
  220.     for (i = 0; i < n; i++, p++)
  221.       *p = lj_bswap(*p);  /* Byteswap .text section. */
  222. #else
  223.     fprintf(stderr, "Error: different byte order for host and target\n");
  224.     exit(1);
  225. #endif
  226.   }
  227.   owrite(ctx, ctx->code, ctx->codesz);
  228.   for (i = 0; i < ctx->nreloc; i++) {
  229.     PEreloc reloc;
  230.     reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
  231.     reloc.symidx = 1+2+ctx->reloc[i].sym;  /* Reloc syms are after .text sym. */
  232.     reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
  233.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  234.   }

  235. #if LJ_TARGET_X64
  236.   { /* Write .pdata section. */
  237.     uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
  238.     uint32_t pdata[3];  /* Start of .text, end of .text and .xdata. */
  239.     PEreloc reloc;
  240.     pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
  241.     owrite(ctx, &pdata, sizeof(pdata));
  242.     pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
  243.     owrite(ctx, &pdata, sizeof(pdata));
  244.     reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
  245.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  246.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  247.     reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
  248.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  249.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  250.     reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
  251.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  252.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  253.     reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
  254.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  255.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  256.     reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
  257.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  258.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  259.     reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
  260.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  261.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  262.   }
  263.   { /* Write .xdata section. */
  264.     uint16_t xdata[8+2+6];
  265.     PEreloc reloc;
  266.     xdata[0] = 0x01|0x08|0x10/* Ver. 1, uhandler/ehandler, prolog size 0. */
  267.     xdata[1] = 0x0005/* Number of unwind codes, no frame pointer. */
  268.     xdata[2] = 0x4200/* Stack offset 4*8+8 = aword*5. */
  269.     xdata[3] = 0x3000/* Push rbx. */
  270.     xdata[4] = 0x6000/* Push rsi. */
  271.     xdata[5] = 0x7000/* Push rdi. */
  272.     xdata[6] = 0x5000/* Push rbp. */
  273.     xdata[7] = 0/* Alignment. */
  274.     xdata[8] = xdata[9] = 0/* Relocated address of exception handler. */
  275.     xdata[10] = 0x01/* Ver. 1, no handler, prolog size 0. */
  276.     xdata[11] = 0x1504/* Number of unwind codes, fp = rbp, fpofs = 16. */
  277.     xdata[12] = 0x0300/* set_fpreg. */
  278.     xdata[13] = 0x0200/* stack offset 0*8+8 = aword*1. */
  279.     xdata[14] = 0x3000/* Push rbx. */
  280.     xdata[15] = 0x5000/* Push rbp. */
  281.     owrite(ctx, &xdata, sizeof(xdata));
  282.     reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
  283.     reloc.type = PEOBJ_RELOC_ADDR32NB;
  284.     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
  285.   }
  286. #endif

  287.   /* Write .rdata$Z section. */
  288.   owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);

  289.   /* Write symbol table. */
  290.   strtab = NULL/* 1st pass: collect string sizes. */
  291.   for (;;) {
  292.     strtabofs = 4;
  293.     /* Mark as SafeSEH compliant. */
  294.     emit_peobj_sym(ctx, "@feat.00", 1,
  295.                    PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);

  296.     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
  297.     for (i = 0; i < nrsym; i++)
  298.       emit_peobj_sym(ctx, ctx->relocsym[i], 0,
  299.                      PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);

  300. #if LJ_TARGET_X64
  301.     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
  302.     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
  303.     emit_peobj_sym(ctx, "lj_err_unwind_win64", 0,
  304.                    PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
  305. #endif

  306.     emit_peobj_sym(ctx, ctx->beginsym, 0,
  307.                    PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
  308.     for (i = 0; i < ctx->nsym; i++)
  309.       emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
  310.                      PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);

  311.     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);

  312.     if (strtab)
  313.       break;
  314.     /* 2nd pass: alloc strtab, write syms and copy strings. */
  315.     strtab = (char *)malloc(strtabofs);
  316.     *(uint32_t *)strtab = (uint32_t)strtabofs;
  317.   }

  318.   /* Write string table. */
  319.   owrite(ctx, strtab, strtabofs);
  320. }

  321. #else

  322. void emit_peobj(BuildCtx *ctx)
  323. {
  324.   UNUSED(ctx);
  325.   fprintf(stderr, "Error: no PE object support for this target\n");
  326.   exit(1);
  327. }

  328. #endif