fix(native): wrap bind address advances to 64 bits

Apply dyld modulo-64 address arithmetic at the shared bind advance, retaining subsequent bindings after a negative ULEB skip.

Validation: all 37 Mach-O fixup tests pass, including continuation and false-failure controls.

Based on #3138.

Co-authored-by: Dragolone <810170966qq@gmail.com>
This commit is contained in:
morlutoandDragolone committed 2026-10-14 13:58:14 +08:00
1 parent 17e3cf9802
commit 576b58cefe
2 files changed
+44 -1

No files matched your search

+41
View File
@@ -907,6 +907,47 @@ describe("legacy pointer fixup streams", () => {
target: 0x99n,
});
});
it("wraps a negative DO_BIND_ADD_ADDR_ULEB step and keeps decoding", () => {
// The unsigned 64-bit encoding of -8 revisits the current pointer slot.
const back = [0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01];
const opcodes = Buffer.from([
0x11, // SET_DYLIB_ORDINAL_IMM 1
0x40,
...Buffer.from("__ZdlPv\0"),
0x71,
0x08, // SET_SEGMENT_AND_OFFSET segment 1 + 8
0xa0,
...back, // DO_BIND_ADD_ADDR_ULEB -8
0x90, // DO_BIND the same slot again
0x12, // SET_DYLIB_ORDINAL_IMM 2
0x40,
...Buffer.from("_OBJC_CLASS_$_NSObject\0"),
0x90, // DO_BIND the next slot
0x00,
]);
const fixups = parsePointerFixups(
opcodes,
{
chained: null,
binds: [{ offset: 0, size: opcodes.length, stream: "bind" }],
rebases: [],
dylibs: ["/usr/lib/libc++.1.dylib", "/usr/lib/libobjc.A.dylib"],
},
SEGMENTS,
BASE,
);
expect(fixups.failures).toEqual([]);
expect(fixups.decode(BASE + 0x4010n, 0n)).toMatchObject({
kind: "bind",
symbol: "_OBJC_CLASS_$_NSObject",
library: "/usr/lib/libobjc.A.dylib",
});
expect(fixups.decode(BASE + 0x4018n, 0x99n)).toEqual({
kind: "rebase",
target: 0x99n,
});
});
});
describe("Objective-C property attributes", () => {
+3 -1
View File
@@ -652,7 +652,9 @@ const readBindStream = (
} else {
binds.push({ start: state.address, count, stride, binding });
}
state.address += count * stride;
// The dyld bind stream advances addresses modulo 64 bits; ld uses -8 to
// bind the current pointer slot again with DO_BIND_ADD_ADDR_ULEB.
state.address = (state.address + count * stride) & 0xffffffffffffffffn;
};
while (cursor.at < end) {
const byte = bytes[cursor.at++] ?? 0;