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 #elif LJ_TARGET_X86
 113   PEOBJ_SECT_SXDATA,
 114 #endif
 115   PEOBJ_SECT_RDATA_Z,
 116   PEOBJ_NSECTIONS
 117 };
 118 
 119 /* Symbol types. */
 120 #define PEOBJ_TYPE_NULL         0
 121 #define PEOBJ_TYPE_FUNC         0x20
 122 
 123 /* Symbol storage class. */
 124 #define PEOBJ_SCL_EXTERN        2
 125 #define PEOBJ_SCL_STATIC        3
 126 
 127 /* -- PE object emitter --------------------------------------------------- */
 128 
 129 /* Emit PE object symbol. */
 130 static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
 131                            int sect, int type, int scl)
 132 {
 133   PEsym sym;
 134   size_t len = strlen(name);
 135   if (!strtab) {  /* Pass 1: only calculate string table length. */
 136     if (len > 8) strtabofs += len+1;
 137     return;
 138   }
 139   if (len <= 8) {
 140     memcpy(sym.n.name, name, len);
 141     memset(sym.n.name+len, 0, 8-len);
 142   } else {
 143     sym.n.nameref[0] = 0;
 144     sym.n.nameref[1] = (uint32_t)strtabofs;
 145     memcpy(strtab + strtabofs, name, len);
 146     strtab[strtabofs+len] = 0;
 147     strtabofs += len+1;
 148   }
 149   sym.value = value;
 150   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
 151   sym.type = (uint16_t)type;
 152   sym.scl = (uint8_t)scl;
 153   sym.naux = 0;
 154   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
 155 }
 156 
 157 /* Emit PE object section symbol. */
 158 static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
 159 {
 160   PEsym sym;
 161   PEsymaux aux;
 162   if (!strtab) return;  /* Pass 1: no output. */
 163   memcpy(sym.n.name, pesect[sect].name, 8);
 164   sym.value = 0;
 165   sym.sect = (int16_t)(sect+1);  /* 1-based section number. */
 166   sym.type = PEOBJ_TYPE_NULL;
 167   sym.scl = PEOBJ_SCL_STATIC;
 168   sym.naux = 1;
 169   owrite(ctx, &sym, PEOBJ_SYM_SIZE);
 170   memset(&aux, 0, sizeof(PEsymaux));
 171   aux.size = pesect[sect].size;
 172   aux.nreloc = pesect[sect].nreloc;
 173   owrite(ctx, &aux, PEOBJ_SYM_SIZE);
 174 }
 175 
 176 /* Emit Windows PE object file. */
 177 void emit_peobj(BuildCtx *ctx)
 178 {
 179   PEheader pehdr;
 180   PEsection pesect[PEOBJ_NSECTIONS];
 181   uint32_t sofs;
 182   int i, nrsym;
 183   union { uint8_t b; uint32_t u; } host_endian;
 184 
 185   sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
 186 
 187   /* Fill in PE sections. */
 188   memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
 189   memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
 190   pesect[PEOBJ_SECT_TEXT].ofs = sofs;
 191   sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
 192   pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
 193   sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
 194   /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
 195   pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
 196 
 197 #if LJ_TARGET_X64
 198   memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
 199   pesect[PEOBJ_SECT_PDATA].ofs = sofs;
 200   sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
 201   pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
 202   sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
 203   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 204   pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
 205 
 206   memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
 207   pesect[PEOBJ_SECT_XDATA].ofs = sofs;
 208   sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2);  /* See below. */
 209   pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
 210   sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
 211   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 212   pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
 213 #elif LJ_TARGET_X86
 214   memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1);
 215   pesect[PEOBJ_SECT_SXDATA].ofs = sofs;
 216   sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4);
 217   pesect[PEOBJ_SECT_SXDATA].relocofs = sofs;
 218   /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */
 219   pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240;
 220 #endif
 221 
 222   memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
 223   pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
 224   sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
 225   /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
 226   pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
 227 
 228   /* Fill in PE header. */
 229   pehdr.arch = PEOBJ_ARCH_TARGET;
 230   pehdr.nsects = PEOBJ_NSECTIONS;
 231   pehdr.time = 0;  /* Timestamp is optional. */
 232   pehdr.symtabofs = sofs;
 233   pehdr.opthdrsz = 0;
 234   pehdr.flags = 0;
 235 
 236   /* Compute the size of the symbol table:
 237   ** @feat.00 + nsections*2
 238   ** + asm_start + nsym
 239   ** + nrsym
 240   */
 241   nrsym = ctx->nrelocsym;
 242   pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
 243 #if LJ_TARGET_X64
 244   pehdr.nsyms += 1;  /* Symbol for lj_err_unwind_win. */
 245 #endif
 246 
 247   /* Write PE object header and all sections. */
 248   owrite(ctx, &pehdr, sizeof(PEheader));
 249   owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
 250 
 251   /* Write .text section. */
 252   host_endian.u = 1;
 253   if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
 254 #if LJ_TARGET_PPC
 255     uint32_t *p = (uint32_t *)ctx->code;
 256     int n = (int)(ctx->codesz >> 2);
 257     for (i = 0; i < n; i++, p++)
 258       *p = lj_bswap(*p);  /* Byteswap .text section. */
 259 #else
 260     fprintf(stderr, "Error: different byte order for host and target\n");
 261     exit(1);
 262 #endif
 263   }
 264   owrite(ctx, ctx->code, ctx->codesz);
 265   for (i = 0; i < ctx->nreloc; i++) {
 266     PEreloc reloc;
 267     reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
 268     reloc.symidx = 1+2+ctx->reloc[i].sym;  /* Reloc syms are after .text sym. */
 269     reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
 270     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 271   }
 272 
 273 #if LJ_TARGET_X64
 274   { /* Write .pdata section. */
 275     uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
 276     uint32_t pdata[3];  /* Start of .text, end of .text and .xdata. */
 277     PEreloc reloc;
 278     pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
 279     owrite(ctx, &pdata, sizeof(pdata));
 280     pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
 281     owrite(ctx, &pdata, sizeof(pdata));
 282     reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
 283     reloc.type = PEOBJ_RELOC_ADDR32NB;
 284     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 285     reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
 286     reloc.type = PEOBJ_RELOC_ADDR32NB;
 287     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 288     reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
 289     reloc.type = PEOBJ_RELOC_ADDR32NB;
 290     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 291     reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
 292     reloc.type = PEOBJ_RELOC_ADDR32NB;
 293     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 294     reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
 295     reloc.type = PEOBJ_RELOC_ADDR32NB;
 296     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 297     reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
 298     reloc.type = PEOBJ_RELOC_ADDR32NB;
 299     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 300   }
 301   { /* Write .xdata section. */
 302     uint16_t xdata[8+2+6];
 303     PEreloc reloc;
 304     xdata[0] = 0x01|0x08|0x10;  /* Ver. 1, uhandler/ehandler, prolog size 0. */
 305     xdata[1] = 0x0005;  /* Number of unwind codes, no frame pointer. */
 306     xdata[2] = 0x4200;  /* Stack offset 4*8+8 = aword*5. */
 307     xdata[3] = 0x3000;  /* Push rbx. */
 308     xdata[4] = 0x6000;  /* Push rsi. */
 309     xdata[5] = 0x7000;  /* Push rdi. */
 310     xdata[6] = 0x5000;  /* Push rbp. */
 311     xdata[7] = 0;  /* Alignment. */
 312     xdata[8] = xdata[9] = 0;  /* Relocated address of exception handler. */
 313     xdata[10] = 0x01;  /* Ver. 1, no handler, prolog size 0. */
 314     xdata[11] = 0x1504;  /* Number of unwind codes, fp = rbp, fpofs = 16. */
 315     xdata[12] = 0x0300;  /* set_fpreg. */
 316     xdata[13] = 0x0200;  /* stack offset 0*8+8 = aword*1. */
 317     xdata[14] = 0x3000;  /* Push rbx. */
 318     xdata[15] = 0x5000;  /* Push rbp. */
 319     owrite(ctx, &xdata, sizeof(xdata));
 320     reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
 321     reloc.type = PEOBJ_RELOC_ADDR32NB;
 322     owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
 323   }
 324 #elif LJ_TARGET_X86
 325   /* Write .sxdata section. */
 326   for (i = 0; i < nrsym; i++) {
 327     if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) {
 328       uint32_t symidx = 1+2+i;
 329       owrite(ctx, &symidx, 4);
 330       break;
 331     }
 332   }
 333   if (i == nrsym) {
 334     fprintf(stderr, "Error: extern lj_err_unwind_win not used\n");
 335     exit(1);
 336   }
 337 #endif
 338 
 339   /* Write .rdata$Z section. */
 340   owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
 341 
 342   /* Write symbol table. */
 343   strtab = NULL;  /* 1st pass: collect string sizes. */
 344   for (;;) {
 345     strtabofs = 4;
 346     /* Mark as SafeSEH compliant. */
 347     emit_peobj_sym(ctx, "@feat.00", 1,
 348                    PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
 349 
 350     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
 351     for (i = 0; i < nrsym; i++)
 352       emit_peobj_sym(ctx, ctx->relocsym[i], 0,
 353                      PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 354 
 355 #if LJ_TARGET_X64
 356     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
 357     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
 358     emit_peobj_sym(ctx, "lj_err_unwind_win", 0,
 359                    PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 360 #elif LJ_TARGET_X86
 361     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA);
 362 #endif
 363 
 364     emit_peobj_sym(ctx, ctx->beginsym, 0,
 365                    PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
 366     for (i = 0; i < ctx->nsym; i++)
 367       emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
 368                      PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
 369 
 370     emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
 371 
 372     if (strtab)
 373       break;
 374     /* 2nd pass: alloc strtab, write syms and copy strings. */
 375     strtab = (char *)malloc(strtabofs);
 376     *(uint32_t *)strtab = (uint32_t)strtabofs;
 377   }
 378 
 379   /* Write string table. */
 380   owrite(ctx, strtab, strtabofs);
 381 }
 382 
 383 #else
 384 
 385 void emit_peobj(BuildCtx *ctx)
 386 {
 387   UNUSED(ctx);
 388   fprintf(stderr, "Error: no PE object support for this target\n");
 389   exit(1);
 390 }
 391 
 392 #endif

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