diff --git a/scripts/lib/managed-pe-fixture.d.mts b/scripts/lib/managed-pe-fixture.d.mts new file mode 100644 index 000000000..57567b917 --- /dev/null +++ b/scripts/lib/managed-pe-fixture.d.mts @@ -0,0 +1,36 @@ +export interface ManagedPeFixtureMethod { + readonly body?: Buffer; + readonly flags?: number; + readonly implFlags?: number; + readonly name: string; +} + +export interface ManagedPeFixtureOptions { + readonly cliFlags?: number; + readonly corruptMetadataSignature?: boolean; + readonly fieldName?: string; + readonly ilBody?: Buffer; + readonly machine?: number; + readonly metadataValidMaskExtra?: bigint; + readonly methodImplFlags?: number; + readonly methodName?: string; + readonly methods?: readonly ManagedPeFixtureMethod[]; + readonly mvid?: Buffer; + readonly pinvoke?: { + readonly importName?: string; + readonly mappingFlags?: number; + readonly moduleName?: string; + }; + readonly readyToRun?: boolean; + readonly references?: readonly string[]; + readonly resourceData?: Buffer; + readonly targetFramework?: string; + readonly typeName?: string; + readonly typeNamespace?: string; +} + +export const alternateMvid: Buffer; +export function buildManagedPeFixture( + options?: ManagedPeFixtureOptions, +): Buffer; +export function buildNativePeFixture(): Buffer; diff --git a/scripts/lib/managed-pe-fixture.mjs b/scripts/lib/managed-pe-fixture.mjs index dffc742f9..01d388dde 100644 --- a/scripts/lib/managed-pe-fixture.mjs +++ b/scripts/lib/managed-pe-fixture.mjs @@ -330,22 +330,27 @@ export const buildManagedPeFixture = (options = {}) => { image.writeUInt32LE(0x80, 0x3c); image.writeUInt32LE(0x0000_4550, 0x80); const coff = 0x84; - image.writeUInt16LE(options.machine ?? 0x014c, coff); + const machine = options.machine ?? 0x014c; + const pe32Plus = machine === 0x8664 || machine === 0xaa64; + const optionalSize = pe32Plus ? 0x00f0 : 0x00e0; + const directoryOffset = pe32Plus ? 112 : 96; + image.writeUInt16LE(machine, coff); image.writeUInt16LE(1, coff + 2); - image.writeUInt16LE(0x00e0, coff + 16); + image.writeUInt16LE(optionalSize, coff + 16); image.writeUInt16LE(0x0102, coff + 18); const optional = coff + 20; - image.writeUInt16LE(0x010b, optional); + image.writeUInt16LE(pe32Plus ? 0x020b : 0x010b, optional); image.writeUInt32LE(0x2000, optional + 20); - image.writeUInt32LE(0x0040_0000, optional + 28); + if (pe32Plus) image.writeBigUInt64LE(0x0040_0000n, optional + 24); + else image.writeUInt32LE(0x0040_0000, optional + 28); image.writeUInt32LE(0x1000, optional + 32); image.writeUInt32LE(0x200, optional + 36); image.writeUInt32LE(0x3000, optional + 56); image.writeUInt32LE(0x200, optional + 60); - image.writeUInt32LE(16, optional + 92); - image.writeUInt32LE(0x2000, optional + 96 + 14 * 8); - image.writeUInt32LE(72, optional + 96 + 14 * 8 + 4); - const section = optional + 0x00e0; + image.writeUInt32LE(16, optional + directoryOffset - 4); + image.writeUInt32LE(0x2000, optional + directoryOffset + 14 * 8); + image.writeUInt32LE(72, optional + directoryOffset + 14 * 8 + 4); + const section = optional + optionalSize; image.write(".text\0\0\0", section, "ascii"); image.writeUInt32LE(0x1000, section + 8); image.writeUInt32LE(0x2000, section + 12); diff --git a/tests/managedConformanceFixture.test.ts b/tests/managedConformanceFixture.test.ts new file mode 100644 index 000000000..ec2528dc2 --- /dev/null +++ b/tests/managedConformanceFixture.test.ts @@ -0,0 +1,36 @@ +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { afterEach, describe, expect, it } from "vitest"; + +import { buildManagedPeFixture } from "../scripts/lib/managed-pe-fixture.mjs"; +import { parseBinaryTarget } from "../src/domain/binaryTarget.js"; + +const workspaces: string[] = []; + +afterEach(async () => { + await Promise.all( + workspaces.splice(0).map((path) => rm(path, { recursive: true })), + ); +}); + +describe("managed conformance fixture", () => { + it("emits PE32+ headers when the COFF machine is x86-64", async () => { + const workspace = await mkdtemp(join(tmpdir(), "rea-managed-fixture-")); + workspaces.push(workspace); + const path = join(workspace, "fixture.exe"); + await writeFile(path, buildManagedPeFixture({ machine: 0x8664 })); + + const parsed = await parseBinaryTarget(path); + + expect(parsed).toMatchObject({ + ok: true, + value: { + format: "pe", + architecture: "x86_64", + managed: true, + }, + }); + }); +});