2020-04-03 02:54:05 +08:00
|
|
|
//===- Config.h -------------------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLD_MACHO_CONFIG_H
|
|
|
|
#define LLD_MACHO_CONFIG_H
|
|
|
|
|
2021-03-04 04:15:09 +08:00
|
|
|
#include "llvm/ADT/CachedHashString.h"
|
2020-05-06 07:37:34 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2021-03-04 04:15:09 +08:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2020-04-29 07:58:22 +08:00
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
2021-03-04 04:15:09 +08:00
|
|
|
#include "llvm/Support/GlobPattern.h"
|
2020-08-11 09:47:16 +08:00
|
|
|
#include "llvm/Support/VersionTuple.h"
|
2021-04-06 00:59:50 +08:00
|
|
|
#include "llvm/TextAPI/Architecture.h"
|
|
|
|
#include "llvm/TextAPI/Platform.h"
|
|
|
|
#include "llvm/TextAPI/Target.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
namespace lld {
|
|
|
|
namespace macho {
|
|
|
|
|
|
|
|
class Symbol;
|
2020-05-06 07:37:34 +08:00
|
|
|
struct SymbolPriorityEntry;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-02-27 07:36:49 +08:00
|
|
|
using NamePair = std::pair<llvm::StringRef, llvm::StringRef>;
|
|
|
|
using SectionRenameMap = llvm::DenseMap<NamePair, NamePair>;
|
|
|
|
using SegmentRenameMap = llvm::DenseMap<llvm::StringRef, llvm::StringRef>;
|
|
|
|
|
2020-08-11 09:47:16 +08:00
|
|
|
struct PlatformInfo {
|
2021-04-21 20:41:14 +08:00
|
|
|
llvm::MachO::Target target;
|
2020-08-11 09:47:16 +08:00
|
|
|
llvm::VersionTuple minimum;
|
|
|
|
llvm::VersionTuple sdk;
|
|
|
|
};
|
|
|
|
|
2021-06-05 14:31:40 +08:00
|
|
|
inline uint32_t encodeVersion(const llvm::VersionTuple &version) {
|
|
|
|
return ((version.getMajor() << 020) |
|
|
|
|
(version.getMinor().getValueOr(0) << 010) |
|
|
|
|
version.getSubminor().getValueOr(0));
|
|
|
|
}
|
|
|
|
|
2021-02-18 21:48:07 +08:00
|
|
|
enum class NamespaceKind {
|
|
|
|
twolevel,
|
|
|
|
flat,
|
|
|
|
};
|
|
|
|
|
2020-12-14 11:31:33 +08:00
|
|
|
enum class UndefinedSymbolTreatment {
|
|
|
|
unknown,
|
|
|
|
error,
|
|
|
|
warning,
|
|
|
|
suppress,
|
|
|
|
dynamic_lookup,
|
|
|
|
};
|
|
|
|
|
2021-05-11 23:43:48 +08:00
|
|
|
struct SectionAlign {
|
|
|
|
llvm::StringRef segName;
|
|
|
|
llvm::StringRef sectName;
|
|
|
|
uint32_t align;
|
|
|
|
};
|
|
|
|
|
2021-03-30 02:08:12 +08:00
|
|
|
struct SegmentProtection {
|
|
|
|
llvm::StringRef name;
|
|
|
|
uint32_t maxProt;
|
|
|
|
uint32_t initProt;
|
|
|
|
};
|
|
|
|
|
2021-03-04 04:15:09 +08:00
|
|
|
class SymbolPatterns {
|
2021-03-11 08:45:18 +08:00
|
|
|
public:
|
2021-03-04 04:15:09 +08:00
|
|
|
// GlobPattern can also match literals,
|
|
|
|
// but we prefer the O(1) lookup of DenseSet.
|
|
|
|
llvm::DenseSet<llvm::CachedHashStringRef> literals;
|
|
|
|
std::vector<llvm::GlobPattern> globs;
|
|
|
|
|
|
|
|
bool empty() const { return literals.empty() && globs.empty(); }
|
|
|
|
void clear();
|
|
|
|
void insert(llvm::StringRef symbolName);
|
|
|
|
bool matchLiteral(llvm::StringRef symbolName) const;
|
|
|
|
bool matchGlob(llvm::StringRef symbolName) const;
|
|
|
|
bool match(llvm::StringRef symbolName) const;
|
|
|
|
};
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
struct Configuration {
|
2021-05-10 08:05:45 +08:00
|
|
|
Symbol *entry = nullptr;
|
2020-04-24 11:16:49 +08:00
|
|
|
bool hasReexports = false;
|
2020-08-26 11:00:42 +08:00
|
|
|
bool allLoad = false;
|
2020-08-19 05:37:04 +08:00
|
|
|
bool forceLoadObjC = false;
|
2021-06-08 11:48:16 +08:00
|
|
|
bool forceLoadSwift = false;
|
2020-09-22 04:21:45 +08:00
|
|
|
bool staticLink = false;
|
2020-12-10 07:08:05 +08:00
|
|
|
bool implicitDylibs = false;
|
2020-09-06 01:55:33 +08:00
|
|
|
bool isPic = false;
|
2020-09-22 02:04:13 +08:00
|
|
|
bool headerPadMaxInstallNames = false;
|
2021-01-13 03:41:56 +08:00
|
|
|
bool ltoNewPassManager = LLVM_ENABLE_NEW_PASS_MANAGER;
|
2021-03-09 23:17:01 +08:00
|
|
|
bool markDeadStrippableDylib = false;
|
2020-12-03 07:57:30 +08:00
|
|
|
bool printEachFile = false;
|
2020-12-03 07:59:00 +08:00
|
|
|
bool printWhyLoad = false;
|
2020-09-20 23:37:20 +08:00
|
|
|
bool searchDylibsFirst = false;
|
2020-10-27 10:18:29 +08:00
|
|
|
bool saveTemps = false;
|
2021-03-05 22:07:58 +08:00
|
|
|
bool adhocCodesign = false;
|
2021-03-23 05:38:52 +08:00
|
|
|
bool emitFunctionStarts = false;
|
2021-04-17 04:46:45 +08:00
|
|
|
bool emitBitcodeBundle = false;
|
2021-04-22 01:35:12 +08:00
|
|
|
bool emitEncryptionInfo = false;
|
2021-03-11 22:04:27 +08:00
|
|
|
bool timeTraceEnabled = false;
|
2021-04-26 07:00:24 +08:00
|
|
|
bool dataConst = false;
|
[lld-macho] Implement cstring deduplication
Our implementation draws heavily from LLD-ELF's, which in turn delegates
its string deduplication to llvm-mc's StringTableBuilder. The messiness of
this diff is largely due to the fact that we've previously assumed that
all InputSections get concatenated together to form the output. This is
no longer true with CStringInputSections, which split their contents into
StringPieces. StringPieces are much more lightweight than InputSections,
which is important as we create a lot of them. They may also overlap in
the output, which makes it possible for strings to be tail-merged. In
fact, the initial version of this diff implemented tail merging, but
I've dropped it for reasons I'll explain later.
**Alignment Issues**
Mergeable cstring literals are found under the `__TEXT,__cstring`
section. In contrast to ELF, which puts strings that need different
alignments into different sections, clang's Mach-O backend puts them all
in one section. Strings that need to be aligned have the `.p2align`
directive emitted before them, which simply translates into zero padding
in the object file.
I *think* ld64 extracts the desired per-string alignment from this data
by preserving each string's offset from the last section-aligned
address. I'm not entirely certain since it doesn't seem consistent about
doing this; but perhaps this can be chalked up to cases where ld64 has
to deduplicate strings with different offset/alignment combos -- it
seems to pick one of their alignments to preserve. This doesn't seem
correct in general; we can in fact can induce ld64 to produce a crashing
binary just by linking in an additional object file that only contains
cstrings and no code. See PR50563 for details.
Moreover, this scheme seems rather inefficient: since unaligned and
aligned strings are all put in the same section, which has a single
alignment value, it doesn't seem possible to tell whether a given string
doesn't have any alignment requirements. Preserving offset+alignments
for strings that don't need it is wasteful.
In practice, the crashes seen so far seem to stem from x86_64 SIMD
operations on cstrings. X86_64 requires SIMD accesses to be
16-byte-aligned. So for now, I'm thinking of just aligning all strings
to 16 bytes on x86_64. This is indeed wasteful, but implementation-wise
it's simpler than preserving per-string alignment+offsets. It also
avoids the aforementioned crash after deduplication of
differently-aligned strings. Finally, the overhead is not huge: using
16-byte alignment (vs no alignment) is only a 0.5% size overhead when
linking chromium_framework.
With these alignment requirements, it doesn't make sense to attempt tail
merging -- most strings will not be eligible since their overlaps aren't
likely to start at a 16-byte boundary. Tail-merging (with alignment) for
chromium_framework only improves size by 0.3%.
It's worth noting that LLD-ELF only does tail merging at `-O2`. By
default (at `-O1`), it just deduplicates w/o tail merging. @thakis has
also mentioned that they saw it regress compressed size in some cases
and therefore turned it off. `ld64` does not seem to do tail merging at
all.
**Performance Numbers**
CString deduplication reduces chromium_framework from 250MB to 242MB, or
about a 3.2% reduction.
Numbers for linking chromium_framework on my 3.2 GHz 16-Core Intel Xeon W:
N Min Max Median Avg Stddev
x 20 3.91 4.03 3.935 3.95 0.034641016
+ 20 3.99 4.14 4.015 4.0365 0.0492336
Difference at 95.0% confidence
0.0865 +/- 0.027245
2.18987% +/- 0.689746%
(Student's t, pooled s = 0.0425673)
As expected, cstring merging incurs some non-trivial overhead.
When passing `--no-literal-merge`, it seems that performance is the
same, i.e. the refactoring in this diff didn't cost us.
N Min Max Median Avg Stddev
x 20 3.91 4.03 3.935 3.95 0.034641016
+ 20 3.89 4.02 3.935 3.9435 0.043197831
No difference proven at 95.0% confidence
Reviewed By: #lld-macho, gkm
Differential Revision: https://reviews.llvm.org/D102964
2021-06-08 11:47:12 +08:00
|
|
|
bool dedupLiterals = true;
|
2020-07-31 05:28:45 +08:00
|
|
|
uint32_t headerPad;
|
2020-12-15 07:24:50 +08:00
|
|
|
uint32_t dylibCompatibilityVersion = 0;
|
|
|
|
uint32_t dylibCurrentVersion = 0;
|
2021-03-25 09:05:26 +08:00
|
|
|
uint32_t timeTraceGranularity = 500;
|
2021-03-11 22:04:27 +08:00
|
|
|
std::string progName;
|
2020-04-29 07:58:22 +08:00
|
|
|
llvm::StringRef installName;
|
2021-03-18 22:38:30 +08:00
|
|
|
llvm::StringRef mapFile;
|
2020-04-29 07:58:22 +08:00
|
|
|
llvm::StringRef outputFile;
|
2020-12-03 12:34:17 +08:00
|
|
|
llvm::StringRef ltoObjPath;
|
2021-04-09 00:14:47 +08:00
|
|
|
llvm::StringRef thinLTOJobs;
|
2021-06-01 10:12:35 +08:00
|
|
|
bool deadStripDylibs = false;
|
clang+lld: Improve clang+ld.darwinnew.lld interaction, pass -demangle
This patch:
- adds an ld64.lld.darwinnew symlink for lld, to go with f2710d4b576,
so that `clang -fuse-ld=lld.darwinnew` can be used to test new
Mach-O lld while it's in bring-up. (The expectation is that we'll
remove this again once new Mach-O lld is the defauld and only Mach-O
lld.)
- lets the clang driver know if the linker is lld (currently
only triggered if `-fuse-ld=lld` or `-fuse-ld=lld.darwinnew` is
passed). Currently only used for the next point, but could be used
to implement other features that need close coordination between
compiler and linker, e.g. having a diag for calling `clang++` instead
of `clang` when link errors are caused by a missing C++ stdlib.
- lets the clang driver pass `-demangle` to Mach-O lld (both old and
new), in addition to ld64
- implements -demangle for new Mach-O lld
- changes demangleItanium() to accept _Z, __Z, ___Z, ____Z prefixes
(and updates one test added in D68014). Mach-O has an extra
underscore for symbols, and the three (or, on Mach-O, four)
underscores are used for block names.
Differential Revision: https://reviews.llvm.org/D91884
2020-11-21 02:57:44 +08:00
|
|
|
bool demangle = false;
|
[lld/mac] Implement -dead_strip
Also adds support for live_support sections, no_dead_strip sections,
.no_dead_strip symbols.
Chromium Framework 345MB unstripped -> 250MB stripped
(vs 290MB unstripped -> 236M stripped with ld64).
Doing dead stripping is a bit faster than not, because so much less
data needs to be processed:
% ministat lld_*
x lld_nostrip.txt
+ lld_strip.txt
N Min Max Median Avg Stddev
x 10 3.929414 4.07692 4.0269079 4.0089678 0.044214794
+ 10 3.8129408 3.9025559 3.8670411 3.8642573 0.024779651
Difference at 95.0% confidence
-0.144711 +/- 0.0336749
-3.60967% +/- 0.839989%
(Student's t, pooled s = 0.0358398)
This interacts with many parts of the linker. I tried to add test coverage
for all added `isLive()` checks, so that some test will fail if any of them
is removed. I checked that the test expectations for the most part match
ld64's behavior (except for live-support-iterations.s, see the comment
in the test). Interacts with:
- debug info
- export tries
- import opcodes
- flags like -exported_symbol(s_list)
- -U / dynamic_lookup
- mod_init_funcs, mod_term_funcs
- weak symbol handling
- unwind info
- stubs
- map files
- -sectcreate
- undefined, dylib, common, defined (both absolute and normal) symbols
It's possible it interacts with more features I didn't think of,
of course.
I also did some manual testing:
- check-llvm check-clang check-lld work with lld with this patch
as host linker and -dead_strip enabled
- Chromium still starts
- Chromium's base_unittests still pass, including unwind tests
Implemenation-wise, this is InputSection-based, so it'll work for
object files with .subsections_via_symbols (which includes all
object files generated by clang). I first based this on the COFF
implementation, but later realized that things are more similar to ELF.
I think it'd be good to refactor MarkLive.cpp to look more like the ELF
part at some point, but I'd like to get a working state checked in first.
Mechanical parts:
- Rename canOmitFromOutput to wasCoalesced (no behavior change)
since it really is for weak coalesced symbols
- Add noDeadStrip to Defined, corresponding to N_NO_DEAD_STRIP
(`.no_dead_strip` in asm)
Fixes PR49276.
Differential Revision: https://reviews.llvm.org/D103324
2021-05-08 05:10:05 +08:00
|
|
|
bool deadStrip = false;
|
2021-03-05 03:36:47 +08:00
|
|
|
PlatformInfo platformInfo;
|
2021-02-18 21:48:07 +08:00
|
|
|
NamespaceKind namespaceKind = NamespaceKind::twolevel;
|
2020-12-14 11:31:33 +08:00
|
|
|
UndefinedSymbolTreatment undefinedSymbolTreatment =
|
|
|
|
UndefinedSymbolTreatment::error;
|
2020-04-24 11:16:49 +08:00
|
|
|
llvm::MachO::HeaderFileType outputType;
|
2020-08-14 04:48:47 +08:00
|
|
|
std::vector<llvm::StringRef> systemLibraryRoots;
|
2020-06-18 10:59:27 +08:00
|
|
|
std::vector<llvm::StringRef> librarySearchPaths;
|
|
|
|
std::vector<llvm::StringRef> frameworkSearchPaths;
|
2020-08-13 10:50:28 +08:00
|
|
|
std::vector<llvm::StringRef> runtimePaths;
|
2021-04-09 02:12:20 +08:00
|
|
|
std::vector<std::string> astPaths;
|
2021-02-09 21:18:23 +08:00
|
|
|
std::vector<Symbol *> explicitUndefineds;
|
2021-05-11 23:43:48 +08:00
|
|
|
// There are typically few custom sectionAlignments or segmentProtections,
|
|
|
|
// so use a vector instead of a map.
|
|
|
|
std::vector<SectionAlign> sectionAlignments;
|
2021-03-30 02:08:12 +08:00
|
|
|
std::vector<SegmentProtection> segmentProtections;
|
2021-03-04 04:15:09 +08:00
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
|
2021-02-27 07:36:49 +08:00
|
|
|
SectionRenameMap sectionRenameMap;
|
|
|
|
SegmentRenameMap segmentRenameMap;
|
2021-03-04 04:15:09 +08:00
|
|
|
|
|
|
|
SymbolPatterns exportedSymbols;
|
|
|
|
SymbolPatterns unexportedSymbols;
|
2021-04-22 03:43:38 +08:00
|
|
|
|
2021-06-01 18:55:36 +08:00
|
|
|
bool zeroModTime = false;
|
|
|
|
|
2021-04-22 03:43:38 +08:00
|
|
|
llvm::MachO::Architecture arch() const { return platformInfo.target.Arch; }
|
|
|
|
|
|
|
|
llvm::MachO::PlatformKind platform() const {
|
|
|
|
return platformInfo.target.Platform;
|
|
|
|
}
|
2020-05-06 07:37:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// The symbol with the highest priority should be ordered first in the output
|
|
|
|
// section (modulo input section contiguity constraints). Using priority
|
|
|
|
// (highest first) instead of order (lowest first) has the convenient property
|
|
|
|
// that the default-constructed zero priority -- for symbols/sections without a
|
|
|
|
// user-defined order -- naturally ends up putting them at the end of the
|
|
|
|
// output.
|
|
|
|
struct SymbolPriorityEntry {
|
|
|
|
// The priority given to a matching symbol, regardless of which object file
|
|
|
|
// it originated from.
|
|
|
|
size_t anyObjectFile = 0;
|
|
|
|
// The priority given to a matching symbol from a particular object file.
|
|
|
|
llvm::DenseMap<llvm::StringRef, size_t> objectFiles;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
extern Configuration *config;
|
|
|
|
|
|
|
|
} // namespace macho
|
|
|
|
} // namespace lld
|
|
|
|
|
|
|
|
#endif
|