Loading...
--- dyld/dyld-1340/mach_o/Universal.cpp
+++ dyld/dyld-1162/mach_o/Universal.cpp
@@ -54,7 +54,7 @@
const Universal* fileStartAsFat = (Universal*)fileContent.data();
uint32_t headerFirstFourBytes;
- memcpy(&headerFirstFourBytes, (uint32_t*)fileStartAsFat, 4); // use memcpy to avoid UB if content (such as in static lib) is not aligned
+ memcpy(&headerFirstFourBytes, fileStartAsFat, 4); // use memcpy to avoid UB if content (such as in static lib) is not aligned
if ( (headerFirstFourBytes == OSSwapBigToHostInt32(FAT_MAGIC)) || (headerFirstFourBytes == OSSwapBigToHostInt32(FAT_MAGIC_64)) )
return fileStartAsFat;
else
@@ -243,6 +243,118 @@
return false;
}
+//
+// MARK: --- methods when creating a fat file ---
+//
+
+#if BUILDING_MACHO_WRITER
+
+// FIXME: fill out align field of fat header
+// FIXME: compute slice alignment based on mach_header type and cpu type
+// FIXME: sort slices by alignment
+const Universal* Universal::make(std::span<const Header*> mhs, bool forceFat64, bool arm64offEnd)
+{
+ Slice slices[mhs.size()];
+ for ( size_t i = 0; i < mhs.size(); ++i ) {
+ const Header* header = mhs[i];
+ Slice& slice = slices[i];
+ slice.arch = header->arch();
+ slice.buffer = std::span((const uint8_t*)header, header->fileSize());
+ }
+
+ return make(std::span(slices, mhs.size()), forceFat64, arm64offEnd);
+}
+
+const Universal* Universal::make(std::span<const Universal::Slice> slices, bool forceFat64, bool arm64offEnd)
+{
+ // compute number of slices and total size
+ uint64_t totalSize = 0x4000;
+ int32_t count = 0;
+ for (const Universal::Slice& slice : slices) {
+ ++count;
+ totalSize += slice.buffer.size();
+ pageAlign16K(totalSize);
+ }
+
+ // allocate buffer
+ vm_address_t newAllocationAddr;
+ if ( ::vm_allocate(mach_task_self(), &newAllocationAddr, (size_t)totalSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
+ return nullptr;
+
+ // make fat header
+ Universal* result = (Universal*)newAllocationAddr;
+ bool fat64 = forceFat64 || (totalSize > 0x100000000ULL);
+ if ( fat64 ) {
+ result->fh.magic = OSSwapHostToBigInt32(FAT_MAGIC_64);
+ result->fh.nfat_arch = OSSwapHostToBigInt32(count);
+ }
+ else {
+ result->fh.magic = OSSwapHostToBigInt32(FAT_MAGIC);
+ if ( arm64offEnd && (slices[count-1].arch == Architecture::arm64) )
+ result->fh.nfat_arch = OSSwapHostToBigInt32(count-1); // hide arm64 slice off end of array
+ else
+ result->fh.nfat_arch = OSSwapHostToBigInt32(count);
+ }
+
+ // add entry and copy each slice into buffer
+ fat_arch* entry32 = (fat_arch*) ((uint8_t*)result + sizeof(fat_header));
+ fat_arch_64* entry64 = (fat_arch_64*)((uint8_t*)result + sizeof(fat_header));
+ uint64_t currentOffset = 0x4000;
+ for (const Universal::Slice& slice : slices) {
+ uint64_t sliceSize = slice.buffer.size();
+ if ( fat64 ) {
+ slice.arch.set(*entry64);
+ entry64->offset = OSSwapHostToBigInt64(currentOffset);
+ entry64->size = OSSwapHostToBigInt64(sliceSize);
+ entry64->align = OSSwapHostToBigInt32(0x4000);
+ entry64->reserved = 0;
+ ++entry64;
+ }
+ else {
+ slice.arch.set(*entry32);
+ entry32->offset = OSSwapHostToBigInt32((uint32_t)currentOffset);
+ entry32->size = OSSwapHostToBigInt32((uint32_t)sliceSize);
+ entry32->align = OSSwapHostToBigInt32(0x4000);
+ ++entry32;
+ }
+ memcpy((uint8_t*)newAllocationAddr+currentOffset, slice.buffer.data(), slice.buffer.size());
+ currentOffset += sliceSize;
+ pageAlign16K(currentOffset);
+ }
+ return result;
+}
+
+uint64_t Universal::size() const
+{
+ int currSliceCount = OSSwapBigToHostInt32(fh.nfat_arch);
+ if ( currSliceCount == 0 )
+ return 0x4000;
+
+ __block uint64_t endOffset = 0;
+ this->forEachSlice(^(Architecture arch, uint64_t sliceOffset, uint64_t sliceSize, bool& stop) {
+ endOffset = sliceOffset + sliceSize;
+ });
+ pageAlign16K(endOffset);
+ return endOffset;
+}
+
+void Universal::save(char savedPath[PATH_MAX]) const
+{
+ ::strcpy(savedPath, "/tmp/universal-XXXXXX");
+ int fd = ::mkstemp(savedPath);
+ if ( fd != -1 ) {
+ ::pwrite(fd, this, (size_t)size(), 0);
+ ::close(fd);
+ }
+}
+
+void Universal::free() const
+{
+ ::vm_deallocate(mach_task_self(), (vm_address_t)this, (vm_size_t)size());
+}
+
+#endif // BUILDING_MACHO_WRITER
+
} // namespace mach_o