private void linkPrograms(TaskMonitor monitor) throws CancelledException, MemoryAccessException,
			InvalidInputException, DuplicateNameException, IOException {

		monitor.setMaximum(programs.size());
		monitor.setProgress(1);
		for (Program program : programs) {
			monitor.checkCancelled();
			monitor.incrementProgress(1);
			monitor.setMessage(program.getName());

			DexHeader dexHeader = dexMap.get(program);

			List<Address> changeList = new ArrayList<>();
			changeMap.put(program, changeList);

			int transaction = program.startTransaction("multi-dex");
			try {
				ReferenceManager referenceManager = program.getReferenceManager();
				ExternalManager externalManager = program.getExternalManager();

				MemoryBlock methodLookupBlock = program.getMemory().getBlock("method_lookup");
				AddressSet methodLookupRange =
					new AddressSet(methodLookupBlock.getStart(), methodLookupBlock.getEnd());

				DataIterator dataIterator =
					program.getListing().getDefinedData(methodLookupRange, true);

				while (dataIterator.hasNext()) {
					Data data = dataIterator.next();

					monitor.checkCancelled();
					monitor.setMessage(program.getName() + " " + data.getMinAddress());

					if (program.getMemory().getInt(data.getMinAddress()) != -1) {
						continue;//internally linked, ignore
					}

					if (isExternalReferenceResolved(program, data, monitor)) {
						continue;
					}

					int methodIndex =
						(int) data.getMinAddress().subtract(methodLookupBlock.getStart()) / 4;

					MethodIDItem methodIDItem = dexHeader.getMethods().get(methodIndex);
					String className =
						DexUtil.convertTypeIndexToString(dexHeader, methodIDItem.getClassIndex());
					String prototype = DexUtil.convertPrototypeIndexToString(dexHeader,
						methodIDItem.getProtoIndex());
					String methodName =
						DexUtil.convertToString(dexHeader, methodIDItem.getNameIndex());

					ProgramAddress pa =
						findInOtherProgram(program, className, prototype, methodName, monitor);

					if (pa == null) {
						continue;
					}

					if (externalManager.getExternalLibraryPath(pa.program.getName()) == null) {
						externalManager.setExternalPath(pa.program.getName(),
							pa.program.getDomainFile().getPathname(), true);
					}

					referenceManager.addExternalReference(data.getMinAddress(),
						pa.program.getName(), null, pa.address, SourceType.ANALYSIS, 0,
						RefType.EXTERNAL_REF);

					changeList.add(data.getMinAddress());
				}
			}
			finally {
				program.endTransaction(transaction, true);
			}
		}
	}
Links multidex APKs together
via the "method_lookup" section using
external references.
Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/multidex/MultiDexLinker.java