private void possiblyRelocateSections(Program program, CoffFileHeader header,
			Map<CoffSectionHeader, Address> map) {
		// 1. loop over all sections
		//    put all sections not at 0 into address set
		//    put all sections at 0 into "totals" map, accounting for later alignment needs
		// 2. look for space before minimum of taken addresses
		// 3. or, look for space after maximum of taken addresses

		Language language = program.getLanguage();
		AddressFactory addressFactory = program.getAddressFactory();
		AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace();

		AddressSet nonZeroSet = new AddressSet();

		int totalZeroSectionSize = 0;
		Map<String, Integer> zeroSectionSizes = new TreeMap<>();
		Map<String, Integer> zeroSectionOffsets = new TreeMap<>();

		List<CoffSectionHeader> sections = header.getSections();
		for (CoffSectionHeader section : sections) {
			int physicalAddress = section.getPhysicalAddress();
			int size = section.getSize(language);
			if (physicalAddress == 0) {
				// We don't know the exact offset now, so assume worst-case alignment penalty
				int alignedSize = size + getSectionAlignment(section) - 1;
				String name = section.getName();
				zeroSectionSizes.compute(name,
					(k, v) -> (v == null ? alignedSize : v + alignedSize));

				totalZeroSectionSize += alignedSize;
			}
			else {
				if (size > 0) {
					Address start = defaultAddressSpace.getAddress(physicalAddress);
					Address end = defaultAddressSpace.getAddress(physicalAddress + size - 1);
					if (nonZeroSet.contains(start, end)) {
						Msg.warn(this, "Section " + section.getName() +
							" overlaps another non-zero section (hope it's going in an overlay!)");
					}
					nonZeroSet.addRange(start, end);
				}
			}
		}

		Address maxAddress = nonZeroSet.getMaxAddress();
		int offset = (maxAddress == null ? EMPTY_START_OFFSET - 1
				: (int) (maxAddress.getOffset() & 0xffffffff));
		long sum = offset;
		sum += totalZeroSectionSize;
		if (sum <= 0x100000000L) {
			offset += 1;
			// Each group of sections with the same name should be aligned at least at 256 bytes
			for (Entry<String, Integer> entry : zeroSectionSizes.entrySet()) {
				offset = (offset + DEFAULT_ALIGNMENT - 1) / DEFAULT_ALIGNMENT * DEFAULT_ALIGNMENT;
				zeroSectionOffsets.put(entry.getKey(), offset);
				offset += zeroSectionSizes.get(entry.getKey());
			}
			int sectionNumber = 1;
			for (CoffSectionHeader section : sections) {
				int physicalAddress = section.getPhysicalAddress();
				if (physicalAddress == 0) {
					String name = section.getName();
					int alignment = getSectionAlignment(section);
					offset = (zeroSectionOffsets.get(name) + alignment - 1) / alignment * alignment;
					relocateSection(header, section, sectionNumber, offset);
					zeroSectionOffsets.put(name, offset + section.getSize(language));
				}
				++sectionNumber;
			}
		}
	}
Checks to see if the COFF is CLI.

@param header The COFF's headers.
@return True if the COFF is CLI; otherwise, false.
Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java