public void pack() throws IOException, CancelledException {

		// Keep track of each segment's file offset in the container.
		// Also keep a running total of each segment's size so we know how big to make our
		// packed array.
		int packedSize = 0;
		int packedLinkEditSize = 0;
		for (SegmentCommand segment : machoHeader.getAllSegments()) {
			monitor.checkCancelled();

			packedSegmentStarts.put(segment, packedSize);

			// The __LINKEDIT segment is shared across all Mach-O's, so it is very large.  We
			// Want to create a new packed __LINKEDIT segment with only the relevant info for
			// the Mach-O we are extracting, resulting in a significantly smaller file.
			if (segment == linkEditSegment) {
				for (LoadCommand cmd : machoHeader.getLoadCommands()) {
					if (cmd instanceof SymbolTableCommand symbolTable) {
						symbolTable.addSymbols(getExtraSymbols());
					}
					long offset = cmd.getLinkerDataOffset();
					long size = cmd.getLinkerDataSize();
					if (offset == 0 || size == 0) {
						continue;
					}
					packedLinkEditDataStarts.put(cmd, packedLinkEditSize);
					packedLinkEditSize += size;
				}
				packedSize += packedLinkEditSize;
				segment.setFileSize(packedLinkEditSize);
				segment.setVMsize(packedLinkEditSize);
			}
			else {
				packedSize += segment.getFileSize();
			}

			// Some older containers use a file offset of 0 for their __TEXT segment, despite 
			// being in the middle of the container and despite the other segments using 
			// absolute cache file offsets. Adjust these segments to be consistent with all the 
			// other segments, and store their adjustment values so we can later work with them
			// as absolute container file offsets.
			if (segment == textSegment && segment.getFileOffset() == 0) {
				segment.setFileOffset(providerOffset);
				packedSegmentAdjustments.put(segment, (int) providerOffset);
			}
		}

		// Account for the size of the footer
		packedSize += footer.length;

		packed = new byte[packedSize];

		// Copy each segment into the packed array (leaving no gaps)
		for (SegmentCommand segment : machoHeader.getAllSegments()) {
			monitor.checkCancelled();
			long segmentSize = segment.getFileSize();
			ByteProvider segmentProvider = getSegmentProvider(segment);
			if (segment.getFileOffset() + segmentSize > segmentProvider.length()) {
				segmentSize = segmentProvider.length() - segment.getFileOffset();
				Msg.warn(this, segment.getSegmentName() +
					" segment extends beyond end of file.  Truncating...");
			}
			byte[] bytes;
			if (segment == linkEditSegment) {
				bytes = createPackedLinkEditSegment(segmentProvider, packedLinkEditSize);
				adjustLinkEditAddress();
			}
			else {
				bytes = segmentProvider.readBytes(segment.getFileOffset(), segmentSize);
			}
			System.arraycopy(bytes, 0, packed, packedSegmentStarts.get(segment), bytes.length);
		}

		// Fixup various fields in the packed array
		fixupLoadCommands();

		// Add footer
		System.arraycopy(footer, 0, packed, packed.length - footer.length, footer.length);
	}
Performs the packing

@throws IOException If there was an IO-related error
@throws CancelledException If the user cancelled the operation
Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/ExtractedMacho.java