private void processRelocations(OmfFileHeader header, Program program, TaskMonitor monitor,
			MessageLog log) {
		Language language = program.getLanguage();
		OmfFixupRecord.Subrecord[] targetThreads = new Subrecord[4];
		List<OmfGroupRecord> groups = header.getGroups();
		long targetAddr;		// Address of item being referred to
		Address locAddress;		// Location of data to be patched
		DataConverter converter = DataConverter.getInstance(!header.isLittleEndian());

		monitor.setMessage("Process relocations...");
		Memory memory = program.getMemory();
		for (OmfFixupRecord fixup : header.getFixups()) {
			for (Subrecord subrec : fixup.getSubrecords()) {
				if (monitor.isCancelled()) {
					break;
				}
				if (subrec.isThreadSubrecord()) {
					if (!subrec.isFrameInSubThread()) {
						targetThreads[subrec.getThreadNum()] = subrec;
					}
				}
				else {
					long finalvalue = -1;
					byte[] origbytes = null;
					int method, index, locationType = -1;
					locAddress = null;

					if (fixup.getDataBlock() == null) {
						continue;	// If no data block don't try to fixup
					}
					try {
						if (subrec.isTargetThread()) {
							Subrecord rec = targetThreads[subrec.getFixThreadNum()];
							method = subrec.getFixMethodWithSub(rec);
							index = rec.getIndex();
						}
						else {
							method = subrec.getFixMethod();
							index = subrec.getTargetDatum();
						}
						switch (method) {
							case 0:			// Index is for a segment
							case 4:			// segment only, no displacement
								targetAddr = header.resolveSegment(index).getStartAddress();
								break;
							case 1:			// Index is for a group
							case 5:			// group only, no displacement
								targetAddr = groups.get(index - 1).getStartAddress();
								break;
							case 2:			// Index is for an external symbol
							case 6:			// external only, no displacement
								OmfSymbol symbol = externsyms.get(index - 1);
								if (symbol.isFloatingPointSpecial()) {
									continue;
								}
								targetAddr = symbol.getAddress().getOffset();
								break;
							case 3:			// Not supported by many linkers
							default:
								log.appendMsg(
									"Unsupported target method " + Integer.toString(method));
								continue;
						}
						if (method < 3)
							targetAddr += subrec.getTargetDisplacement();
						locationType = subrec.getLocationType();
						OmfSegmentHeader seg =
							header.resolveSegment(fixup.getDataBlock().getSegmentIndex());
						locAddress = seg.getAddress(language)
								.add(fixup.getDataBlock().getDataOffset() +
									subrec.getDataRecordOffset());
						if (locAddress == null) {
							log.appendMsg("Couldn't find address for fixup");
							continue;
						}
						finalvalue = targetAddr;
						switch (locationType) {
							case 0: // Low-order byte
								origbytes = new byte[1];
								memory.getBytes(locAddress, origbytes);
								if (subrec.isSegmentRelative()) {
									finalvalue += origbytes[0];
								}
								else {
									finalvalue -= (locAddress.getOffset() + 1);
								}
								memory.setByte(locAddress, (byte) finalvalue);
								break;
							case 1: // 16-bit offset
							case 5: // 16-bit loader-resolved offset (treated same as 1)
								origbytes = new byte[2];
								memory.getBytes(locAddress, origbytes);
								if (subrec.isSegmentRelative()) {
									finalvalue += converter.getShort(origbytes);
								}
								else {
									finalvalue -= (locAddress.getOffset() + 2);
								}
								memory.setShort(locAddress, (short) finalvalue);
								break;
							case 2: // 16-bit base -- logical segment base (selector)
								if (!subrec.isSegmentRelative()) {
									// Segment can't be self relative
									relocationError(program, log, locAddress, locationType);
									continue;
								}
								origbytes = new byte[2];
								memory.getBytes(locAddress, origbytes);
								finalvalue += converter.getShort(origbytes) << 4;
								finalvalue >>= 4; // Convert address to segment
								memory.setShort(locAddress, (short) finalvalue);
								break;
							case 3: // 32-bit far pointer (16-bit segment:16-bit offset)
								if (!subrec.isSegmentRelative()) {
									// Far can't be self relative
									relocationError(program, log, locAddress, locationType);
									continue;
								}
								origbytes = new byte[4];
								memory.getBytes(locAddress, origbytes);
								finalvalue += converter.getInt(origbytes);
								// Convert to segment:offset in 64K blocks 
								finalvalue =
									((finalvalue & 0xffff0000L) << 12) | (finalvalue & 0xffff);
								memory.setInt(locAddress, (int) finalvalue);
								break;
							// case 11: // 48-bit far pointer (16-bit segment:32-bit offset)
							case 4: // High-order byte (high byte of 16-bit offset)
							case 9: // 32-bit offset
							case 13: // 32-bit loader-resolved offset (treated same as 9)
								origbytes = new byte[4];
								memory.getBytes(locAddress, origbytes);
								if (subrec.isSegmentRelative()) {
									finalvalue += converter.getInt(origbytes);
								}
								else {
									finalvalue -= (locAddress.getOffset() + 4);
								}
								memory.setInt(locAddress, (int) finalvalue);
								break;
							default:
								log.appendMsg("Unsupported relocation type " +
									Integer.toString(locationType) + " at 0x" +
									Long.toHexString(locAddress.getOffset()));
								break;
						}
					}
					catch (MemoryAccessException e) {
						relocationError(program, log, locAddress, locationType);
						continue;
					}
					catch (OmfException e) {
						relocationError(program, log, locAddress, locationType);
						continue;
					}
					catch (IndexOutOfBoundsException e) {
						relocationError(program, log, locAddress, locationType);
						continue;
					}
					long[] values = new long[1];
					values[0] = finalvalue;
					program.getRelocationTable()
							.add(locAddress, Status.APPLIED, locationType, values, origbytes, null);
				}
			}
		}
	}
Process an relocation (FIXUPP) records and create formal Ghidra relocation objects
@param header is the file header for the program
@param program is the Program
@param monitor is checked for cancellation
@param log receives error messages
Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java