[dsymutil] Add the ability to generate universal binaries with a fat64 header
Add the ability to generate universal binaries with a fat64 header. rdar://107223939 Differential revision: https://reviews.llvm.org/D146879
This commit is contained in:
@@ -37,6 +37,10 @@ OPTIONS
|
||||
Dump the *executable*'s debug-map (the list of the object files containing the
|
||||
debug information) in YAML format and exit. No DWARF link will take place.
|
||||
|
||||
.. option:: --fat64
|
||||
|
||||
Use a 64-bit header when emitting universal binaries.
|
||||
|
||||
.. option:: --flat, -f
|
||||
|
||||
Produce a flat dSYM file. A ``.dwarf`` extension will be appended to the
|
||||
|
||||
@@ -8,6 +8,7 @@ HELP: Dsymutil Options:
|
||||
CHECK: -accelerator
|
||||
CHECK: -arch <arch>
|
||||
CHECK: -dump-debug-map
|
||||
CHECK: -fat64
|
||||
CHECK: -flat
|
||||
CHECK: -gen-reproducer
|
||||
CHECK: -help
|
||||
|
||||
10
llvm/test/tools/dsymutil/fat-header.test
Normal file
10
llvm/test/tools/dsymutil/fat-header.test
Normal file
@@ -0,0 +1,10 @@
|
||||
REQUIRES: system-darwin
|
||||
|
||||
RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat32.dSYM
|
||||
RUN: llvm-objdump -m --universal-headers %t.fat32.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT32
|
||||
|
||||
RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat64.dSYM -fat64
|
||||
RUN: llvm-objdump -m --universal-headers %t.fat64.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT64
|
||||
|
||||
FAT32: fat_magic FAT_MAGIC
|
||||
FAT64: fat_magic FAT_MAGIC_64
|
||||
@@ -57,6 +57,9 @@ struct LinkOptions {
|
||||
/// function.
|
||||
bool KeepFunctionForStatic = false;
|
||||
|
||||
/// Use a 64-bit header when emitting universal binaries.
|
||||
bool Fat64 = false;
|
||||
|
||||
/// Number of threads.
|
||||
unsigned Threads = 1;
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
|
||||
|
||||
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
|
||||
StringRef OutputFileName,
|
||||
const LinkOptions &Options, StringRef SDKPath) {
|
||||
const LinkOptions &Options, StringRef SDKPath,
|
||||
bool Fat64) {
|
||||
// No need to merge one file into a universal fat binary.
|
||||
if (ArchFiles.size() == 1) {
|
||||
if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
|
||||
@@ -97,7 +98,7 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
|
||||
for (auto &Thin : ArchFiles)
|
||||
Args.push_back(Thin.path());
|
||||
|
||||
// Align segments to match dsymutil-classic alignment
|
||||
// Align segments to match dsymutil-classic alignment.
|
||||
for (auto &Thin : ArchFiles) {
|
||||
Thin.Arch = getArchName(Thin.Arch);
|
||||
Args.push_back("-segalign");
|
||||
@@ -105,6 +106,10 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
|
||||
Args.push_back("20");
|
||||
}
|
||||
|
||||
// Use a 64-bit fat header if requested.
|
||||
if (Fat64)
|
||||
Args.push_back("-fat64");
|
||||
|
||||
Args.push_back("-output");
|
||||
Args.push_back(OutputFileName.data());
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ struct DwarfRelocationApplicationInfo {
|
||||
|
||||
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
|
||||
StringRef OutputFileName, const LinkOptions &,
|
||||
StringRef SDKPath);
|
||||
StringRef SDKPath, bool Fat64 = false);
|
||||
bool generateDsymCompanion(
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const DebugMap &DM,
|
||||
SymbolMapTranslator &Translator, MCStreamer &MS, raw_fd_ostream &OutFile,
|
||||
|
||||
@@ -91,6 +91,10 @@ def: Flag<["-"], "f">,
|
||||
HelpText<"Alias for --flat">,
|
||||
Group<grp_general>;
|
||||
|
||||
def fat64: F<"fat64">,
|
||||
HelpText<"Use a 64-bit header when emitting universal binaries.">,
|
||||
Group<grp_general>;
|
||||
|
||||
def update: F<"update">,
|
||||
HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">,
|
||||
Group<grp_general>;
|
||||
|
||||
@@ -301,6 +301,7 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
|
||||
Options.LinkOpts.Update = Args.hasArg(OPT_update);
|
||||
Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
|
||||
Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
|
||||
Options.LinkOpts.Fat64 = Args.hasArg(OPT_fat64);
|
||||
Options.LinkOpts.KeepFunctionForStatic =
|
||||
Args.hasArg(OPT_keep_func_for_static);
|
||||
|
||||
@@ -780,40 +781,47 @@ int main(int argc, char **argv) {
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (NeedsTempFiles) {
|
||||
// Universal Mach-O files can't have an archicture slice that starts
|
||||
// beyond the 4GB boundary. "lipo" can creeate a 64 bit universal header,
|
||||
// but not all tools can parse these files so we want to return an error
|
||||
// if the file can't be encoded as a file with a 32 bit universal header.
|
||||
// To detect this, we check the size of each architecture's skinny Mach-O
|
||||
// file and add up the offsets. If they exceed 4GB, then we return an
|
||||
// error.
|
||||
const bool Fat64 = Options.LinkOpts.Fat64;
|
||||
if (!Fat64) {
|
||||
// Universal Mach-O files can't have an archicture slice that starts
|
||||
// beyond the 4GB boundary. "lipo" can create a 64 bit universal
|
||||
// header, but not all tools can parse these files so we want to return
|
||||
// an error if the file can't be encoded as a file with a 32 bit
|
||||
// universal header. To detect this, we check the size of each
|
||||
// architecture's skinny Mach-O file and add up the offsets. If they
|
||||
// exceed 4GB, then we return an error.
|
||||
|
||||
// First we compute the right offset where the first architecture will fit
|
||||
// followin the 32 bit universal header. The 32 bit universal header
|
||||
// starts with a uint32_t magic and a uint32_t number of architecture
|
||||
// infos. Then it is followed by 5 uint32_t values for each architecture.
|
||||
// So we set the start offset to the right value so we can calculate the
|
||||
// exact offset that the first architecture slice can start at.
|
||||
constexpr uint64_t MagicAndCountSize = 2 * 4;
|
||||
constexpr uint64_t UniversalArchInfoSize = 5 * 4;
|
||||
uint64_t FileOffset = MagicAndCountSize +
|
||||
UniversalArchInfoSize * TempFiles.size();
|
||||
for (const auto &File: TempFiles) {
|
||||
ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
|
||||
if (!stat)
|
||||
break;
|
||||
if (FileOffset > UINT32_MAX) {
|
||||
WithColor::error() << formatv(
|
||||
"the universal binary has a slice with a starting offset ({0:x}) "
|
||||
"that exceeds 4GB and will produce an invalid Mach-O file.",
|
||||
FileOffset);
|
||||
return EXIT_FAILURE;
|
||||
// First we compute the right offset where the first architecture will
|
||||
// fit followin the 32 bit universal header. The 32 bit universal header
|
||||
// starts with a uint32_t magic and a uint32_t number of architecture
|
||||
// infos. Then it is followed by 5 uint32_t values for each
|
||||
// architecture. So we set the start offset to the right value so we can
|
||||
// calculate the exact offset that the first architecture slice can
|
||||
// start at.
|
||||
constexpr uint64_t MagicAndCountSize = 2 * 4;
|
||||
constexpr uint64_t UniversalArchInfoSize = 5 * 4;
|
||||
uint64_t FileOffset =
|
||||
MagicAndCountSize + UniversalArchInfoSize * TempFiles.size();
|
||||
for (const auto &File : TempFiles) {
|
||||
ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
|
||||
if (!stat)
|
||||
break;
|
||||
if (FileOffset > UINT32_MAX) {
|
||||
WithColor::error()
|
||||
<< formatv("the universal binary has a slice with a starting "
|
||||
"offset ({0:x}) that exceeds 4GB and will produce "
|
||||
"an invalid Mach-O file. Use the -fat64 flag to "
|
||||
"generate a universal binary with a 64-bit header "
|
||||
"but note that not all tools support this format.",
|
||||
FileOffset);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
FileOffset += stat->getSize();
|
||||
}
|
||||
FileOffset += stat->getSize();
|
||||
}
|
||||
if (!MachOUtils::generateUniversalBinary(TempFiles,
|
||||
OutputLocationOrErr->DWARFFile,
|
||||
Options.LinkOpts, SDKPath))
|
||||
if (!MachOUtils::generateUniversalBinary(
|
||||
TempFiles, OutputLocationOrErr->DWARFFile, Options.LinkOpts,
|
||||
SDKPath, Fat64))
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user