1/*
2** LuaJIT VM builder: PE object emitter.
3** Copyright (C) 2005-2014 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. */
15static char *strtab;
16static size_t strtabofs;
17
18/* -- PE object definitions ----------------------------------------------- */
19
20/* PE header. */
21typedef 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. */
32typedef 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. */
46typedef 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. */
56typedef 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. */
69typedef 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). */
105enum {
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. */
128static 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. */
156static 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. */
175void 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
361void 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
369