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