From 55b16959717084884fd4a0cbae6d19e3786c20c7 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Tue, 8 Dec 2009 19:46:35 +0100 Subject: RELEASE LuaJIT-2.0.0-beta1 --- src/buildvm_peobj.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/buildvm_peobj.c (limited to 'src/buildvm_peobj.c') diff --git a/src/buildvm_peobj.c b/src/buildvm_peobj.c new file mode 100644 index 00000000..9acf6b76 --- /dev/null +++ b/src/buildvm_peobj.c @@ -0,0 +1,303 @@ +/* +** LuaJIT VM builder: PE object emitter. +** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h +** +** Only used for building on Windows, since we cannot assume the presence +** of a suitable assembler. The host and target byte order must match. +*/ + +#include "buildvm.h" +#include "lj_bc.h" + +#if LJ_TARGET_X86ORX64 + +/* Context for PE object emitter. */ +static char *strtab; +static size_t strtabofs; + +/* -- PE object definitions ----------------------------------------------- */ + +/* PE header. */ +typedef struct PEheader { + uint16_t arch; + uint16_t nsects; + uint32_t time; + uint32_t symtabofs; + uint32_t nsyms; + uint16_t opthdrsz; + uint16_t flags; +} PEheader; + +/* PE section. */ +typedef struct PEsection { + char name[8]; + uint32_t vsize; + uint32_t vaddr; + uint32_t size; + uint32_t ofs; + uint32_t relocofs; + uint32_t lineofs; + uint16_t nreloc; + uint16_t nline; + uint32_t flags; +} PEsection; + +/* PE relocation. */ +typedef struct PEreloc { + uint32_t vaddr; + uint32_t symidx; + uint16_t type; +} PEreloc; + +/* Cannot use sizeof, because it pads up to the max. alignment. */ +#define PEOBJ_RELOC_SIZE (4+4+2) + +/* PE symbol table entry. */ +typedef struct PEsym { + union { + char name[8]; + uint32_t nameref[2]; + } n; + uint32_t value; + int16_t sect; + uint16_t type; + uint8_t scl; + uint8_t naux; +} PEsym; + +/* PE symbol table auxiliary entry for a section. */ +typedef struct PEsymaux { + uint32_t size; + uint16_t nreloc; + uint16_t nline; + uint32_t cksum; + uint16_t assoc; + uint8_t comdatsel; + uint8_t unused[3]; +} PEsymaux; + +/* Cannot use sizeof, because it pads up to the max. alignment. */ +#define PEOBJ_SYM_SIZE (8+4+2+2+1+1) + +/* PE object CPU specific defines. */ +#if LJ_TARGET_X86 +#define PEOBJ_ARCH_TARGET 0x014c +#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */ +#define PEOBJ_RELOC_DIR32 0x06 +#define PEOBJ_SYM_PREFIX "_" +#elif LJ_TARGET_X64 +#define PEOBJ_ARCH_TARGET 0x8664 +#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */ +#define PEOBJ_RELOC_DIR32 0x02 +#define PEOBJ_SYM_PREFIX "" +#endif + +/* Section numbers (0-based). */ +enum { + PEOBJ_SECT_ABS = -2, + PEOBJ_SECT_UNDEF = -1, + PEOBJ_SECT_TEXT, + /* TODO: add .pdata/.xdata for x64. */ + PEOBJ_SECT_RDATA, + PEOBJ_SECT_RDATA_Z, + PEOBJ_NSECTIONS +}; + +/* Symbol types. */ +#define PEOBJ_TYPE_NULL 0 +#define PEOBJ_TYPE_FUNC 0x20 + +/* Symbol storage class. */ +#define PEOBJ_SCL_EXTERN 2 +#define PEOBJ_SCL_STATIC 3 + +/* -- PE object emitter --------------------------------------------------- */ + +/* Emit PE object symbol. */ +static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value, + int sect, int type, int scl) +{ + PEsym sym; + size_t len = strlen(name); + if (!strtab) { /* Pass 1: only calculate string table length. */ + if (len > 8) strtabofs += len+1; + return; + } + if (len <= 8) { + memcpy(sym.n.name, name, len); + memset(sym.n.name+len, 0, 8-len); + } else { + sym.n.nameref[0] = 0; + sym.n.nameref[1] = strtabofs; + memcpy(strtab + strtabofs, name, len); + strtab[strtabofs+len] = 0; + strtabofs += len+1; + } + sym.value = value; + sym.sect = (int16_t)(sect+1); /* 1-based section number. */ + sym.type = (uint16_t)type; + sym.scl = (uint8_t)scl; + sym.naux = 0; + owrite(ctx, &sym, PEOBJ_SYM_SIZE); +} + +/* Emit PE object section symbol. */ +static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect) +{ + PEsym sym; + PEsymaux aux; + if (!strtab) return; /* Pass 1: no output. */ + memcpy(sym.n.name, pesect[sect].name, 8); + sym.value = 0; + sym.sect = (int16_t)(sect+1); /* 1-based section number. */ + sym.type = PEOBJ_TYPE_NULL; + sym.scl = PEOBJ_SCL_STATIC; + sym.naux = 1; + owrite(ctx, &sym, PEOBJ_SYM_SIZE); + memset(&aux, 0, sizeof(PEsymaux)); + aux.size = pesect[sect].size; + aux.nreloc = pesect[sect].nreloc; + owrite(ctx, &aux, PEOBJ_SYM_SIZE); +} + +#define emit_peobj_sym_func(ctx, name, ofs) \ + emit_peobj_sym(ctx, name, (uint32_t)(ofs), \ + PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN) +#define emit_peobj_sym_rdata(ctx, name, ofs) \ + emit_peobj_sym(ctx, name, (uint32_t)(ofs), \ + PEOBJ_SECT_RDATA, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN) + +/* Emit Windows PE object file. */ +void emit_peobj(BuildCtx *ctx) +{ + PEheader pehdr; + PEsection pesect[PEOBJ_NSECTIONS]; + int nzsym, relocsyms; + uint32_t sofs; + int i; + union { uint8_t b; uint32_t u; } host_endian; + + host_endian.u = 1; + if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) { + fprintf(stderr, "Error: different byte order for host and target\n"); + exit(1); + } + + sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection); + + /* Fill in PE sections. */ + memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection)); + memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1); + pesect[PEOBJ_SECT_TEXT].ofs = sofs; + sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz); + pesect[PEOBJ_SECT_TEXT].relocofs = sofs; + sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE; + /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ + pesect[PEOBJ_SECT_TEXT].flags = 0x60500020; + + memcpy(pesect[PEOBJ_SECT_RDATA].name, ".rdata", sizeof(".rdata")-1); + pesect[PEOBJ_SECT_RDATA].ofs = sofs; + sofs += (pesect[PEOBJ_SECT_RDATA].size = ctx->npc*sizeof(uint16_t)); + /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ + pesect[PEOBJ_SECT_RDATA].flags = 0x40300040; + + memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1); + pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs; + sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1); + /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ + pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040; + + /* Fill in PE header. */ + pehdr.arch = PEOBJ_ARCH_TARGET; + pehdr.nsects = PEOBJ_NSECTIONS; + pehdr.time = 0; /* Timestamp is optional. */ + pehdr.symtabofs = sofs; + pehdr.opthdrsz = 0; + pehdr.flags = 0; + + /* Compute the size of the symbol table: + ** @feat.00 + nsections*2 + ** + asm_start + (nsyms-nzsym) + op_ofs + ** + relocsyms + */ + /* Skip _Z syms. */ + for (nzsym = 0; ctx->sym_ofs[ctx->perm[nzsym]] < 0; nzsym++) ; + for (relocsyms = 0; ctx->extnames[relocsyms]; relocsyms++) ; + pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+(ctx->nsym-nzsym)+1 + relocsyms; + + /* Write PE object header and all sections. */ + owrite(ctx, &pehdr, sizeof(PEheader)); + owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS); + + /* Write .text section. */ + owrite(ctx, ctx->code, ctx->codesz); + for (i = 0; i < ctx->nreloc; i++) { + PEreloc reloc; + reloc.vaddr = (uint32_t)ctx->reloc[i].ofs; + reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */ + reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + } + + /* Write .rdata section. */ + for (i = 0; i < ctx->npc; i++) { + uint16_t pcofs = (uint16_t)ctx->sym_ofs[i]; + owrite(ctx, &pcofs, 2); + } + + /* Write .rdata$Z section. */ + owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1); + + /* Write symbol table. */ + strtab = NULL; /* 1st pass: collect string sizes. */ + for (;;) { + char name[80]; + + strtabofs = 4; + /* Mark as SafeSEH compliant. */ + emit_peobj_sym(ctx, "@feat.00", 1, + PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC); + + emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT); + for (i = 0; ctx->extnames[i]; i++) { + sprintf(name, PEOBJ_SYM_PREFIX "%s", ctx->extnames[i]); + emit_peobj_sym(ctx, name, 0, + PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); + } + emit_peobj_sym_func(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0); + for (i = nzsym; i < ctx->nsym; i++) { + int pi = ctx->perm[i]; + if (pi >= ctx->npc) { + sprintf(name, PEOBJ_SYM_PREFIX LABEL_PREFIX "%s", + ctx->globnames[pi-ctx->npc]); + emit_peobj_sym_func(ctx, name, ctx->sym_ofs[pi]); +#if LJ_HASJIT + } else { +#else + } else if (!(pi == BC_JFORI || pi == BC_JFORL || pi == BC_JITERL || + pi == BC_JLOOP || pi == BC_IFORL || pi == BC_IITERL || + pi == BC_ILOOP)) { +#endif + sprintf(name, PEOBJ_SYM_PREFIX LABEL_PREFIX_BC "%s", + bc_names[pi]); + emit_peobj_sym_func(ctx, name, ctx->sym_ofs[pi]); + } + } + + emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA); + emit_peobj_sym_rdata(ctx, PEOBJ_SYM_PREFIX LABEL_OP_OFS, 0); + + emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z); + + if (strtab) + break; + /* 2nd pass: alloc strtab, write syms and copy strings. */ + strtab = (char *)malloc(strtabofs); + *(uint32_t *)strtab = strtabofs; + } + + /* Write string table. */ + owrite(ctx, strtab, strtabofs); +} + +#endif -- cgit v1.2.3-55-g6feb