[lld-macho] Allow the entry symbol to be dynamically bound

Apparently this is used in real programs. I've handled this by reusing
the logic we already have for branch (function call) relocations.

Reviewed By: #lld-macho, smeenai

Differential Revision: https://reviews.llvm.org/D87852
This commit is contained in:
Jez Ng 2020-09-17 10:20:16 -07:00
parent f23f512691
commit c7c9776f77
6 changed files with 84 additions and 31 deletions

View File

@ -238,28 +238,7 @@ void X86_64::prepareSymbolRelocation(lld::macho::Symbol *sym,
break;
}
case X86_64_RELOC_BRANCH: {
// TODO: factor this logic out so it can be reused for different
// architectures
if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
if (in.stubs->addEntry(dysym)) {
if (sym->isWeakDef()) {
in.binding->addEntry(dysym, in.lazyPointers,
sym->stubsIndex * WordSize);
in.weakBinding->addEntry(sym, in.lazyPointers,
sym->stubsIndex * WordSize);
} else {
in.lazyBinding->addEntry(dysym);
}
}
} else if (auto *defined = dyn_cast<Defined>(sym)) {
if (defined->isWeakDef() && defined->isExternal()) {
if (in.stubs->addEntry(sym)) {
in.rebase->addEntry(in.lazyPointers, sym->stubsIndex * WordSize);
in.weakBinding->addEntry(sym, in.lazyPointers,
sym->stubsIndex * WordSize);
}
}
}
prepareBranchTarget(sym);
break;
}
case X86_64_RELOC_UNSIGNED: {

View File

@ -697,7 +697,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
if (!orderFile.empty())
parseOrderFile(orderFile);
if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
if (config->outputType == MH_EXECUTE && isa<Undefined>(config->entry)) {
error("undefined symbol: " + config->entry->getName());
return false;
}

View File

@ -529,6 +529,29 @@ uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
return opstreamOffset;
}
void macho::prepareBranchTarget(Symbol *sym) {
if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
if (in.stubs->addEntry(dysym)) {
if (sym->isWeakDef()) {
in.binding->addEntry(dysym, in.lazyPointers,
sym->stubsIndex * WordSize);
in.weakBinding->addEntry(sym, in.lazyPointers,
sym->stubsIndex * WordSize);
} else {
in.lazyBinding->addEntry(dysym);
}
}
} else if (auto *defined = dyn_cast<Defined>(sym)) {
if (defined->isWeakDef() && defined->isExternal()) {
if (in.stubs->addEntry(sym)) {
in.rebase->addEntry(in.lazyPointers, sym->stubsIndex * WordSize);
in.weakBinding->addEntry(sym, in.lazyPointers,
sym->stubsIndex * WordSize);
}
}
}
}
ExportSection::ExportSection()
: LinkEditSection(segment_names::linkEdit, section_names::export_) {}

View File

@ -364,6 +364,10 @@ private:
llvm::raw_svector_ostream os{contents};
};
// Adds stubs and bindings where necessary (e.g. if the symbol is a
// DylibSymbol.)
void prepareBranchTarget(Symbol *);
// Stores a trie that describes the set of exported symbols.
class ExportSection : public LinkEditSection {
public:

View File

@ -194,7 +194,13 @@ class LCMain : public LoadCommand {
auto *c = reinterpret_cast<entry_point_command *>(buf);
c->cmd = LC_MAIN;
c->cmdsize = getSize();
c->entryoff = config->entry->getFileOffset();
if (config->entry->isInStubs())
c->entryoff =
in.stubs->fileOff + config->entry->stubsIndex * target->stubSize;
else
c->entryoff = config->entry->getFileOffset();
c->stacksize = 0;
}
};
@ -617,6 +623,7 @@ void Writer::run() {
OutputSegment *linkEditSegment =
getOrCreateOutputSegment(segment_names::linkEdit);
prepareBranchTarget(config->entry);
scanRelocations();
if (in.stubHelper->isNeeded())
in.stubHelper->setup();

View File

@ -1,7 +1,11 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -o %t %t.o -e _not_main
# RUN: llvm-objdump --macho --all-headers --syms %t | FileCheck %s
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/not-main.s -o %t/not-main.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib %t/libfoo.o -o %t/libfoo.dylib
# RUN: lld -flavor darwinnew -o %t/not-main %t/not-main.o -e _not_main
# RUN: llvm-objdump --macho --all-headers --syms %t/not-main | FileCheck %s
# CHECK-LABEL: SYMBOL TABLE
# CHECK-NEXT: {{0*}}[[#%x, ENTRY_ADDR:]] {{.*}} __TEXT,__text _not_main
# CHECK: cmd LC_MAIN
@ -15,14 +19,50 @@
# CHECK-NEXT: size
# CHECK-NEXT: offset [[#ENTRYOFF]]
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -o %t/dysym-main %t/not-main.o %t/libfoo.dylib -e _dysym_main
# RUN: llvm-objdump --macho --all-headers --indirect-symbols --lazy-bind %t/dysym-main | FileCheck %s --check-prefix=DYSYM
# DYSYM-LABEL: Indirect symbols for (__TEXT,__stubs) 1 entries
# DYSYM-NEXT: address index name
# DYSYM-NEXT: 0x[[#%x,DYSYM_ENTRY_ADDR:]] [[#]] _dysym_main
# DYSYM-LABEL: cmd LC_MAIN
# DYSYM-NEXT: cmdsize 24
# DYSYM-NEXT: entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]]
# DYSYM-LABEL: Lazy bind table:
# DYSYM-NEXT: segment section address dylib symbol
# DYSYM-NEXT: __DATA __la_symbol_ptr {{.*}} libfoo _dysym_main
# RUN: not lld -flavor darwinnew -o /dev/null %t.o -e _missing 2>&1 | FileCheck %s --check-prefix=UNDEFINED
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -o %t/weak-dysym-main %t/not-main.o %t/libfoo.dylib -e _weak_dysym_main
# RUN: llvm-objdump --macho --all-headers --indirect-symbols --bind --weak-bind %t/weak-dysym-main | FileCheck %s --check-prefix=WEAK-DYSYM
# WEAK-DYSYM-LABEL: Indirect symbols for (__TEXT,__stubs) 1 entries
# WEAK-DYSYM-NEXT: address index name
# WEAK-DYSYM-NEXT: 0x[[#%x,DYSYM_ENTRY_ADDR:]] [[#]] _weak_dysym_main
# WEAK-DYSYM: cmd LC_MAIN
# WEAK-DYSYM-NEXT: cmdsize 24
# WEAK-DYSYM-NEXT: entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]]
# WEAK-DYSYM-LABEL: Bind table:
# WEAK-DYSYM-NEXT: segment section address type addend dylib symbol
# WEAK-DYSYM: __DATA __la_symbol_ptr {{.*}} pointer 0 libfoo _weak_dysym_main
# WEAK-DYSYM-LABEL: Weak bind table:
# WEAK-DYSYM-NEXT: segment section address type addend symbol
# WEAK-DYSYM-NEXT: __DATA __la_symbol_ptr {{.*}} pointer 0 _weak_dysym_main
# RUN: not lld -flavor darwinnew -o /dev/null %t/not-main.o -e _missing 2>&1 | FileCheck %s --check-prefix=UNDEFINED
# UNDEFINED: error: undefined symbol: _missing
# RUN: not lld -flavor darwinnew -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY
# RUN: not lld -flavor darwinnew -o /dev/null %t/not-main.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY
# DEFAULT-ENTRY: error: undefined symbol: _main
#--- libfoo.s
.text
.global _dysym_main, _weak_dysym_main
.weak_definition _weak_dysym_main
_dysym_main:
ret
_weak_dysym_main:
ret
#--- not-main.s
.text
.global _not_main
_not_main:
movq $0, %rax
retq
ret