private void parseSectionBasedRelocationTable(ElfSectionHeader section,
			ArrayList<ElfRelocationTable> relocationTableList) throws IOException {
		try {
			int sectionHeaderType = section.getType();
			if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL ||
				sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
				sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR ||
				sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
				sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA ||
				sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) {

				for (ElfRelocationTable relocTable : relocationTableList) {
					if (relocTable.getFileOffset() == section.getOffset()) {
						return; // skip reloc table previously parsed as dynamic entry
					}
				}

				if (section.isInvalidOffset()) {
					Msg.debug(this, "Skipping Elf relocation table section with invalid offset " +
						section.getNameAsString());
					return;
				}

				int link = section.getLink(); // section index of associated symbol table
				int info = section.getInfo(); // section index of section to which relocations apply (relocation offset base)

				ElfSectionHeader sectionToBeRelocated = info != 0 ? getLinkedSection(info) : null;
				String relocaBaseName =
					sectionToBeRelocated != null ? sectionToBeRelocated.getNameAsString()
							: "PT_LOAD";

				ElfSectionHeader symbolTableSection;
				if (link == 0) {
					// dynamic symbol table assumed when link section value is 0
					symbolTableSection = getSection(ElfSectionHeaderConstants.dot_dynsym);
				}
				else {
					symbolTableSection = getLinkedSection(link,
						ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB);
				}

				ElfSymbolTable symbolTable = getSymbolTable(symbolTableSection);

				boolean addendTypeReloc =
					(sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
						sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA);

				String details = "Elf relocation table section " + section.getNameAsString();
				if (symbolTableSection != null) {
					details +=
						" linked to symbol table section " + symbolTableSection.getNameAsString();
				}
				details += " affecting " + relocaBaseName;
				Msg.debug(this, details);

				ElfRelocationTable.TableFormat format = TableFormat.DEFAULT;
				if (sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
					sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
					format = TableFormat.ANDROID;
				}
				else if (sectionHeaderType == ElfSectionHeaderConstants.SHT_RELR ||
					sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELR) {
					format = TableFormat.RELR;
				}

				ElfRelocationTable relocTable =
					new ElfRelocationTable(reader, this, section, section.getOffset(),
						section.getAddress(), section.getSize(), section.getEntrySize(),
						addendTypeReloc, symbolTable, sectionToBeRelocated, format);

				relocationTableList.add(relocTable);
			}
		}
		catch (NotFoundException e) {
			errorConsumer.accept("Failed to process relocation section " +
				section.getNameAsString() + ": " + e.getMessage());
		}
	}
Unadjust address offset for certain pre-linked binaries which do not adjust certain
header fields (e.g., dynamic table address entries).  This may be needed when updating
a header address field which requires pre-link adjustment.
@param address prelink-adjusted address offset
@return address with appropriate pre-link adjustment subtracted
Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java