refactor(pe): share optional header image and alignment facts

This commit is contained in:
morluto committed 2026-10-26 14:04:45 +08:00
1 parent 72fa15a509
commit 5c4a6c467c
4 files changed
+52 -4

No files matched your search

+13
View File
@@ -14,6 +14,10 @@ const header = (
): Buffer => {
const bytes = Buffer.alloc(byteLength);
bytes.writeUInt16LE(format.magic);
if (format.bits === 64) bytes.writeBigUInt64LE(0xfedcba9876540000n, 24);
else bytes.writeUInt32LE(0x87650000, 28);
bytes.writeUInt32LE(0x1000, 32);
bytes.writeUInt32LE(0x200, 36);
bytes.writeUInt32LE(0x400, 60);
bytes.writeUInt32LE(directoryCount, format.directoryOffset - 4);
return bytes;
@@ -32,6 +36,9 @@ it.each(formats)(
if (!result.ok) throw new Error(result.error.message);
expect(result.value).toMatchObject({
...format,
imageBase: format.bits === 64 ? 0xfedcba9876540000n : 0x87650000n,
sectionAlignment: 0x1000,
fileAlignment: 0x200,
sizeOfHeaders: 0x400,
directoryCount: 5,
});
@@ -54,6 +61,9 @@ it.each(formats)(
ok: true,
value: {
...format,
imageBase: format.bits === 64 ? 0xfedcba9876540000n : 0x87650000n,
sectionAlignment: 0x1000,
fileAlignment: 0x200,
sizeOfHeaders: 0xffffffff,
directoryCount: 0,
dataDirectories: [],
@@ -157,6 +167,9 @@ it("honors a Uint8Array window and detaches facts from later source changes", ()
backing.fill(0);
expect(result.value).toEqual({
...formats[1],
imageBase: 0xfedcba9876540000n,
sectionAlignment: 0x1000,
fileAlignment: 0x200,
sizeOfHeaders: 0x400,
directoryCount: 1,
dataDirectories: [{ address: 0x12345678, size: 0x90, offset: 112 }],
+9
View File
@@ -13,6 +13,9 @@ export interface PeOptionalHeaderStructure {
readonly magic: 0x10b | 0x20b;
readonly bits: 32 | 64;
readonly format: "pe32" | "pe32-plus";
readonly imageBase: bigint;
readonly sectionAlignment: number;
readonly fileAlignment: number;
readonly sizeOfHeaders: number;
readonly directoryOffset: number;
readonly directoryCount: number;
@@ -74,6 +77,12 @@ export const readPeOptionalHeaderStructure = (
magic,
bits,
format: bits === 64 ? "pe32-plus" : "pe32",
imageBase:
bits === 64
? view.getBigUint64(24, true)
: BigInt(view.getUint32(28, true)),
sectionAlignment: view.getUint32(32, true),
fileAlignment: view.getUint32(36, true),
sizeOfHeaders: view.getUint32(60, true),
directoryOffset,
directoryCount,
+21
View File
@@ -68,6 +68,27 @@ it.each([32, 64] as const)(
},
);
it.each([32, 64] as const)(
"retains PE%d declared image base and alignments in native image facts",
(bits) => {
const { bytes } = createGoBinaryFixture({ format: "pe", bits });
const optional = bytes.readUInt32LE(0x3c) + 24;
const imageBase = bits === 64 ? 0xfedcba9876540000n : 0x87650000n;
if (bits === 64) bytes.writeBigUInt64LE(imageBase, optional + 24);
else bytes.writeUInt32LE(Number(imageBase), optional + 28);
// These remain declarations; alignment policy belongs to image consumers.
bytes.writeUInt32LE(0, optional + 32);
bytes.writeUInt32LE(0xffffffff, optional + 36);
const container = readPeImage(bytes);
expect(container.image_base).toBe(imageBase);
expect(container.pe_header_mapping.address).toBe(imageBase);
expect(container.mappings[0]?.address).toBe(imageBase + 0x400n);
expect(container.pe_section_alignment).toBe(0);
expect(container.pe_file_alignment).toBe(0xffffffff);
expect(container.sections[0]?.file_alignment).toBe(0xffffffff);
},
);
it("keeps Go fallback candidates when a PE section has no printable name", () => {
const fixture = createGoBinaryFixture({ format: "pe", bits: 64 });
const expected = readGoBinaryImage(fixture.bytes).build_info;
+9 -4
View File
@@ -82,9 +82,14 @@ export const readPeImage = (bytes: Buffer): PeImage => {
);
if (!facts.ok)
throw new BinaryFormatFailure(facts.error.kind, facts.error.message);
const { bits, dataDirectories, sizeOfHeaders } = facts.value;
const imageBase = reader.word(optional + (bits === 64 ? 24 : 28), bits);
const fileAlignment = reader.u32(optional + 36);
const {
bits,
dataDirectories,
sizeOfHeaders,
imageBase,
sectionAlignment,
fileAlignment,
} = facts.value;
const headerMapping: FileMapping = {
address: imageBase,
offset: 0,
@@ -153,7 +158,7 @@ export const readPeImage = (bytes: Buffer): PeImage => {
format: "pe",
image_base: imageBase,
pe_machine: machine,
pe_section_alignment: reader.u32(optional + 32),
pe_section_alignment: sectionAlignment,
pe_file_alignment: fileAlignment,
pe_data_directories: dataDirectories,
pe_header_mapping: headerMapping,