[lld] 2a38dba - [lld-macho] Emit binding opcodes for defined symbols that override weak dysyms
Jez Ng via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 17:44:43 PDT 2020
Author: Jez Ng
Date: 2020-08-27T17:44:16-07:00
New Revision: 2a38dba7dd4d3360908e93c326fbef6a7465346e
URL: https://github.com/llvm/llvm-project/commit/2a38dba7dd4d3360908e93c326fbef6a7465346e
DIFF: https://github.com/llvm/llvm-project/commit/2a38dba7dd4d3360908e93c326fbef6a7465346e.diff
LOG: [lld-macho] Emit binding opcodes for defined symbols that override weak dysyms
These opcodes tell dyld to coalesce the overridden weak dysyms to this
particular symbol definition.
Reviewed By: #lld-macho, smeenai
Differential Revision: https://reviews.llvm.org/D86575
Added:
lld/test/MachO/nonweak-definition-override.s
Modified:
lld/MachO/SymbolTable.cpp
lld/MachO/Symbols.h
lld/MachO/SyntheticSections.cpp
lld/MachO/SyntheticSections.h
lld/MachO/Writer.cpp
lld/test/MachO/weak-header-flags.s
Removed:
################################################################################
diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp
index 2072b914fa83..cfb35718e7ec 100644
--- a/lld/MachO/SymbolTable.cpp
+++ b/lld/MachO/SymbolTable.cpp
@@ -40,6 +40,7 @@ Symbol *SymbolTable::addDefined(StringRef name, InputSection *isec,
uint32_t value, bool isWeakDef) {
Symbol *s;
bool wasInserted;
+ bool overridesWeakDef = false;
std::tie(s, wasInserted) = insert(name);
if (!wasInserted) {
@@ -48,12 +49,16 @@ Symbol *SymbolTable::addDefined(StringRef name, InputSection *isec,
return s;
if (!defined->isWeakDef())
error("duplicate symbol: " + name);
+ } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
+ overridesWeakDef = !isWeakDef && dysym->isWeakDef();
}
// Defined symbols take priority over other types of symbols, so in case
// of a name conflict, we fall through to the replaceSymbol() call below.
}
- replaceSymbol<Defined>(s, name, isec, value, isWeakDef, /*isExternal=*/true);
+ Defined *defined = replaceSymbol<Defined>(s, name, isec, value, isWeakDef,
+ /*isExternal=*/true);
+ defined->overridesWeakDef = overridesWeakDef;
return s;
}
@@ -75,6 +80,11 @@ Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
bool wasInserted;
std::tie(s, wasInserted) = insert(name);
+ if (!wasInserted && isWeakDef)
+ if (auto *defined = dyn_cast<Defined>(s))
+ if (!defined->isWeakDef())
+ defined->overridesWeakDef = true;
+
if (wasInserted || isa<Undefined>(s) ||
(isa<DylibSymbol>(s) && !isWeakDef && s->isWeakDef()))
replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, isTlv);
diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h
index a8b8540378d7..f12cc8549bd6 100644
--- a/lld/MachO/Symbols.h
+++ b/lld/MachO/Symbols.h
@@ -81,8 +81,8 @@ class Defined : public Symbol {
public:
Defined(StringRefZ name, InputSection *isec, uint32_t value, bool isWeakDef,
bool isExternal)
- : Symbol(DefinedKind, name), isec(isec), value(value), weakDef(isWeakDef),
- external(isExternal) {}
+ : Symbol(DefinedKind, name), isec(isec), value(value),
+ overridesWeakDef(false), weakDef(isWeakDef), external(isExternal) {}
bool isWeakDef() const override { return weakDef; }
@@ -101,9 +101,11 @@ class Defined : public Symbol {
InputSection *isec;
uint32_t value;
+ bool overridesWeakDef : 1;
+
private:
- const bool weakDef;
- const bool external;
+ const bool weakDef : 1;
+ const bool external : 1;
};
class Undefined : public Symbol {
@@ -182,14 +184,14 @@ union SymbolUnion {
};
template <typename T, typename... ArgT>
-void replaceSymbol(Symbol *s, ArgT &&... arg) {
+T *replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
- new (s) T(std::forward<ArgT>(arg)...);
+ return new (s) T(std::forward<ArgT>(arg)...);
}
} // namespace macho
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 07e8dfcddea8..679a1c9bd6a3 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -63,12 +63,10 @@ void MachHeaderSection::writeTo(uint8_t *buf) const {
if (config->outputType == MachO::MH_DYLIB && !config->hasReexports)
hdr->flags |= MachO::MH_NO_REEXPORTED_DYLIBS;
- // TODO: ld64 also sets this flag if we have defined a non-weak symbol that
- // overrides a weak symbol from an imported dylib.
- if (in.exports->hasWeakSymbol)
+ if (in.exports->hasWeakSymbol || in.weakBinding->hasNonWeakDefinition())
hdr->flags |= MachO::MH_WEAK_DEFINES;
- if (in.exports->hasWeakSymbol || in.weakBinding->isNeeded())
+ if (in.exports->hasWeakSymbol || in.weakBinding->hasEntry())
hdr->flags |= MachO::MH_BINDS_TO_WEAK;
for (OutputSegment *seg : outputSegments) {
@@ -178,6 +176,14 @@ static void encodeDylibOrdinal(const DylibSymbol *dysym, Binding &lastBinding,
}
}
+static void encodeWeakOverride(const Defined *defined,
+ raw_svector_ostream &os) {
+ using namespace llvm::MachO;
+ os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM |
+ BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
+ << defined->getName() << '\0';
+}
+
uint64_t BindingTarget::getVA() const {
if (auto *isec = section.dyn_cast<const InputSection *>())
return isec->getVA() + offset;
@@ -233,6 +239,9 @@ void WeakBindingSection::finalizeContents() {
raw_svector_ostream os{contents};
Binding lastBinding;
+ for (const Defined *defined : definitions)
+ encodeWeakOverride(defined, os);
+
// Since bindings are delta-encoded, sorting them allows for a more compact
// result.
llvm::sort(bindings,
@@ -249,7 +258,7 @@ void WeakBindingSection::finalizeContents() {
lastBinding, os);
}
}
- if (!bindings.empty())
+ if (!bindings.empty() || !definitions.empty())
os << static_cast<uint8_t>(MachO::BIND_OPCODE_DONE);
}
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 155d39ef9053..1000dd13fc54 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -38,6 +38,7 @@ constexpr const char threadPtrs[] = "__thread_ptrs";
} // namespace section_names
+class Defined;
class DylibSymbol;
class LoadCommand;
@@ -189,9 +190,16 @@ struct WeakBindingEntry {
: symbol(symbol), target(std::move(target)) {}
};
-// Stores bind opcodes for telling dyld which weak symbols to load. Note that
-// the bind opcodes will only refer to these symbols by name, but will not
-// specify which dylib to load them from.
+// Stores bind opcodes for telling dyld which weak symbols need coalescing.
+// There are two types of entries in this section:
+//
+// 1) Non-weak definitions: This is a symbol definition that weak symbols in
+// other dylibs should coalesce to.
+//
+// 2) Weak bindings: These tell dyld that a given symbol reference should
+// coalesce to a non-weak definition if one is found. Note that unlike in the
+// entries in the BindingSection, the bindings here only refer to these
+// symbols by name, but do not specify which dylib to load them from.
class WeakBindingSection : public LinkEditSection {
public:
WeakBindingSection();
@@ -201,7 +209,9 @@ class WeakBindingSection : public LinkEditSection {
// offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
// section headers.
bool isHidden() const override { return true; }
- bool isNeeded() const override { return !bindings.empty(); }
+ bool isNeeded() const override {
+ return !bindings.empty() || !definitions.empty();
+ }
void writeTo(uint8_t *buf) const override;
@@ -210,8 +220,17 @@ class WeakBindingSection : public LinkEditSection {
bindings.emplace_back(symbol, BindingTarget(section, offset, addend));
}
+ bool hasEntry() const { return !bindings.empty(); }
+
+ void addNonWeakDefinition(const Defined *defined) {
+ definitions.emplace_back(defined);
+ }
+
+ bool hasNonWeakDefinition() const { return !definitions.empty(); }
+
private:
std::vector<WeakBindingEntry> bindings;
+ std::vector<const Defined *> definitions;
SmallVector<char, 128> contents;
};
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 6abee4338486..741ec31b19ee 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -561,6 +561,11 @@ void Writer::run() {
if (in.stubHelper->isNeeded())
in.stubHelper->setup();
+ for (const macho::Symbol *sym : symtab->getSymbols())
+ if (const auto *defined = dyn_cast<Defined>(sym))
+ if (defined->overridesWeakDef)
+ in.weakBinding->addNonWeakDefinition(defined);
+
// Sort and assign sections to their respective segments. No more sections nor
// segments may be created after these methods run.
createOutputSections();
diff --git a/lld/test/MachO/nonweak-definition-override.s b/lld/test/MachO/nonweak-definition-override.s
new file mode 100644
index 000000000000..d5c94d4cdca2
--- /dev/null
+++ b/lld/test/MachO/nonweak-definition-override.s
@@ -0,0 +1,60 @@
+# REQUIRES: x86
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/nonweakdef.s -o %t/nonweakdef.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/weakdef.s -o %t/weakdef.o
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -dylib %t/libfoo.o -o %t/libfoo.dylib
+
+## Check that non-weak defined symbols override weak dylib symbols.
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk %t/nonweakdef.o -L%t -lfoo -o %t/nonweakdef -lSystem
+# RUN: llvm-objdump --macho --weak-bind %t/nonweakdef | FileCheck %s
+
+## Test loading the dylib before the obj file.
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -L%t -lfoo %t/nonweakdef.o -o %t/nonweakdef -lSystem
+# RUN: llvm-objdump --macho --weak-bind %t/nonweakdef | FileCheck %s
+
+# CHECK: Weak bind table:
+# CHECK-NEXT: segment section address type addend symbol
+# CHECK-NEXT: strong _weak_in_dylib
+# CHECK-EMPTY:
+
+## Check that weak defined symbols do not override weak dylib symbols.
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk %t/weakdef.o -L%t -lfoo -o %t/weakdef -lSystem
+# RUN: llvm-objdump --macho --weak-bind %t/weakdef | FileCheck %s --check-prefix=NO-WEAK-OVERRIDE
+
+## Test loading the dylib before the obj file.
+# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -L%t -lfoo %t/weakdef.o -o %t/weakdef -lSystem
+# RUN: llvm-objdump --macho --weak-bind %t/weakdef | FileCheck %s --check-prefix=NO-WEAK-OVERRIDE
+
+# NO-WEAK-OVERRIDE: Weak bind table:
+# NO-WEAK-OVERRIDE-NEXT: segment section address type addend symbol
+# NO-WEAK-OVERRIDE-EMPTY:
+
+#--- libfoo.s
+
+.globl _weak_in_dylib, _nonweak_in_dylib
+.weak_definition _weak_in_dylib
+
+_weak_in_dylib:
+_nonweak_in_dylib:
+
+#--- nonweakdef.s
+
+.globl _main, _weak_in_dylib, _nonweak_in_dylib
+
+_weak_in_dylib:
+_nonweak_in_dylib:
+
+_main:
+ ret
+
+#--- weakdef.s
+
+.globl _main, _weak_in_dylib, _nonweak_in_dylib
+.weak_definition _weak_in_dylib, _nonweak_in_dylib
+
+_weak_in_dylib:
+_nonweak_in_dylib:
+
+_main:
+ ret
diff --git a/lld/test/MachO/weak-header-flags.s b/lld/test/MachO/weak-header-flags.s
index 3d3c5660a65a..eb799cd2be0c 100644
--- a/lld/test/MachO/weak-header-flags.s
+++ b/lld/test/MachO/weak-header-flags.s
@@ -9,6 +9,10 @@
# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -L%t -lweak-defines -o %t/binds-to-weak %t/binds-to-weak.o
# RUN: llvm-readobj --file-headers %t/binds-to-weak | FileCheck %s --check-prefix=WEAK-BINDS-ONLY
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/overrides-weak.s -o %t/overrides-weak.o
+# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -L%t -lweak-defines -o %t/overrides-weak %t/overrides-weak.o
+# RUN: llvm-readobj --file-headers %t/overrides-weak | FileCheck %s --check-prefix=WEAK-DEFINES-ONLY
+
# WEAK-DEFINES-AND-BINDS: MH_BINDS_TO_WEAK
# WEAK-DEFINES-AND-BINDS: MH_WEAK_DEFINES
@@ -16,6 +20,10 @@
# WEAK-BINDS-ONLY: MH_BINDS_TO_WEAK
# WEAK-BINDS-ONLY-NOT: MH_WEAK_DEFINES
+# WEAK-DEFINES-ONLY-NOT: MH_BINDS_TO_WEAK
+# WEAK-DEFINES-ONLY: MH_WEAK_DEFINES
+# WEAK-DEFINES-ONLY-NOT: MH_BINDS_TO_WEAK
+
#--- libweak-defines.s
.globl _foo
@@ -33,3 +41,11 @@ _main:
## Don't generate MH_WEAK_DEFINES for weak locals
.weak_definition _weak_local
_weak_local:
+
+#--- overrides-weak.s
+
+.globl _main, _foo
+_foo:
+
+_main:
+ ret
More information about the llvm-commits
mailing list