2 ** LuaJIT VM builder: PE object emitter.
3 ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
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.
12 #if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC
14 /* Context for PE object emitter. */
16 static size_t strtabofs
;
18 /* -- PE object definitions ----------------------------------------------- */
21 typedef struct PEheader
{
32 typedef struct PEsection
{
46 typedef struct PEreloc
{
52 /* Cannot use sizeof, because it pads up to the max. alignment. */
53 #define PEOBJ_RELOC_SIZE (4+4+2)
55 /* PE symbol table entry. */
56 typedef struct PEsym
{
68 /* PE symbol table auxiliary entry for a section. */
69 typedef struct PEsymaux
{
79 /* Cannot use sizeof, because it pads up to the max. alignment. */
80 #define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
82 /* PE object CPU specific defines. */
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. */
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. */
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. */
104 /* Section numbers (0-based). */
107 PEOBJ_SECT_UNDEF
= -1,
118 #define PEOBJ_TYPE_NULL 0
119 #define PEOBJ_TYPE_FUNC 0x20
121 /* Symbol storage class. */
122 #define PEOBJ_SCL_EXTERN 2
123 #define PEOBJ_SCL_STATIC 3
125 /* -- PE object emitter --------------------------------------------------- */
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
)
132 size_t len
= strlen(name
);
133 if (!strtab
) { /* Pass 1: only calculate string table length. */
134 if (len
> 8) strtabofs
+= len
+1;
138 memcpy(sym
.n
.name
, name
, len
);
139 memset(sym
.n
.name
+len
, 0, 8-len
);
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;
148 sym
.sect
= (int16_t)(sect
+1); /* 1-based section number. */
149 sym
.type
= (uint16_t)type
;
150 sym
.scl
= (uint8_t)scl
;
152 owrite(ctx
, &sym
, PEOBJ_SYM_SIZE
);
155 /* Emit PE object section symbol. */
156 static void emit_peobj_sym_sect(BuildCtx
*ctx
, PEsection
*pesect
, int sect
)
160 if (!strtab
) return; /* Pass 1: no output. */
161 memcpy(sym
.n
.name
, pesect
[sect
].name
, 8);
163 sym
.sect
= (int16_t)(sect
+1); /* 1-based section number. */
164 sym
.type
= PEOBJ_TYPE_NULL
;
165 sym
.scl
= PEOBJ_SCL_STATIC
;
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
);
174 /* Emit Windows PE object file. */
175 void emit_peobj(BuildCtx
*ctx
)
178 PEsection pesect
[PEOBJ_NSECTIONS
];
181 union { uint8_t b
; uint32_t u
; } host_endian
;
183 sofs
= sizeof(PEheader
) + PEOBJ_NSECTIONS
*sizeof(PEsection
);
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
;
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;
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;
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;
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
;
227 /* Compute the size of the symbol table:
228 ** @feat.00 + nsections*2
229 ** + asm_start + nsym
232 nrsym
= ctx
->nrelocsym
;
233 pehdr
.nsyms
= 1+PEOBJ_NSECTIONS
*2 + 1+ctx
->nsym
+ nrsym
;
235 pehdr
.nsyms
+= 1; /* Symbol for lj_err_unwind_win64. */
238 /* Write PE object header and all sections. */
239 owrite(ctx
, &pehdr
, sizeof(PEheader
));
240 owrite(ctx
, &pesect
, sizeof(PEsection
)*PEOBJ_NSECTIONS
);
242 /* Write .text section. */
244 if (host_endian
.b
!= LJ_ENDIAN_SELECT(1, 0)) {
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. */
251 fprintf(stderr
, "Error: different byte order for host and target\n");
255 owrite(ctx
, ctx
->code
, ctx
->codesz
);
256 for (i
= 0; i
< ctx
->nreloc
; i
++) {
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
);
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. */
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
);
292 { /* Write .xdata section. */
293 uint16_t xdata
[8+2+6];
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
);
317 /* Write .rdata$Z section. */
318 owrite(ctx
, ctx
->dasm_ident
, strlen(ctx
->dasm_ident
)+1);
320 /* Write symbol table. */
321 strtab
= NULL
; /* 1st pass: collect string sizes. */
324 /* Mark as SafeSEH compliant. */
325 emit_peobj_sym(ctx
, "@feat.00", 1,
326 PEOBJ_SECT_ABS
, PEOBJ_TYPE_NULL
, PEOBJ_SCL_STATIC
);
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
);
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
);
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
);
346 emit_peobj_sym_sect(ctx
, pesect
, PEOBJ_SECT_RDATA_Z
);
350 /* 2nd pass: alloc strtab, write syms and copy strings. */
351 strtab
= (char *)malloc(strtabofs
);
352 *(uint32_t *)strtab
= (uint32_t)strtabofs
;
355 /* Write string table. */
356 owrite(ctx
, strtab
, strtabofs
);
361 void emit_peobj(BuildCtx
*ctx
)
364 fprintf(stderr
, "Error: no PE object support for this target\n");