Skip to content

Commit 9bd3727

Browse files
authored
Merge pull request #6541 from apple/🍒/navy/4d683f7fa7d4
[dsymutil] Add the ability to generate universal binaries with a fat64 header
2 parents e8395d1 + 3b02d04 commit 9bd3727

File tree

8 files changed

+70
-35
lines changed

8 files changed

+70
-35
lines changed

llvm/docs/CommandGuide/dsymutil.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ OPTIONS
3737
Dump the *executable*'s debug-map (the list of the object files containing the
3838
debug information) in YAML format and exit. No DWARF link will take place.
3939

40+
.. option:: --fat64
41+
42+
Use a 64-bit header when emitting universal binaries.
43+
4044
.. option:: --flat, -f
4145

4246
Produce a flat dSYM file. A ``.dwarf`` extension will be appended to the

llvm/test/tools/dsymutil/cmdline.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ HELP: Dsymutil Options:
88
CHECK: -accelerator
99
CHECK: -arch <arch>
1010
CHECK: -dump-debug-map
11+
CHECK: -fat64
1112
CHECK: -flat
1213
CHECK: -gen-reproducer
1314
CHECK: -help
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
REQUIRES: system-darwin
2+
3+
RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat32.dSYM
4+
RUN: llvm-objdump -m --universal-headers %t.fat32.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT32
5+
6+
RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat64.dSYM -fat64
7+
RUN: llvm-objdump -m --universal-headers %t.fat64.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT64
8+
9+
FAT32: fat_magic FAT_MAGIC
10+
FAT64: fat_magic FAT_MAGIC_64

llvm/tools/dsymutil/LinkUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ struct LinkOptions {
4949
/// function.
5050
bool KeepFunctionForStatic = false;
5151

52+
/// Use a 64-bit header when emitting universal binaries.
53+
bool Fat64 = false;
54+
5255
/// Number of threads.
5356
unsigned Threads = 1;
5457

llvm/tools/dsymutil/MachOUtils.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
7777

7878
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
7979
StringRef OutputFileName,
80-
const LinkOptions &Options, StringRef SDKPath) {
80+
const LinkOptions &Options, StringRef SDKPath,
81+
bool Fat64) {
8182
// No need to merge one file into a universal fat binary.
8283
if (ArchFiles.size() == 1) {
8384
if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
@@ -96,14 +97,18 @@ bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
9697
for (auto &Thin : ArchFiles)
9798
Args.push_back(Thin.path());
9899

99-
// Align segments to match dsymutil-classic alignment
100+
// Align segments to match dsymutil-classic alignment.
100101
for (auto &Thin : ArchFiles) {
101102
Thin.Arch = getArchName(Thin.Arch);
102103
Args.push_back("-segalign");
103104
Args.push_back(Thin.Arch);
104105
Args.push_back("20");
105106
}
106107

108+
// Use a 64-bit fat header if requested.
109+
if (Fat64)
110+
Args.push_back("-fat64");
111+
107112
Args.push_back("-output");
108113
Args.push_back(OutputFileName.data());
109114

llvm/tools/dsymutil/MachOUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct DwarfRelocationApplicationInfo {
5454

5555
bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
5656
StringRef OutputFileName, const LinkOptions &,
57-
StringRef SDKPath);
57+
StringRef SDKPath, bool Fat64 = false);
5858
bool generateDsymCompanion(
5959
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const DebugMap &DM,
6060
SymbolMapTranslator &Translator, MCStreamer &MS, raw_fd_ostream &OutFile,

llvm/tools/dsymutil/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ def: Flag<["-"], "f">,
9191
HelpText<"Alias for --flat">,
9292
Group<grp_general>;
9393

94+
def fat64: F<"fat64">,
95+
HelpText<"Use a 64-bit header when emitting universal binaries.">,
96+
Group<grp_general>;
97+
9498
def update: F<"update">,
9599
HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">,
96100
Group<grp_general>;

llvm/tools/dsymutil/dsymutil.cpp

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
297297
Options.LinkOpts.Update = Args.hasArg(OPT_update);
298298
Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
299299
Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
300+
Options.LinkOpts.Fat64 = Args.hasArg(OPT_fat64);
300301
Options.LinkOpts.KeepFunctionForStatic =
301302
Args.hasArg(OPT_keep_func_for_static);
302303

@@ -775,40 +776,47 @@ int dsymutil_main(int argc, char **argv) {
775776
return EXIT_FAILURE;
776777

777778
if (NeedsTempFiles) {
778-
// Universal Mach-O files can't have an archicture slice that starts
779-
// beyond the 4GB boundary. "lipo" can creeate a 64 bit universal header,
780-
// but not all tools can parse these files so we want to return an error
781-
// if the file can't be encoded as a file with a 32 bit universal header.
782-
// To detect this, we check the size of each architecture's skinny Mach-O
783-
// file and add up the offsets. If they exceed 4GB, then we return an
784-
// error.
785-
786-
// First we compute the right offset where the first architecture will fit
787-
// followin the 32 bit universal header. The 32 bit universal header
788-
// starts with a uint32_t magic and a uint32_t number of architecture
789-
// infos. Then it is followed by 5 uint32_t values for each architecture.
790-
// So we set the start offset to the right value so we can calculate the
791-
// exact offset that the first architecture slice can start at.
792-
constexpr uint64_t MagicAndCountSize = 2 * 4;
793-
constexpr uint64_t UniversalArchInfoSize = 5 * 4;
794-
uint64_t FileOffset = MagicAndCountSize +
795-
UniversalArchInfoSize * TempFiles.size();
796-
for (const auto &File: TempFiles) {
797-
ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
798-
if (!stat)
799-
break;
800-
if (FileOffset > UINT32_MAX) {
801-
WithColor::error() << formatv(
802-
"the universal binary has a slice with a starting offset ({0:x}) "
803-
"that exceeds 4GB and will produce an invalid Mach-O file.",
804-
FileOffset);
805-
return EXIT_FAILURE;
779+
const bool Fat64 = Options.LinkOpts.Fat64;
780+
if (!Fat64) {
781+
// Universal Mach-O files can't have an archicture slice that starts
782+
// beyond the 4GB boundary. "lipo" can create a 64 bit universal
783+
// header, but not all tools can parse these files so we want to return
784+
// an error if the file can't be encoded as a file with a 32 bit
785+
// universal header. To detect this, we check the size of each
786+
// architecture's skinny Mach-O file and add up the offsets. If they
787+
// exceed 4GB, then we return an error.
788+
789+
// First we compute the right offset where the first architecture will
790+
// fit followin the 32 bit universal header. The 32 bit universal header
791+
// starts with a uint32_t magic and a uint32_t number of architecture
792+
// infos. Then it is followed by 5 uint32_t values for each
793+
// architecture. So we set the start offset to the right value so we can
794+
// calculate the exact offset that the first architecture slice can
795+
// start at.
796+
constexpr uint64_t MagicAndCountSize = 2 * 4;
797+
constexpr uint64_t UniversalArchInfoSize = 5 * 4;
798+
uint64_t FileOffset =
799+
MagicAndCountSize + UniversalArchInfoSize * TempFiles.size();
800+
for (const auto &File : TempFiles) {
801+
ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
802+
if (!stat)
803+
break;
804+
if (FileOffset > UINT32_MAX) {
805+
WithColor::error()
806+
<< formatv("the universal binary has a slice with a starting "
807+
"offset ({0:x}) that exceeds 4GB and will produce "
808+
"an invalid Mach-O file. Use the -fat64 flag to "
809+
"generate a universal binary with a 64-bit header "
810+
"but note that not all tools support this format.",
811+
FileOffset);
812+
return EXIT_FAILURE;
813+
}
814+
FileOffset += stat->getSize();
806815
}
807-
FileOffset += stat->getSize();
808816
}
809-
if (!MachOUtils::generateUniversalBinary(TempFiles,
810-
OutputLocationOrErr->DWARFFile,
811-
Options.LinkOpts, SDKPath))
817+
if (!MachOUtils::generateUniversalBinary(
818+
TempFiles, OutputLocationOrErr->DWARFFile, Options.LinkOpts,
819+
SDKPath, Fat64))
812820
return EXIT_FAILURE;
813821
}
814822
}

0 commit comments

Comments
 (0)