.Pass();
}
+ private string MakeUniversalBinary(string path, string rid)
+ {
+ string fatApp = path + ".fat";
+ string arch = BundleHelper.GetTargetArch(rid) == Architecture.Arm64 ? "arm64" : "x86_64";
+
+ // We will create a universal binary with just one arch slice and run it.
+ // It is enough for testing purposes. The code that finds the releavant slice
+ // would work the same regardless if there is 1, 2, 3 or more slices.
+ Command.Create("lipo", $"-create -arch {arch} {path} -output {fatApp}")
+ .CaptureStdErr()
+ .CaptureStdOut()
+ .Execute()
+ .Should()
+ .Pass();
+
+ return fatApp;
+ }
+
private void BundleRun(TestProjectFixture fixture, string publishPath)
{
var hostName = BundleHelper.GetHostName(fixture);
// Run the extracted app
RunTheApp(singleFile);
+
+ if (targetOS == OSPlatform.OSX)
+ {
+ string fatApp = MakeUniversalBinary(singleFile, fixture.CurrentRid);
+
+ // Run the fat app
+ RunTheApp(fatApp);
+ }
}
private string RelativePath(string path)
const char* addr = map_bundle();
reader_t reader(addr, m_bundle_size, m_header_offset);
+ m_offset_in_file = reader.offset_in_file();
m_header = header_t::read(reader);
m_deps_json.set_location(&m_header.deps_json_location());
trace::info(_X("Mapped bundle for [%s]"), path.c_str());
- return addr + location->offset;
+ return addr + location->offset + app->m_offset_in_file;
}
void info_t::config_t::unmap(const char* addr, const location_t* location)
{
// Adjust to the beginning of the bundle.
- addr -= location->offset;
+ const bundle::info_t* app = bundle::info_t::the_app;
+ addr -= location->offset - app->m_offset_in_file;
+
bundle::info_t::the_app->unmap_bundle(addr);
}
pal::string_t m_base_path;
size_t m_bundle_size;
int64_t m_header_offset;
+ int64_t m_offset_in_file;
header_t m_header;
config_t m_deps_json;
config_t m_runtimeconfig_json;
throw StatusCode::BundleExtractionFailure;
}
- m_ptr = m_base_ptr + offset;
+ m_ptr = m_base_ptr + offset + m_offset_in_file;
}
void reader_t::bounds_check(int64_t len)
#include "pal.h"
#include "utils.h"
+// support for parsing OSX universal binary headers
+#ifdef TARGET_OSX
+#include "error_codes.h"
+#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
+#include <mach/machine.h>
+
+#if defined(TARGET_ARM64)
+#define TARGET_CPU_TYPE CPU_TYPE_ARM64
+#else
+#define TARGET_CPU_TYPE CPU_TYPE_X86_64
+#endif
+
+template <typename fat_arch_type>
+void* offset_in_FAT_universal_binary(const char* addr)
+{
+ uint32_t nfat_arch = OSSwapBigToHostInt32(((uint32_t*)addr)[1]);
+
+ fat_arch_type* arch_list = (fat_arch_type*)(addr + sizeof(uint32_t) * 2);
+ for (int i = 0; i < nfat_arch; i++)
+ {
+ if (OSSwapBigToHostInt32((uint32_t)arch_list[i].cputype) == TARGET_CPU_TYPE)
+ {
+ return &arch_list[i].offset;
+ }
+ }
+
+ trace::error(_X("Couldn't find offset in an universal fat binary."));
+ throw StatusCode::BundleExtractionFailure;
+}
+#endif // TARGET_OSX
+
+
namespace bundle
{
// Helper class for reading sequentially from the memory-mapped bundle file.
, m_bound(bound)
, m_bound_ptr(add_without_overflow(base_ptr, bound))
{
+ m_offset_in_file = 0;
+
+#ifdef TARGET_OSX
+ // check for universal binary container and adjust the offset accordingly
+ uint32_t magic = OSSwapBigToHostInt32(((uint32_t*)base_ptr)[0]);
+ if (magic == FAT_MAGIC)
+ {
+ m_offset_in_file = OSSwapBigToHostInt32(*(uint32_t*)offset_in_FAT_universal_binary<fat_arch>(base_ptr));
+ trace::info(_X("FAT container detected. Offset in file:[%lx]"), m_offset_in_file);
+ }
+ else if (magic == FAT_MAGIC_64)
+ {
+ m_offset_in_file = OSSwapBigToHostInt64(*(uint64_t*)offset_in_FAT_universal_binary<fat_arch_64>(base_ptr));
+ trace::info(_X("FAT64 container detected. Offset in file:[%lx]"), m_offset_in_file);
+ }
+#endif
+
set_offset(start_offset);
}
return *m_ptr++;
}
+ int64_t offset_in_file()
+ {
+ return m_offset_in_file;
+ }
+
// Copy len bytes from m_ptr to dest
void read(void* dest, int64_t len)
{
const char* m_ptr;
const int64_t m_bound;
const char* const m_bound_ptr;
+
+ int64_t m_offset_in_file;
};
}
// Set the Reader at header_offset
reader_t reader(addr, m_bundle_size, m_header_offset);
+ m_offset_in_file = reader.offset_in_file();
// Read the bundle header
m_header = header_t::read(reader);
assert(!entry->is_disabled());
assert(entry->offset() != 0);
- *offset = entry->offset();
+ *offset = entry->offset() + m_offset_in_file;
*size = entry->size();
*compressedSize = entry->compressedSize();