mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-21 20:52:13 +08:00
GP-4462: Marking up the Mach-O rebase opcode table
This commit is contained in:
+28
-10
@@ -20,8 +20,7 @@ import java.io.IOException;
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||
import ghidra.app.util.bin.format.macho.commands.dyld.BindOpcode;
|
||||
import ghidra.app.util.bin.format.macho.commands.dyld.BindingTable;
|
||||
import ghidra.app.util.bin.format.macho.commands.dyld.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.address.Address;
|
||||
@@ -47,6 +46,7 @@ public class DyldInfoCommand extends LoadCommand {
|
||||
private int exportOff;
|
||||
private int exportSize;
|
||||
|
||||
private RebaseTable rebaseTable;
|
||||
private BindingTable bindingTable;
|
||||
private BindingTable weakBindingTable;
|
||||
private BindingTable lazyBindingTable;
|
||||
@@ -77,7 +77,13 @@ public class DyldInfoCommand extends LoadCommand {
|
||||
exportOff = loadCommandReader.readNextInt();
|
||||
exportSize = loadCommandReader.readNextInt();
|
||||
|
||||
// TODO: rebase
|
||||
if (rebaseOff > 0 && rebaseSize > 0) {
|
||||
dataReader.setPointerIndex(header.getStartIndex() + rebaseOff);
|
||||
rebaseTable = new RebaseTable(dataReader, header, rebaseSize);
|
||||
}
|
||||
else {
|
||||
rebaseTable = new RebaseTable();
|
||||
}
|
||||
|
||||
if (bindOff > 0 && bindSize > 0) {
|
||||
dataReader.setPointerIndex(header.getStartIndex() + bindOff);
|
||||
@@ -182,6 +188,13 @@ public class DyldInfoCommand extends LoadCommand {
|
||||
return exportSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return The rebase table}
|
||||
*/
|
||||
public RebaseTable getRebaseTable() {
|
||||
return rebaseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return The binding table}
|
||||
*/
|
||||
@@ -246,22 +259,27 @@ public class DyldInfoCommand extends LoadCommand {
|
||||
|
||||
private void markupRebaseInfo(Program program, MachHeader header, String source,
|
||||
TaskMonitor monitor, MessageLog log) {
|
||||
Address rebaseAddr = fileOffsetToAddress(program, header, rebaseOff, rebaseSize);
|
||||
markupPlateComment(program, fileOffsetToAddress(program, header, rebaseOff, rebaseSize),
|
||||
source, "rebase");
|
||||
markupOpcodeTable(program, rebaseAddr, rebaseTable, RebaseOpcode.toDataType(), source,
|
||||
"rebase", log);
|
||||
}
|
||||
|
||||
private void markupBindings(Program program, MachHeader header, String source,
|
||||
TaskMonitor monitor, MessageLog log) {
|
||||
Address bindAddr = fileOffsetToAddress(program, header, bindOff, bindSize);
|
||||
markupPlateComment(program, bindAddr, source, "bind");
|
||||
markupBindingTable(program, bindAddr, bindingTable, source, "bind", log);
|
||||
markupOpcodeTable(program, bindAddr, bindingTable, BindOpcode.toDataType(), source, "bind",
|
||||
log);
|
||||
}
|
||||
|
||||
private void markupWeakBindings(Program program, MachHeader header, String source,
|
||||
TaskMonitor monitor, MessageLog log) {
|
||||
Address addr = fileOffsetToAddress(program, header, weakBindOff, weakBindSize);
|
||||
markupPlateComment(program, addr, source, "weak bind");
|
||||
markupBindingTable(program, addr, weakBindingTable, source, "weak bind", log);
|
||||
markupOpcodeTable(program, addr, weakBindingTable, BindOpcode.toDataType(), source,
|
||||
"weak bind", log);
|
||||
|
||||
}
|
||||
|
||||
@@ -269,18 +287,18 @@ public class DyldInfoCommand extends LoadCommand {
|
||||
TaskMonitor monitor, MessageLog log) {
|
||||
Address addr = fileOffsetToAddress(program, header, lazyBindOff, lazyBindSize);
|
||||
markupPlateComment(program, addr, source, "lazy bind");
|
||||
markupBindingTable(program, addr, lazyBindingTable, source, "lazy bind", log);
|
||||
markupOpcodeTable(program, addr, lazyBindingTable, BindOpcode.toDataType(), source,
|
||||
"lazy bind", log);
|
||||
}
|
||||
|
||||
private void markupBindingTable(Program program, Address addr, BindingTable table,
|
||||
String source, String additionalDescription, MessageLog log) {
|
||||
private void markupOpcodeTable(Program program, Address addr, OpcodeTable table,
|
||||
DataType opcodeDataType, String source, String additionalDescription, MessageLog log) {
|
||||
if (addr == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
DataType bindOpcodeDataType = BindOpcode.toDataType();
|
||||
for (long offset : table.getOpcodeOffsets()) {
|
||||
DataUtilities.createData(program, addr.add(offset), bindOpcodeDataType, -1,
|
||||
DataUtilities.createData(program, addr.add(offset), opcodeDataType, -1,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
}
|
||||
for (long offset : table.getUlebOffsets()) {
|
||||
|
||||
+4
-43
@@ -28,29 +28,18 @@ import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* A Mach-O binding table
|
||||
*
|
||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOLayout.cpp">common/MachOLayout.cpp</a>
|
||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOAnalyzer.cpp">common/MachOAnalyzer.cpp</a>
|
||||
*/
|
||||
public class BindingTable {
|
||||
public class BindingTable extends OpcodeTable {
|
||||
|
||||
private List<Binding> bindings;
|
||||
private List<Binding> bindings = new ArrayList<>();
|
||||
private List<Binding> threadedBindings;
|
||||
private List<Long> opcodeOffsets;
|
||||
private List<Long> ulebOffsets;
|
||||
private List<Long> slebOffsets;
|
||||
private List<Long> stringOffsets;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an empty {@link BindingTable}
|
||||
*/
|
||||
public BindingTable() {
|
||||
bindings = new ArrayList<>();
|
||||
threadedBindings = null;
|
||||
opcodeOffsets = new ArrayList<>();
|
||||
ulebOffsets = new ArrayList<>();
|
||||
slebOffsets = new ArrayList<>();
|
||||
stringOffsets = new ArrayList<>();
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,34 +195,6 @@ public class BindingTable {
|
||||
return threadedBindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return opcode offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getOpcodeOffsets() {
|
||||
return opcodeOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return ULEB128 offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getUlebOffsets() {
|
||||
return ulebOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return SLEB128 offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getSlebOffsets() {
|
||||
return slebOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return string offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getStringOffsets() {
|
||||
return stringOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* A piece of binding information from a {@link BindingTable}
|
||||
*/
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.commands.dyld;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract class used to represent the generic components of a Mach-O opcode table
|
||||
*
|
||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOLayout.cpp">common/MachOLayout.cpp</a>
|
||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOAnalyzer.cpp">common/MachOAnalyzer.cpp</a>
|
||||
*/
|
||||
public abstract class OpcodeTable {
|
||||
|
||||
protected List<Long> opcodeOffsets = new ArrayList<>();
|
||||
protected List<Long> ulebOffsets = new ArrayList<>();
|
||||
protected List<Long> slebOffsets = new ArrayList<>();
|
||||
protected List<Long> stringOffsets = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* {@return opcode offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getOpcodeOffsets() {
|
||||
return opcodeOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return ULEB128 offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getUlebOffsets() {
|
||||
return ulebOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return SLEB128 offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getSlebOffsets() {
|
||||
return slebOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return string offsets from the start of the bind data}
|
||||
*/
|
||||
public List<Long> getStringOffsets() {
|
||||
return stringOffsets;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.commands.dyld;
|
||||
|
||||
import ghidra.app.util.bin.format.macho.MachConstants;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* Rebase opcodes
|
||||
*
|
||||
* @see <a href="https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h">EXTERNAL_HEADERS/mach-o/loader.h</a>
|
||||
*/
|
||||
public enum RebaseOpcode {
|
||||
|
||||
REBASE_OPCODE_DONE(0x00),
|
||||
REBASE_OPCODE_SET_TYPE_IMM(0x10),
|
||||
REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x20),
|
||||
REBASE_OPCODE_ADD_ADDR_ULEB(0x30),
|
||||
REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x40),
|
||||
REBASE_OPCODE_DO_REBASE_IMM_TIMES(0x50),
|
||||
REBASE_OPCODE_DO_REBASE_ULEB_TIMES(0x60),
|
||||
REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x70),
|
||||
REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(0x80);
|
||||
|
||||
private int opcode;
|
||||
|
||||
/**
|
||||
* Creates a new {@link RebaseOpcode} for the given opcode value
|
||||
*
|
||||
* @param opcode The opcode value
|
||||
*/
|
||||
private RebaseOpcode(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the opcode value}
|
||||
*/
|
||||
public int getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new data type from this enum}
|
||||
*/
|
||||
public static DataType toDataType() {
|
||||
EnumDataType enumDataType = new EnumDataType("rebase_opcode", 1);
|
||||
enumDataType.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||
for (RebaseOpcode rebaseOpcode : RebaseOpcode.values()) {
|
||||
enumDataType.add(rebaseOpcode.toString(), rebaseOpcode.getOpcode());
|
||||
}
|
||||
return enumDataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link RebaseOpcode} that corresponds to the given opcode value
|
||||
*
|
||||
* @param opcode The opcode value
|
||||
* @return The {@link RebaseOpcode} that corresponds to the given opcode value, or null if it
|
||||
* does not exist
|
||||
*/
|
||||
public static RebaseOpcode forOpcode(int opcode) {
|
||||
for (RebaseOpcode rebaseOpcode : RebaseOpcode.values()) {
|
||||
if (rebaseOpcode.getOpcode() == opcode) {
|
||||
return rebaseOpcode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.commands.dyld;
|
||||
|
||||
import static ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* A Mach-O rebase table
|
||||
*/
|
||||
public class RebaseTable extends OpcodeTable {
|
||||
|
||||
private List<Rebase> rebases = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates an empty {@link RebaseTable}
|
||||
*/
|
||||
public RebaseTable() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and parses a new {@link RebaseTable}
|
||||
*
|
||||
* @param reader A {@link BinaryReader reader} positioned at the start of the rebase table
|
||||
* @param header The header
|
||||
* @param tableSize The size of the table, in bytes
|
||||
* @throws IOException if an IO-related error occurs while parsing
|
||||
*/
|
||||
public RebaseTable(BinaryReader reader, MachHeader header, int tableSize) throws IOException {
|
||||
this();
|
||||
|
||||
int pointerSize = header.getAddressSize();
|
||||
long origIndex = reader.getPointerIndex();
|
||||
Rebase rebase = new Rebase();
|
||||
|
||||
while (reader.getPointerIndex() < origIndex + tableSize) {
|
||||
|
||||
opcodeOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
byte b = reader.readNextByte();
|
||||
RebaseOpcode opcode = RebaseOpcode.forOpcode(b & REBASE_OPCODE_MASK);
|
||||
int immediate = b & REBASE_IMMEDIATE_MASK;
|
||||
|
||||
switch (opcode) {
|
||||
case REBASE_OPCODE_DONE: { // 0x00
|
||||
return;
|
||||
}
|
||||
case REBASE_OPCODE_SET_TYPE_IMM: { // 0x10
|
||||
rebase.type = immediate;
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: { // 0x20
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
rebase.segmentIndex = immediate;
|
||||
rebase.segmentOffset = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_ADD_ADDR_ULEB: { // 0x30
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
rebase.segmentOffset += reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: { // 0x40
|
||||
rebase.segmentOffset += immediate * pointerSize;
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_DO_REBASE_IMM_TIMES: { // 0x50
|
||||
for (int i = 0; i < immediate; ++i) {
|
||||
rebases.add(new Rebase(rebase));
|
||||
rebase.segmentOffset += pointerSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: { // 0x60
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rebases.add(new Rebase(rebase));
|
||||
rebase.segmentOffset += pointerSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: { // 0x70
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
rebases.add(new Rebase(rebase));
|
||||
rebase.segmentOffset += reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: { // 0x80
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
ulebOffsets.add(reader.getPointerIndex() - origIndex);
|
||||
int skip = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rebases.add(new Rebase(rebase));
|
||||
rebase.segmentOffset += skip + pointerSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Rebase unknownRebase = new Rebase(rebase);
|
||||
unknownRebase.unknownOpcode = Byte.toUnsignedInt(b) & REBASE_OPCODE_MASK;
|
||||
rebases.add(unknownRebase);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the rebases}
|
||||
*/
|
||||
public List<Rebase> getRebases() {
|
||||
return rebases;
|
||||
}
|
||||
|
||||
/**
|
||||
* A piece of rebase information from a {@link RebaseTable}
|
||||
*/
|
||||
public static class Rebase {
|
||||
|
||||
private int type;
|
||||
private long segmentOffset;
|
||||
private int segmentIndex = -1;
|
||||
private Integer unknownOpcode;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Rebase}
|
||||
*/
|
||||
public Rebase() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the given {@link Rebase}
|
||||
*
|
||||
* @param rebase The {@link Rebase} to copy
|
||||
*/
|
||||
public Rebase(Rebase rebase) {
|
||||
this.segmentIndex = rebase.segmentIndex;
|
||||
this.segmentOffset = rebase.segmentOffset;
|
||||
this.type = rebase.type;
|
||||
this.unknownOpcode = rebase.unknownOpcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return The segment index}
|
||||
*/
|
||||
public int getSegmentIndex() {
|
||||
return segmentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return The segment offset}
|
||||
*/
|
||||
public long getSegmentOffset() {
|
||||
return segmentOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return The type}
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return null if the opcode is known; otherwise, returns the unknown opcode's value}
|
||||
*/
|
||||
public Integer getUnknownOpcode() {
|
||||
return unknownOpcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "segment: 0x%x, index: 0x%x, kind: %d".formatted(segmentIndex, segmentOffset,
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class MachoProgramBuilder {
|
||||
processAbsoluteSymbols();
|
||||
List<String> libraryPaths = processLibraries();
|
||||
List<Address> chainedFixups = processChainedFixups(libraryPaths);
|
||||
processBindings(false, libraryPaths);
|
||||
processDyldInfo(false, libraryPaths);
|
||||
processSectionRelocations();
|
||||
processExternalRelocations();
|
||||
processLocalRelocations();
|
||||
@@ -824,10 +824,11 @@ public class MachoProgramBuilder {
|
||||
log, monitor);
|
||||
}
|
||||
|
||||
protected void processBindings(boolean doClassic, List<String> libraryPaths) throws Exception {
|
||||
protected void processDyldInfo(boolean doClassic, List<String> libraryPaths) throws Exception {
|
||||
|
||||
List<DyldInfoCommand> commands = machoHeader.getLoadCommands(DyldInfoCommand.class);
|
||||
for (DyldInfoCommand command : commands) {
|
||||
processRebases(command.getRebaseTable());
|
||||
processBindings(command.getBindingTable(), libraryPaths);
|
||||
processBindings(command.getLazyBindingTable(), libraryPaths);
|
||||
processBindings(command.getWeakBindingTable(), libraryPaths);
|
||||
@@ -854,6 +855,10 @@ public class MachoProgramBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void processRebases(RebaseTable rebaseTable) throws Exception {
|
||||
// If we ever support rebasing a Mach-O at load time, this should get implemented
|
||||
}
|
||||
|
||||
private void processBindings(BindingTable bindingTable, List<String> libraryPaths)
|
||||
throws Exception {
|
||||
DataConverter converter = DataConverter.getInstance(program.getLanguage().isBigEndian());
|
||||
|
||||
Reference in New Issue
Block a user