root/host/buildvm_peobj.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. emit_peobj_sym
  2. emit_peobj_sym_sect
  3. emit_peobj
  4. emit_peobj

   1 /*
   2 ** LuaJIT VM builder: PE object emitter.
   3 ** Copyright (C) 2005-2017 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 
   9 #include "buildvm.h"
  10 #include "lj_bc.h"
  11 
  12 #if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC
  13 
  14 /* Context for PE object emitter. */
  15 static char *strtab;
  16 static size_t strtabofs;
  17 
  18 /* -- PE object definitions ----------------------------------------------- */
  19 
  20 /* PE header. */
  21 typedef struct PEheader {
  22   uint16_t arch;
  23   uint16_t nsects;
  24   uint32_t time;
  25   uint32_t symtabofs;
  26   uint32_t nsyms;
  27   uint16_t opthdrsz;
  28   uint16_t flags;
  29 } PEheader;
  30 
  31 /* PE section. */
  32 typedef struct PEsection {
  33   char name[8];
  34   uint32_t vsize;
  35   uint32_t vaddr;
  36   uint32_t size;
  37   uint32_t ofs;
  38   uint32_t relocofs;
  39   uint32_t lineofs;
  40   uint16_t nreloc;
  41   uint16_t nline;
  42   uint32_t flags;
  43 } PEsection;
  44 
  45 /* PE relocation. */
  46 typedef struct PEreloc {
  47   uint32_t vaddr;
  48   uint32_t symidx;
  49   uint16_t type;
  50 } PEreloc;
  51 
  52 /* Cannot use sizeof, because it pads up to the max. alignment. */
  53 #define PEOBJ_RELOC_SIZE        (4+4+2)
  54 
  55 /* PE symbol table entry. */
  56 typedef struct PEsym {
  57   union {
  58     char name[8];
  59     uint32_t nameref[2];
  60   } n;
  61   uint32_t value;
  62   int16_t sect;
  63   uint16_t type;
  64   uint8_t scl;
  65   uint8_t naux;
  66 } PEsym;
  67 
  68 /* PE symbol table auxiliary entry for a section. */
  69 typedef struct PEsymaux {
  70   uint32_t size;
  71   uint16_t nreloc;
  72   uint16_t nline;
  73   uint32_t cksum;
  74   uint16_t assoc;
  75   uint8_t comdatsel;
  76   uint8_t unused[3];
  77 } PEsymaux;
  78 
  79 /* Cannot use sizeof, because it pads up to the max. alignment. */
  80 #define PEOBJ_SYM_SIZE  (8+4+2+2+1+1)
  81 
  82 /* PE object CPU specific defines. */
  83 #if LJ_TARGET_X86
  84 #define PEOBJ_ARCH_TARGET       0x014c
  85 #define PEOBJ_RELOC_REL32       0x14  /* MS: REL32, GNU: DISP32. */
  86 #define PEOBJ_RELOC_DIR32       0x06
  87 #define PEOBJ_RELOC_OFS         0
  88 #define PEOBJ_TEXT_FLAGS        0x60500020  /* 60=r+x, 50=align16, 20=code. */
  89 #elif LJ_TARGET_X64
  90 #define PEOBJ_ARCH_TARGET       0x8664
  91 #define PEOBJ_RELOC_REL32       0x04  /* MS: REL32, GNU: DISP32. */
  92 #define PEOBJ_RELOC_DIR32       0x02
  93 #define PEOBJ_RELOC_ADDR32NB    0x03
  94 #define PEOBJ_RELOC_OFS         0
  95 #define PEOBJ_TEXT_FLAGS        0x60500020  /* 60=r+x, 50=align16, 20=code. */
  96 #elif LJ_TARGET_PPC
  97 #define PEOBJ_ARCH_TARGET       0x01f2
  98 #define PEOBJ_RELOC_REL32       0x06
  99 #define PEOBJ_RELOC_DIR32       0x02
 100 #define PEOBJ_RELOC_OFS         (-4)
 101 #define PEOBJ_TEXT_FLAGS        0x60400020  /* 60=r+x, 40=align8, 20=code. */
 102 #endif
 103 
 104 /* Section numbers (0-based). */
 105 enum {
 106   PEOBJ_SECT_ABS = -2,
 107   PEOBJ_SECT_UNDEF = -1,
 108   PEOBJ_SECT_TEXT,
 109 #if LJ_TARGET_X64
 110   PEOBJ_SECT_PDATA,
 111   PEOBJ_SECT_XDATA,
 112 #endif
 113   PEOBJ_SECT_RDATA_Z,
 114   PEOBJ_NSECTIONS
 115 };
 116 
 117 /* Symbol types. */
 118 #define PEOBJ_TYPE_NULL         0
 119 #define PEOBJ_TYPE_FUNC         0x20
 120 
 121 /* Symbol storage class. */
 122 #define PEOBJ_SCL_EXTERN        2
 123 #define PEOBJ_SCL_STATIC        3
 124 
 125 /* -- PE object emitter --------------------------------------------------- */
 126 
 127 /* Emit PE object symbol. */
 128 static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
 129                            int sect, int type, int scl)
 130 {
 131   PEsym sym;
 132   size_t len = strlen(name);
 133   if (!strtab) {  /* Pass 1: only calculate string table length. */
 134     if (len > 8) strtabofs += len+1;
 135     return;
 136   }
 137   if (len <= 8) {
 138     memcpy(sym.n.name, name, len);
 139     memset(sym.n.name+len, 0, 8-len);
 140   } else {
 141     sym.n.nameref[0] = 0;
 142     sym.n.nameref[1] = (uint32_t)strtabofs;
 143     memcpy(strtab + strtabofs, name, len);
 144     strtab[strtabofs+len] = 0;
 145     strtabofs += len+1;
 146   }
 147   sym.value = value;
 148   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
 149   sym.type = (uint16_t)type;
 150   sym.scl = (uint8_t)scl;
 151   sym.naux = 0;
 152   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
 153 }
 154 
 155 /* Emit PE object section symbol. */
 156 static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
 157 {
 158   PEsym sym;
 159   PEsymaux aux;
 160   if (!strtab) return;  /* Pass 1: no output. */
 161   memcpy(sym.n.name, pesect[sect].name, 8);
 162   sym.value = 0;
 163   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
 164   sym.type = PEOBJ_TYPE_NULL;
 165   sym.scl = PEOBJ_SCL_STATIC;
 166   sym.naux = 1;
 167   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
 168   memset(&aux, 0, sizeof(PEsymaux));
 169   aux.size = pesect[sect].size;
 170   aux.nreloc = pesect[sect].nreloc;
 171   owrite(ctx, &aux, PEOBJ_SYM_SIZE);
 172 }
 173 
 174 /* Emit Windows PE object file. */
 175 void emit_peobj(BuildCtx *ctx)
 176 {
 177   PEheader pehdr;
 178   PEsection pesect[PEOBJ_NSECTIONS];
 179   uint32_t sofs;
 180   int i, nrsym;
 181   union { uint8_t b; uint32_t u; } host_endian;
 182 
 183   sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
 184 
 185   /* Fill in PE sections. */
 186   memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
 187   memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
 188   pesect[PEOBJ_SECT_TEXT].ofs = sofs;
 189   sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
 190   pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
 191   sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
 192   /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
 193   pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
 194 
 195 #if LJ_TARGET_X64
 196   memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
 197   pesect[PEOBJ_SECT_PDATA].ofs = sofs;
 198   sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
 199   pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
 200   sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
 201   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 202   pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
 203 
 204   memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
 205   pesect[PEOBJ_SECT_XDATA].ofs = sofs;
 206   sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2);  /* See below. */
 207   pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
 208   sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
 209   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 210   pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
 211 #endif
 212 
 213   memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
 214   pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
 215   sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
 216   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 217   pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
 218 
 219   /* Fill in PE header. */
 220   pehdr.arch = PEOBJ_ARCH_TARGET;
 221   pehdr.nsects = PEOBJ_NSECTIONS;
 222   pehdr.time = 0;  /* Timestamp is optional. */
 223   pehdr.symtabofs = sofs;
 224   pehdr.opthdrsz = 0;
 225   pehdr.flags = 0;
 226 
 227   /* Compute the size of the symbol table:
 228   ** @feat.00 + nsections*2
 229   ** + asm_start + nsym
 230   ** + nrsym
 231   */
 232   nrsym = ctx->nrelocsym;
 233   pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
 234 #if LJ_TARGET_X64
 235   pehdr.nsyms += 1;  /* Symbol for lj_err_unwind_win64. */
 236 #endif
 237 
 238   /* Write PE object header and all sections. */
 239   owrite(ctx, &pehdr, sizeof(PEheader));
 240   owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
 241 
 242   /* Write .text section. */
 243   host_endian.u = 1;
 244   if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
 245 #if LJ_TARGET_PPC
 246     uint32_t *p = (uint32_t *)ctx->code;
 247     int n = (int)(ctx->codesz >> 2);
 248     for (i = 0; i < n; i++, p++)
 249       *p = lj_bswap(*p);  /* Byteswap .text section. */
 250 #else
 251     fprintf(stderr, "Error: different byte order for host and target\n");
 252     exit(1);
 253 #endif
 254   }
 255   owrite(ctx, ctx->code, ctx->codesz);
 256   for (i = 0; i < ctx->nreloc; i++) {
 257     PEreloc reloc;
 258     reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
 259     reloc.symidx = 1+2+ctx->reloc[i].sym;  /* Reloc syms are after .text sym. */
 260     reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
 261     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 262   }
 263 
 264 #if LJ_TARGET_X64
 265   { /* Write .pdata section. */
 266     uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
 267     uint32_t pdata[3];  /* Start of .text, end of .text and .xdata. */
 268     PEreloc reloc;
 269     pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
 270     owrite(ctx, &pdata, sizeof(pdata));
 271     pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
 272     owrite(ctx, &pdata, sizeof(pdata));
 273     reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
 274     reloc.type = PEOBJ_RELOC_ADDR32NB;
 275     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 276     reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
 277     reloc.type = PEOBJ_RELOC_ADDR32NB;
 278     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 279     reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
 280     reloc.type = PEOBJ_RELOC_ADDR32NB;
 281     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 282     reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
 283     reloc.type = PEOBJ_RELOC_ADDR32NB;
 284     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 285     reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
 286     reloc.type = PEOBJ_RELOC_ADDR32NB;
 287     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 288     reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
 289     reloc.type = PEOBJ_RELOC_ADDR32NB;
 290     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 291   }
 292   { /* Write .xdata section. */
 293     uint16_t xdata[8+2+6];
 294     PEreloc reloc;
 295     xdata[0] = 0x01|0x08|0x10;  /* Ver. 1, uhandler/ehandler, prolog size 0. */
 296     xdata[1] = 0x0005;  /* Number of unwind codes, no frame pointer. */
 297     xdata[2] = 0x4200;  /* Stack offset 4*8+8 = aword*5. */
 298     xdata[3] = 0x3000;  /* Push rbx. */
 299     xdata[4] = 0x6000;  /* Push rsi. */
 300     xdata[5] = 0x7000;  /* Push rdi. */
 301     xdata[6] = 0x5000;  /* Push rbp. */
 302     xdata[7] = 0;  /* Alignment. */
 303     xdata[8] = xdata[9] = 0;  /* Relocated address of exception handler. */
 304     xdata[10] = 0x01;  /* Ver. 1, no handler, prolog size 0. */
 305     xdata[11] = 0x1504;  /* Number of unwind codes, fp = rbp, fpofs = 16. */
 306     xdata[12] = 0x0300;  /* set_fpreg. */
 307     xdata[13] = 0x0200;  /* stack offset 0*8+8 = aword*1. */
 308     xdata[14] = 0x3000;  /* Push rbx. */
 309     xdata[15] = 0x5000;  /* Push rbp. */
 310     owrite(ctx, &xdata, sizeof(xdata));
 311     reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
 312     reloc.type = PEOBJ_RELOC_ADDR32NB;
 313     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 314   }
 315 #endif
 316 
 317   /* Write .rdata$Z section. */
 318   owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
 319 
 320   /* Write symbol table. */
 321   strtab = NULL;  /* 1st pass: collect string sizes. */
 322   for (;;) {
 323     strtabofs = 4;
 324     /* Mark as SafeSEH compliant. */
 325     emit_peobj_sym(ctx, "@feat.00", 1,
 326                    PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
 327 
 328     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
 329     for (i = 0; i < nrsym; i++)
 330       emit_peobj_sym(ctx, ctx->relocsym[i], 0,
 331                      PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 332 
 333 #if LJ_TARGET_X64
 334     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
 335     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
 336     emit_peobj_sym(ctx, "lj_err_unwind_win64", 0,
 337                    PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 338 #endif
 339 
 340     emit_peobj_sym(ctx, ctx->beginsym, 0,
 341                    PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
 342     for (i = 0; i < ctx->nsym; i++)
 343       emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
 344                      PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 345 
 346     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
 347 
 348     if (strtab)
 349       break;
 350     /* 2nd pass: alloc strtab, write syms and copy strings. */
 351     strtab = (char *)malloc(strtabofs);
 352     *(uint32_t *)strtab = (uint32_t)strtabofs;
 353   }
 354 
 355   /* Write string table. */
 356   owrite(ctx, strtab, strtabofs);
 357 }
 358 
 359 #else
 360 
 361 void emit_peobj(BuildCtx *ctx)
 362 {
 363   UNUSED(ctx);
 364   fprintf(stderr, "Error: no PE object support for this target\n");
 365   exit(1);
 366 }
 367 
 368 #endif

/* [<][>][^][v][top][bottom][index][help] */