private void processRelocations(ContainerHeader header, Program program,
			ImportStateCache importState, MessageLog log, TaskMonitor monitor) throws IOException {
		List<LoaderRelocationHeader> relocationHeaders = header.getLoader().getRelocations();
		for (LoaderRelocationHeader relocationHeader : relocationHeaders) {
			if (monitor.isCancelled()) {
				return;
			}
			RelocationState state =
				new RelocationState(header, relocationHeader, program, importState);
			List<Relocation> relocations = relocationHeader.getRelocations();
			int relocationIndex = 0;
			int numRepeats = 0;
			int jumpToIdx = -1;
			while (relocationIndex < relocations.size()) {
				if (monitor.isCancelled()) {
					return;
				}
				if (relocationIndex % 100 == 0) {
					monitor.setMessage(
						"Processing relocation " + relocationIndex + " of " + relocations.size());
				}

				Relocation relocation = relocations.get(relocationIndex);
				relocation.apply(importState, state, header, program, log, monitor);

				if (relocation.getRepeatCount() != 0) {
					numRepeats++;

					if (numRepeats < relocation.getRepeatCount()) {
						if (jumpToIdx != -1) {
							relocationIndex = jumpToIdx;
							continue;
						}

						int blocksBack = 0;
						jumpToIdx = relocationIndex;
						while (blocksBack < relocation.getRepeatChunks()) {
							jumpToIdx--;
							blocksBack += relocations.get(jumpToIdx).getSizeInBytes() / 2;
						}

						if (blocksBack != relocation.getRepeatChunks()) {
							throw new IOException("specified number of repeat chunks does not point to the start of a relocation command!");
						}

						continue;

					} else {
						/* done looping */
						numRepeats = 0;
						jumpToIdx = -1;
					}
				}

				++relocationIndex;
			}
			state.dispose();
		}
	}
TODO determine how to correctly identify TOC location
Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PefLoader.java