-
Notifications
You must be signed in to change notification settings - Fork 17
refactor(macho): abstract bind/rebase resolution behind protocol #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import MachOKit | ||
|
|
||
| /// Exposes dyld bind / rebase resolution capabilities required when decoding | ||
| /// indirect symbolic references in Swift metadata. | ||
| /// | ||
| /// `SymbolOrElementPointer` and other indirect-pointer readers must consult | ||
| /// this protocol before treating the bytes at a relocation site as a literal | ||
| /// virtual address. For files coming straight from disk the bytes are still | ||
| /// chained-fixup encoded; only after binding/rebasing through the dyld | ||
| /// metadata do they become a usable address. | ||
| /// | ||
| /// The protocol exists so the resolver code can stay generic over the reading | ||
| /// context and not hard-code `MachOFile`. Wrapper types (e.g. UI-layer | ||
| /// projections that compose a `MachOFile` plus extra state) just forward to | ||
| /// the underlying `MachOFile` to participate in the same dispatch. | ||
| public protocol MachOBindRebaseResolving: Sendable { | ||
| /// Resolves a bind operation at the given file offset and returns the | ||
| /// imported symbol name, or `nil` when the offset is not bound. | ||
| func resolveBind(fileOffset: Int) -> String? | ||
|
|
||
| /// Resolves a rebase operation at the given file offset and returns the | ||
| /// rebased absolute address, or `nil` when no rebase is recorded. | ||
| func resolveRebase(fileOffset: Int) -> UInt64? | ||
| } | ||
|
|
||
| extension MachOFile: MachOBindRebaseResolving {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,42 +75,31 @@ public enum SymbolOrElementPointer<Element: Resolvable>: RelativeIndirectType { | |
| } | ||
|
|
||
| public static func resolve<MachO: MachORepresentableWithCache & Readable>(from offset: Int, in machO: MachO) throws -> Self { | ||
| if let machOFile = machO as? MachOFile { | ||
| if let symbol = machOFile.resolveBind(fileOffset: offset) { | ||
| if let resolver = machO as? any MachOBindRebaseResolving { | ||
| if let symbol = resolver.resolveBind(fileOffset: offset) { | ||
| return .symbol(.init(offset: offset, name: symbol)) | ||
| } else { | ||
| let resolvedFileOffset = offset | ||
| if let rebase = machOFile.resolveRebase(fileOffset: resolvedFileOffset) { | ||
| return .address(rebase) | ||
| } else { | ||
| return try .address(machOFile.readElement(offset: resolvedFileOffset)) | ||
| } | ||
| } | ||
| } else { | ||
| return try .address(machO.readElement(offset: offset)) | ||
| if let rebase = resolver.resolveRebase(fileOffset: offset) { | ||
| return .address(rebase) | ||
| } | ||
| } | ||
| return try .address(machO.readElement(offset: offset)) | ||
|
Comment on lines
77
to
+86
|
||
| } | ||
|
|
||
| public static func resolve(from ptr: UnsafeRawPointer) throws -> Self { | ||
| return try .address(ptr.stripPointerTags().assumingMemoryBound(to: UInt64.self).pointee) | ||
| } | ||
|
|
||
| public static func resolve<Context: ReadingContext>(at address: Context.Address, in context: Context) throws -> Self { | ||
| if let machOFileContext = context as? MachOContext<MachOFile> { | ||
| let machOFile = machOFileContext.machO | ||
| if let resolver = context.bindRebaseResolver { | ||
| let offset = try context.offsetFromAddress(address) | ||
| if let symbol = machOFile.resolveBind(fileOffset: offset) { | ||
| if let symbol = resolver.resolveBind(fileOffset: offset) { | ||
| return .symbol(.init(offset: offset, name: symbol)) | ||
| } else { | ||
| let resolvedFileOffset = offset | ||
| if let rebase = machOFile.resolveRebase(fileOffset: resolvedFileOffset) { | ||
| return .address(rebase) | ||
| } else { | ||
| return try .address(machOFile.readElement(offset: resolvedFileOffset)) | ||
| } | ||
| } | ||
| } else { | ||
| return try .address(context.readElement(at: address)) | ||
| if let rebase = resolver.resolveRebase(fileOffset: offset) { | ||
| return .address(rebase) | ||
| } | ||
| } | ||
| return try .address(context.readElement(at: address)) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a retroactive conformance of an external type (
MachOFilefrom MachOKit) to a local protocol. The codebase already uses@retroactivefor similar conformances; adding it here will avoid Swift’s retroactive-conformance warnings and makes the intent explicit.