private Integer getBaseOffset(String symbolName, String... blockNames) {

		MessageLog log = getLog();

		Symbol baseSymbol = SymbolUtilities.getLabelOrFunctionSymbol(program, symbolName,
			msg -> log.appendMsg(msg));
		if (baseSymbol != null) {
			int baseOffset = (int) baseSymbol.getAddress().getOffset();
			String absString = "";
			if (baseSymbol.isPinned()) {
				absString = "absolute ";
			}
			log.appendMsg(
				"Using " + absString + symbolName + " of 0x" + Integer.toHexString(baseOffset));
			return baseOffset;
		}

		Memory mem = program.getMemory();
		AddressSpace defaultSpace = program.getAddressFactory().getDefaultAddressSpace();
		AddressSet blockSet = new AddressSet();
		for (String blockName : blockNames) {
			MemoryBlock block = mem.getBlock(blockName);
			if (block != null) {
				if (!block.getStart().getAddressSpace().equals(defaultSpace)) {
					log.appendMsg("ERROR: " + blockName + " not in default space");
					return -1;
				}
				blockSet.add(block.getStart(), block.getEnd());
			}
		}
		if (blockSet.isEmpty()) {
			return -1;
		}

		Address baseAddr = blockSet.getMinAddress();
		long range = blockSet.getMaxAddress().subtract(baseAddr) + 1;
		if (range > Short.MAX_VALUE) {
			// use aligned midpoint of range
			baseAddr = baseAddr.add((range / 2) & ~0x0f);
		}

		try {
			program.getSymbolTable().createLabel(baseAddr, symbolName, SourceType.ANALYSIS);
		}
		catch (InvalidInputException e) {
			throw new AssertException(e);
		}

		int baseOffset = (int) baseAddr.getOffset();
		log.appendMsg("Defined " + symbolName + " of 0x" + Integer.toHexString(baseOffset));
		return baseOffset;
	}
Establish base offset from symbol or range of specified memory blocks.
@param symbolName base symbol name
@param blockNames block names which may be used to establish base range
@return base offset or -1 on failure
Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationContext.java