Java Code Examples for ghidra.program.model.address.Address#compareTo()

The following examples show how to use ghidra.program.model.address.Address#compareTo() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: SequenceRange.java    From ghidra with Apache License 2.0 6 votes vote down vote up
public boolean contains(SequenceNumber seq) {
	Address addr = seq.getTarget();
	int index = seq.getTime();
	Address startAddr = start.getTarget();
	int startIndex = start.getTime();
	Address endAddr = end.getTarget();
	int endIndex = end.getTime();
	int c = addr.compareTo(startAddr);
	if (c == 0) {
		c = index - startIndex;
	}
	if (c < 0) {
		return false;
	}
	c = addr.compareTo(endAddr);
	if (c == 0) {
		c = index - endIndex;
	}
	return c <= 0;
}
 
Example 2
Source File: CombinedStringSearcher.java    From ghidra with Apache License 2.0 6 votes vote down vote up
/** returns 0 if the strings (they represent address ranges) have any overlap */
private int compareRange(FoundString string1, FoundString string2) {
	if (string1 == null) {  // for this purpose, null are larger than non nulls
		return 1;
	}
	else if (string2 == null) {
		return -1;
	}

	Address end1 = string1.getEndAddress();
	Address start2 = string2.getAddress();
	if (end1.compareTo(start2) < 0) {
		return -1;
	}

	Address start1 = string1.getAddress();
	Address end2 = string2.getEndAddress();
	if (end2.compareTo(start1) < 0) {
		return 1;
	}

	return 0;
}
 
Example 3
Source File: AddRemoveAddressRangeDialog.java    From ghidra with Apache License 2.0 6 votes vote down vote up
private boolean isValidRange() {
	Address minAddress = getMinAddress();
	if (minAddress == null) {
		setStatusText("Specify a minimum address.");
		return false;
	}
	Address maxAddress = getMaxAddress();
	if (maxAddress == null) {
		setStatusText("Specify a maximum address.");
		return false;
	}
	if (!minAddress.getAddressSpace().equals(maxAddress.getAddressSpace())) {
		setStatusText("Min and Max must be in same address space.");
		return false;
	}
	if (minAddress.compareTo(maxAddress) > 0) {
		setStatusText("Max address must be greater than Min address.");
		return false;
	}
	return true;
}
 
Example 4
Source File: MessageDigestFidHasher.java    From ghidra with Apache License 2.0 6 votes vote down vote up
private static boolean hasRelocation(Mask mask,Address minAddress,Address maxAddress,RelocationTable relocationTable) {
	byte[] bytes = mask.getBytes();
	for (byte b : bytes) {
		if (b != 0) {
			break;
		}
		minAddress = minAddress.addWrap(1);
	}
	for (int jj = bytes.length - 1; jj >= 0; --jj) {
		if (bytes[jj] != 0) {
			break;
		}
		maxAddress = maxAddress.subtract(1);
	}
	if (minAddress.compareTo(maxAddress) <= 0) {
		AddressSet range = new AddressSet(minAddress, maxAddress);
		Iterator<Relocation> relocations = relocationTable.getRelocations(range);
		if (relocations.hasNext()) {
			return true;
		}
	}
	return false;
}
 
Example 5
Source File: OmfLoader.java    From ghidra with Apache License 2.0 6 votes vote down vote up
/**
 * If necessary, create an external block to hold external symbols for this file 
 * @param program is the program representing the file
 * @param log for error messages
 * @param externalAddress is the address of the first byte of the external block
 * @param externalAddressStart is the address of the last byte (+1)
 */
private void createExternalBlock(Program program, MessageLog log, Address externalAddress,
		Address externalAddressStart) {
	//create an artificial block for the external symbols
	if (!externalAddressStart.equals(externalAddress)) {
		long size = externalAddress.subtract(externalAddressStart);
		try {
			MemoryBlock block = program.getMemory().createUninitializedBlock("EXTERNAL",
				externalAddressStart, size, false);

			// assume any value in external is writable.
			block.setWrite(true);

			Address current = externalAddressStart;
			while (current.compareTo(externalAddress) < 0) {
				createUndefined(program.getListing(), program.getMemory(), current,
					externalAddress.getAddressSpace().getPointerSize());
				current = current.add(externalAddress.getAddressSpace().getPointerSize());
			}
		}
		catch (Exception e) {
			log.appendMsg("Error creating external memory block: " + " - " + e.getMessage());
		}
	}
}
 
Example 6
Source File: OmfLoader.java    From ghidra with Apache License 2.0 6 votes vote down vote up
/**
 * Locate the start of a free range of memory (for holding external symbols)
 * by finding an Address beyond any memory block in the program
 * @param program is the Program
 * @return the starting address of the free region
 */
private Address findFreeAddress(Program program) {
	Memory memory = program.getMemory();
	// Don't consider overlay blocks for max addr
	Address maxAddr = memory.getMinAddress();
	if (maxAddr == null) {
		return null;
	}
	MemoryBlock[] blocks = memory.getBlocks();
	for (MemoryBlock block : blocks) {
		// get the physical address in case it is an overlay address
		Address blockEnd = block.getEnd().getPhysicalAddress();
		if (blockEnd.compareTo(maxAddr) > 0) {
			maxAddr = blockEnd;
		}
	}

	// Always Align the fake External Address Space
	Address externAddress = null;
	long newOffset = (maxAddr.getOffset() + 0x1000) & 0xfffffffffffff000L;
	externAddress = maxAddr.getNewAddress(newOffset);
	return externAddress;
}
 
Example 7
Source File: ObjectiveC1_ClassAnalyzer.java    From ghidra with Apache License 2.0 5 votes vote down vote up
private void processProtocols(ObjectiveC1_State state, BinaryReader reader) throws Exception {
	state.monitor.setMessage("Objective-C Protocols...");

	MemoryBlock block =
		state.program.getMemory().getBlock(ObjectiveC1_Constants.OBJC_SECTION_PROTOCOL);
	if (block == null) {
		return;
	}

	state.monitor.initialize((int) block.getSize());

	Address address = block.getStart();

	reader.setPointerIndex(block.getStart().getOffset());

	while (address.compareTo(block.getEnd()) < 0) {
		if (state.monitor.isCancelled()) {
			break;
		}
		state.monitor.setProgress((int) address.subtract(block.getStart()));

		ObjectiveC1_Protocol protocol = new ObjectiveC1_Protocol(state, reader);
		protocol.applyTo();

		address = address.add(ObjectiveC1_Protocol.SIZEOF);
	}
}
 
Example 8
Source File: AbstractVTMatchTableModel.java    From ghidra with Apache License 2.0 5 votes vote down vote up
@Override
public int compare(VTMatch o1, VTMatch o2) {
	VTAssociation association1 = o1.getAssociation();
	VTAssociation association2 = o2.getAssociation();
	Address address1 = association1.getSourceAddress();
	Address address2 = association2.getSourceAddress();
	return address1.compareTo(address2);
}
 
Example 9
Source File: ChooseDataTypeAction.java    From ghidra with Apache License 2.0 5 votes vote down vote up
private int getMaxSize(Program program, Address addr) {

		// can't go past the end of a block to start with
		Address maxAddr = program.getMemory().getBlock(addr).getEnd();

		// get the next non undefined element in memory
		Instruction instr = program.getListing().getInstructionAfter(addr);
		if (instr != null) {
			Address instrAddr = instr.getMinAddress();
			if (instrAddr.compareTo(maxAddr) < 0) {
				maxAddr = instrAddr.subtract(1);
			}
		}

		Data data = DataUtilities.getNextNonUndefinedDataAfter(program, addr, maxAddr);
		if (data != null) {
			Address dataAddr = data.getMinAddress();
			if (dataAddr.compareTo(maxAddr) < 0) {
				maxAddr = dataAddr.subtract(1);
			}
		}

		long length = maxAddr.subtract(addr) + 1;
		SystemUtilities.assertTrue(length > 0,
			"Subtraction an address from the max address in its block should never be negative");
		return length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length;
	}
 
Example 10
Source File: OdexHeaderFormatAnalyzer.java    From ghidra with Apache License 2.0 5 votes vote down vote up
private void processDeps(Program program, OdexHeader header,
		TaskMonitor monitor, MessageLog log) throws Exception {

	int depsOffset = header.getDepsOffset();
	int depsLength = header.getDepsLength();

	Address depsAddress = toAddr( program, depsOffset );
	Address depsEndAddress = depsAddress.add( depsLength );

	createData( program, depsAddress, new DWordDataType() );
	depsAddress = depsAddress.add( 4 );

	createData( program, depsAddress, new DWordDataType() );
	depsAddress = depsAddress.add( 4 );

	createData( program, depsAddress, new DWordDataType() );
	depsAddress = depsAddress.add( 4 );

	createData( program, depsAddress, new DWordDataType() );
	depsAddress = depsAddress.add( 4 );

	while ( depsAddress.compareTo(depsEndAddress) < 0 ) {
		monitor.checkCanceled();

		createData( program, depsAddress, new DWordDataType() );
		int stringLength = program.getMemory().getInt(depsAddress);
		depsAddress = depsAddress.add( 4 );

		program.getListing().createData(depsAddress, new StringDataType(), stringLength);
		depsAddress = depsAddress.add( stringLength );

		for ( int i = 0; i < 5; ++i ) {
			createData( program, depsAddress, new DWordDataType() );
			depsAddress = depsAddress.add( 4 );
		}
	}
}
 
Example 11
Source File: DisambiguateByParentWithOrder.java    From ghidra with Apache License 2.0 5 votes vote down vote up
@Override
public ArrayList<Hash> calcHashes(InstructHash instHash, int matchSize, HashStore store) throws CancelledException {
	ArrayList<Hash> res = new ArrayList<Hash>();
	Block block = instHash.getBlock();
	CodeBlockReferenceIterator iter = block.origBlock.getSources(store.getMonitor());
	Address startAddr = block.origBlock.getMinAddress();
	while(iter.hasNext()) {			// Looking at each parent of -block- in turn
		CodeBlockReference ref = iter.next();
		Block srcBlock = store.getBlock(ref.getSourceAddress());
		if (srcBlock != null && srcBlock.getMatchHash() != 0) {
			CodeBlockReferenceIterator srcIter = srcBlock.origBlock.getDestinations(store.getMonitor());
			// Figure out the index of -block- within all blocks out of parent, sorted by address
			int totalcount = 0;
			int count = 0;
			while(srcIter.hasNext()) {
				Address addr = srcIter.next().getDestinationAddress();
				totalcount += 1;
				if (addr.compareTo(startAddr) < 0)	// If child is earlier than -block-
					count += 1;						//   increment index
			}
			if (totalcount <= 1) continue;			// If no siblings, this does no better than ParentStrategy
			count = SimpleCRC32.hashOneByte(srcBlock.getMatchHash(), count);	// Mix order index
			res.add(new Hash(count,1));											//   into disambiguation hash
		}
	}
	return res;
}
 
Example 12
Source File: MachoPrelinkProgramBuilder.java    From ghidra with Apache License 2.0 5 votes vote down vote up
/**
 * Fixes up any chained pointers.  Relies on the __thread_starts section being present.
 * 
 * @return A list of addresses where pointer fixes were performed.
 * @throws MemoryAccessException if there was a problem reading/writing memory.
 */
private List<Address> fixupChainedPointers() throws MemoryAccessException {

	Section threadStarts = machoHeader.getSection(SegmentNames.SEG_TEXT, "__thread_starts");
	if (threadStarts == null) {
		return Collections.emptyList();
	}

	monitor.setMessage("Fixing up chained pointers...");

	List<Address> fixedAddresses = new ArrayList<>();
	Address threadSectionStart = space.getAddress(threadStarts.getAddress());
	Address threadSectionEnd = threadSectionStart.add(threadStarts.getSize() - 1);

	long nextOffSize = (memory.getInt(threadSectionStart) & 1) * 4 + 4;
	Address chainHead = threadSectionStart.add(4);

	while (chainHead.compareTo(threadSectionEnd) < 0 && !monitor.isCancelled()) {
		int headStartOffset = memory.getInt(chainHead);
		if (headStartOffset == 0xFFFFFFFF || headStartOffset == 0) {
			break;
		}

		Address chainStart = program.getImageBase().add(headStartOffset & 0xffffffffL);
		fixedAddresses.addAll(processPointerChain(chainStart, nextOffSize));
		chainHead = chainHead.add(4);
	}

	log.appendMsg("Fixed up " + fixedAddresses.size() + " chained pointers.");
	return fixedAddresses;
}
 
Example 13
Source File: SearchBaseExtended.java    From ghidra with Apache License 2.0 5 votes vote down vote up
private void findLocations(MaskValueCase searchArrays, ArrayList<Case> localDatabase) {

		if (currentProgram == null || localDatabase == null || searchArrays == null) {
			throw new IllegalArgumentException("Null Data-Structure");
		}
		if (searchArrays.mask.length != searchArrays.value.length) {
			throw new IllegalArgumentException("Mask and value lengths are different.");
		}

		if (containsOnBit(searchArrays.mask)) {
			Memory mem = currentProgram.getMemory();

			//Gets the start and end address to search through
			Address endAddress = currentProgram.getMaxAddress();

			Address currentPosition = currentProgram.getMinAddress();
			while (currentPosition.compareTo(endAddress) < 0) {

				//Searches memory for the given mask and value.
				currentPosition = mem.findBytes(currentPosition, endAddress, searchArrays.value,
					searchArrays.mask, true, monitor);

				//Determines if a new location was found.
				if (currentPosition == null) {
					break;
				}

				Case temp = new Case();
				temp.mask = searchArrays.mask;
				temp.value = searchArrays.value;
				temp.addr = currentPosition;
				localDatabase.add(temp);

				currentPosition = currentPosition.add(1);
			}
		}
		else {
			return;
		}
	}
 
Example 14
Source File: FunctionTagComparator.java    From ghidra with Apache License 2.0 5 votes vote down vote up
/** Compares two function tag lists to determine whether the first 
 *  tag address is effectively less than (comes before it in memory), 
 *  equal to (at the same spot in memory), or greater than (comes after 
 *  it in memory) the second comment's address.
 *  
 * @param obj1 the address for the first program's tag.
 * @param obj2 the address for the second program's tag.
 * @return -1 if the first comes before the second in memory. 
 *          0 if the objects are at the same spot in memory.
 *          1 if the first comes after the second in memory.
 */
@Override
public int compare(Object o1, Object o2) {
	FunctionDB f1 = (FunctionDB) o1;
	FunctionDB f2 = (FunctionDB) o2;

	Address a1 = f1.getEntryPoint();
	Address a2 = f2.getEntryPoint();

	Address address2CompatibleWith1 =
		SimpleDiffUtility.getCompatibleAddress(program2, a2, program1);
	return a1.compareTo(address2CompatibleWith1);
}
 
Example 15
Source File: SearchBaseExtended.java    From ghidra with Apache License 2.0 4 votes vote down vote up
public void loadSelectedInstructions() {
	if (currentProgram == null || currentSelection == null) {
		return;
	}

	try {
		//Builds object that is used to extract all the instructions masks and values
		SleighDebugLogger logger = null;

		//Grabs the AddressRange for the first continuous selection of instructions
		AddressRange addrRange = currentSelection.getFirstRange();
		if (addrRange == null) {
			return;
		}//makes sure that something was returned

		//Creates a list that is used to determine the location of the instructions starting byte
		Listing list = currentProgram.getListing();

		Address tempAddr = addrRange.getMinAddress();//sets the beginning scan address

		/*
		 * The purpose of this while loop is to iterate through the memory that is currently selected by user. 
		 * All the instructions within this selection range are extracted and corresponding masks made from them.
		 * These masks will then be used to search through memory to find instructions of the same type.
		 */
		while (tempAddr.compareTo(addrRange.getMaxAddress()) <= 0) {

			//Determines if current location is start of instruction, tempIns will be null if not beginning of instruction
			Instruction tempIns = list.getInstructionAt(tempAddr);

			if (tempIns != null) {//means that current address is start of an instruction

				logger =
					new SleighDebugLogger(currentProgram, tempAddr, SleighDebugMode.VERBOSE);
				if (logger.parseFailed()) {
					break;
				}

				//This takes care of the headers
				byte[] mask = logger.getInstructionMask();
				byte[] value = logger.getMaskedBytes(mask);
				if (mask == null || value == null) {
					break;
				}//need to move on to next byte, not sure if this is right command to use

				//Builds a structure representing the recently found instruction mask and value
				Case tCase = new Case();
				tCase.mask = mask;
				tCase.value = value;
				tCase.textRep = tempIns.getMnemonicString();
				mnemonics.add(tCase); //adds the mnemonic mask and value to the arraylist

				//Gets a code unit which can be used to determine if the operands are constants.
				CodeUnit cu = list.getCodeUnitAt(tempAddr);

				//Iterates through all the operands for the currently selected instruction and stores them accordingly
				for (int x = 1; x <= logger.getNumOperands(); x++) {
					mask = logger.getOperandValueMask(x - 1);
					value = logger.getMaskedBytes(mask);

					if (mask == null || value == null) {
						break;
					}//move on to next instruction

					//Builds case to store the operands mask and value
					OperandCase otCase = new OperandCase();
					otCase.mask = mask;
					otCase.value = value;
					//Object hey = tempIns.getDefaultOperandRepresentationList(x-1);
					otCase.textRep = tempIns.getDefaultOperandRepresentation(x - 1);

					//Determines if the given operand is a constant value. If it is a constant then proper flag is set.
					if (cu.getScalar(x - 1) != null) {
						otCase.constant = true;
					}

					//Determines if current structure is large enough to hold new operand, if it isn't increases structure size
					if (ops.size() < x && ops.size() > -1) {
						ops.add(new LinkedHashMap<Case, OperandCase>());
					}

					//Adds the operand to the data-structure with a mapping to the instruction mnemonic extracted earlier in line 87
					ops.get(x - 1).put(tCase, otCase);
				}
				//Increments the address pointer to point to the beginning of next instruction.
				tempAddr = tempAddr.add(tempIns.getLength());
			}
			else {

				//Increments the address pointer by 1
				//This would be hit if the tempAddr didn't get offset correctly.
				tempAddr.addWrap(1);
			}
		}
	}
	catch (Exception e) {
		println(e.getMessage());
	}
}
 
Example 16
Source File: DebugFrameSection.java    From ghidra with Apache License 2.0 4 votes vote down vote up
private List<RegionDescriptor> analyzeSection(MemoryBlock curMemBlock)
		throws MemoryAccessException, AddressOutOfBoundsException,
		ExceptionHandlerFrameException {

	monitor.setMessage("Analyzing " + curMemBlock.getName() + " section");
	monitor.setShowProgressValue(true);
	monitor.setIndeterminate(false);

	ProgramLocation loc = new ProgramLocation(program, curMemBlock.getStart());
	Address curAddress = loc.getAddress();

	List<RegionDescriptor> regions = new ArrayList<>();

	if (curAddress != null) {
		monitor.setMaximum(curMemBlock.getEnd().subtract(curAddress));
	}

	while (curAddress != null && curAddress.compareTo(curMemBlock.getEnd()) < 0) {
		if (monitor.isCancelled()) {
			return regions;
		}

		/* Get the Common Information Entry */
		Cie cie = getCie(curAddress);

		/* Check for the end of the frame record. */
		if (cie.isEndOfFrame()) {
			break;
		}

		curAddress = cie.getNextAddress();

		/* 
		 * Add each Frame Description Entry (FDE) for the current CIE.
		 */
		List<RegionDescriptor> newRegions = new ArrayList<>();

		while (curAddress != null && (curAddress.compareTo(curMemBlock.getEnd()) < 0)) {

			monitor.setProgress(curAddress.subtract(loc.getAddress()));

			Address currFdeAddr = curAddress;

			try {

				FrameDescriptionEntry fde = new FrameDescriptionEntry(monitor, program, this);
				RegionDescriptor region = fde.create(curAddress);

				if (fde.isEndOfFrame()) {
					break;
				}

				if (region != null) {
					newRegions.add(region);
					createFdeComment(curAddress);
				}

				curAddress = fde.getNextAddress(); // This can be null.

			}
			catch (ExceptionHandlerFrameException efe) {
				// May have run into another CIE.
				curAddress = currFdeAddr;
				break;
			}
		}

		createAugmentationData(newRegions, cie);

		regions.addAll(newRegions);
	}
	return regions;
}
 
Example 17
Source File: FdeTable.java    From ghidra with Apache License 2.0 4 votes vote down vote up
/**
 * Creates an FDE Table at the specified Address.
 * 
 * @param addr Address at which the FDE Table should be created.
 * @param decoder the decoder for DWARF encoded exception handling information
 * @param fdeTableCnt the number of exception handler FDEs.
 * @throws MemoryAccessException if the needed memory can't be read.
 * @throws ExceptionHandlerFrameException if the FDE table can't be decoded.
 */
public void create(Address addr, DwarfEHDecoder decoder, long fdeTableCnt)
		throws MemoryAccessException, ExceptionHandlerFrameException {
	CreateStructureCmd dataCmd = null;
	long curFdeTableCnt = 0;
	
	if (addr == null || decoder == null || monitor.isCancelled()) {
		return;
	}
	
	initFdeTableDataType(decoder);
	
	monitor.setMessage("Creating Frame Description Table Entries");
	monitor.setShowProgressValue(true);
	monitor.setIndeterminate(false);
	monitor.initialize(fdeTableCnt);

	/* Create a new FDE structures beginning at startAddress */
	MemoryBlock curMemBlock = prog.getMemory().getBlock(".eh_frame_hdr");
	while( curMemBlock != null &&
		  (addr.compareTo( curMemBlock.getEnd()) < 0) && 
		  (curFdeTableCnt < fdeTableCnt) )
	{
		/* Create a new FDE structure */
		dataCmd = new CreateStructureCmd( fdeTableEntry, addr);
		dataCmd.applyTo(prog);
		
		/*
		 * -- Create references to the 'initial location' and 'data
		 * location' --
		 */
		Data fdeTableData = prog.getListing().getDataAt(addr);
		Structure fdeStruct = (Structure) fdeTableData.getDataType();

		DataTypeComponent locComponent = fdeStruct.getComponent(0);
		Address locComponentAddr = addr.add(locComponent.getOffset());
		DwarfDecodeContext locDecodeContext =
			new DwarfDecodeContext(prog, locComponentAddr, curMemBlock);
		Address locAddr = decoder.decodeAddress(locDecodeContext);

		// this is an indirect reference to code from the table,
		//  so tag reference as an indirect code flow
		prog.getReferenceManager().addMemoryReference(locComponentAddr, locAddr,
			RefType.INDIRECTION,
			SourceType.ANALYSIS, 0);

		DataTypeComponent dataComponent = fdeStruct.getComponent(1);
		Address dataComponentAddr = addr.add(dataComponent.getOffset());
		DwarfDecodeContext dataDecodeContext =
			new DwarfDecodeContext(prog, dataComponentAddr, curMemBlock);
		Address dataAddr = decoder.decodeAddress(dataDecodeContext);

		prog.getReferenceManager().addMemoryReference(dataComponentAddr, dataAddr, RefType.DATA,
				SourceType.ANALYSIS, 0);

		/* Increment curAddress by number of bytes in a FDE Table entry */
		curFdeTableCnt++;
		addr = addr.add(fdeTableEntry.getLength());

		monitor.incrementProgress(1);
	}
}
 
Example 18
Source File: StringEvent.java    From ghidra with Apache License 2.0 4 votes vote down vote up
public Address getMaxAddress(Address addr1, Address addr2) {
	if (addr1.compareTo(addr2) > 0) {
		return addr1;
	}
	return addr2;
}
 
Example 19
Source File: IterateFunctionsByAddressScript.java    From ghidra with Apache License 2.0 3 votes vote down vote up
private void iterateBackward() {
	Address minAddress = currentProgram.getMinAddress();

	Address address = currentProgram.getMaxAddress();

	int count = 0;
	while (address.compareTo(minAddress) >= 0) {

		if (monitor.isCancelled()) {
			break;
		}

		Function function = getFunctionBefore(address);

		if (function == null) {
			break;
		}

		String string = count + "  :  " + function.getName() + " @ " + function.getEntryPoint();

		monitor.setMessage(string);

		println(string);

		address = function.getEntryPoint();

		count++;
	}
	println("found " + count + " functions ");
}
 
Example 20
Source File: MultiCodeUnitIterator.java    From ghidra with Apache License 2.0 2 votes vote down vote up
/** Determines whether the first code unit's minimum address is less 
 *  than, equal to, or greater than the second's.
 * @param cu1 the first code unit.
 * @param cu2 the second code unit.
 * @return -1 if less than, 0 if equal to, or 1 if greater than.
 */
private int compareAddress(CodeUnit cu1, CodeUnit cu2) {
	Address addr1 = cu1.getMinAddress();
	Address addr2 = cu2.getMinAddress();
	return addr1.compareTo(addr2);
}