Files
reverse-engineering-anything/src/domain/elfRelocation.ts
T
morluto a7f50e3386 refactor: consolidate ELF and CLR record interpretation
Share ELF note headers across note inspection, Flutter build IDs, Node SEA,
and recorded-crash source binding. Decode REL/RELA records once for MIPS
shared-load analysis and IL2CPP linking, removing superseded scalar helpers.

Share the CLR header prefix between desktop detection and managed PE parsing
while preserving their distinct read bounds and admission policies. Cover
those differences and ignored R_NONE fields with production-boundary tests.

Validation: 493 focused tests passed, two existing skips; static checks and
test discovery passed. Public managed/desktop CLI and ELF notes CLI/MCP
workflows exercised; no real external analysis providers were run.
2026-10-26 16:50:08 +08:00

62 lines
1.9 KiB
TypeScript

import { err, ok, type Result } from "./result.js";
interface ElfRelocationEntry {
readonly offset: bigint;
readonly type: number;
readonly symbolIndex: number;
}
interface ElfRelaEntry extends ElfRelocationEntry {
readonly addend: bigint;
}
interface ElfRelocationFailure {
readonly kind: "malformed";
readonly message: string;
}
export function readElfRelocationEntry(
bytes: Uint8Array,
bits: 32 | 64,
littleEndian: boolean,
encoding: "rel",
): Result<ElfRelocationEntry, ElfRelocationFailure>;
export function readElfRelocationEntry(
bytes: Uint8Array,
bits: 32 | 64,
littleEndian: boolean,
encoding: "rela",
): Result<ElfRelaEntry, ElfRelocationFailure>;
/** Decode standard REL/RELA fields; architecture-specific application remains with consumers. */
export function readElfRelocationEntry(
bytes: Uint8Array,
bits: 32 | 64,
littleEndian: boolean,
encoding: "rel" | "rela",
): Result<ElfRelocationEntry | ElfRelaEntry, ElfRelocationFailure> {
const wordBytes = bits === 64 ? 8 : 4;
if (bytes.byteLength < wordBytes * (encoding === "rela" ? 3 : 2))
return err({
kind: "malformed",
message: "ELF relocation entry is truncated",
});
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
const offset =
bits === 64
? view.getBigUint64(0, littleEndian)
: BigInt(view.getUint32(0, littleEndian));
const info =
bits === 64
? view.getBigUint64(wordBytes, littleEndian)
: BigInt(view.getUint32(wordBytes, littleEndian));
const entry = {
offset,
type: Number(info & (bits === 64 ? 0xffffffffn : 0xffn)),
symbolIndex: Number(info >> (bits === 64 ? 32n : 8n)),
};
if (encoding === "rel") return ok(entry);
const addend =
bits === 64
? view.getBigInt64(wordBytes * 2, littleEndian)
: BigInt(view.getInt32(wordBytes * 2, littleEndian));
return ok({ ...entry, addend });
}