buildvm_peobj.c (12154B)
1 /* 2 ** LuaJIT VM builder: PE object emitter. 3 ** Copyright (C) 2005-2016 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