fix(native): own complete metadata mappings and ambiguity

Resolve Go pointer descriptors and strings across complete, consistent file-backed spans, including PE headers and adjacent ELF load ranges. Reuse the canonical image-mapping selection for native exports. Preserve existing gaps, alias, zero-fill and capacity refusals.

Forward parsed zero-fill ownership through IL2CPP relocation tables, destinations and mapped-span checks. Distinguish missing spans from ambiguous ownership in the shared mapping failure: unresolved relocation targets may remain unknown, while ambiguous raw registration bytes cannot be reused as a resolved count.

Validation: parser, provider, service, native-export, IL2CPP and public CLI/MCP regressions cover PE32/PE32+ headers, split ELF descriptors/contents, relocation count conflicts, ordinary unresolved targets and unchanged inputs. Authored carriers establish static parsing, not Windows loading or actual legacy Go linker emission.

Fixes #6831
Fixes #6830
This commit is contained in:
morluto committed 2026-10-24 04:21:56 +08:00
1 parent b7ebccf8d3
commit 8b3902d377
12 files changed
+526 -41

No files matched your search

+8 -7
View File
@@ -1,5 +1,5 @@
import {
BinaryFormatFailure,
BinaryMappingFailure,
mappedFileOffset,
isZeroFilledSpan,
type FileMapping,
@@ -124,14 +124,15 @@ function* dynamicTags(image: Buffer): Generator<void, Map<bigint, bigint>> {
}
const fileOffset = (
mappings: readonly FileMapping[],
source: RelocationSource,
address: bigint,
size: number,
): number | null => {
try {
return mappedFileOffset(mappings, address, size);
return mappedFileOffset(source.mappings, address, size, source.zeroFills);
} catch (cause) {
if (cause instanceof BinaryFormatFailure) return null;
if (cause instanceof BinaryMappingFailure && cause.reason === "unmapped")
return null;
throw cause;
}
};
@@ -163,7 +164,7 @@ function* applyRelaTable(
size > BigInt(source.image.length)
)
throw malformed("invalid DT_RELASZ or DT_RELAENT");
const start = fileOffset(source.mappings, address, Number(size));
const start = fileOffset(source, address, Number(size));
if (start === null) throw malformed("RELA table is not file-backed");
for (let at = start; at < start + Number(size); at += 24) {
if ((at - start) % (24 * 4096) === 0) yield;
@@ -180,11 +181,11 @@ function* applyRelaTable(
output.unresolved.set(destination, Math.max(priorWidth ?? 0, width));
// Registration scans read this private image directly. Clear unknown
// fields so their stored bytes cannot masquerade as resolved pointers.
const target = fileOffset(source.mappings, destination, width);
const target = fileOffset(source, destination, width);
if (target !== null) output.bytes.fill(0, target, target + width);
continue;
}
const target = fileOffset(source.mappings, destination, 8);
const target = fileOffset(source, destination, 8);
const value = source.image.readBigInt64LE(at + 16) & 0xffffffffffffffffn;
if (target !== null) output.bytes.writeBigUInt64LE(value, target);
else if (
+6 -1
View File
@@ -237,7 +237,12 @@ export const readUInt32 = (
export const isMapped = (image: NativeImage, address: bigint, size: number) => {
try {
mappedFileOffset(image.container.mappings, address, size);
mappedFileOffset(
image.container.mappings,
address,
size,
image.container.zero_fills,
);
return true;
} catch (cause) {
if (cause instanceof BinaryFormatFailure) return false;