/*size=*/0,
/*isWeakDef=*/false,
/*isExternal=*/true, common->privateExtern,
- /*isThumb=*/false);
+ /*isThumb=*/false,
+ /*isReferencedDynamically=*/false);
}
}
return symtab->addDefined(name, isec->file, isec, value, size,
sym.n_desc & N_WEAK_DEF, isPrivateExtern,
- sym.n_desc & N_ARM_THUMB_DEF);
+ sym.n_desc & N_ARM_THUMB_DEF,
+ sym.n_desc & REFERENCED_DYNAMICALLY);
}
assert(!isWeakDefCanBeHidden &&
return make<Defined>(name, isec->file, isec, value, size,
sym.n_desc & N_WEAK_DEF,
/*isExternal=*/false, /*isPrivateExtern=*/false,
- sym.n_desc & N_ARM_THUMB_DEF);
+ sym.n_desc & N_ARM_THUMB_DEF,
+ sym.n_desc & REFERENCED_DYNAMICALLY);
}
// Absolute symbols are defined symbols that do not have an associated
assert((sym.n_type & N_EXT) && "invalid input");
return symtab->addDefined(name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false, sym.n_type & N_PEXT,
- sym.n_desc & N_ARM_THUMB_DEF);
+ sym.n_desc & N_ARM_THUMB_DEF,
+ /*isReferencedDynamically=*/false);
}
return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false,
/*isExternal=*/false, /*isPrivateExtern=*/false,
- sym.n_desc & N_ARM_THUMB_DEF);
+ sym.n_desc & N_ARM_THUMB_DEF,
+ /*isReferencedDynamically=*/false);
}
template <class NList>
return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
/*size=*/0, objSym.isWeak(), isPrivateExtern,
- /*isThumb=*/false);
+ /*isThumb=*/false,
+ /*isReferencedDynamically=*/false);
}
BitcodeFile::BitcodeFile(MemoryBufferRef mbref)
r.referent = thunkInfo.sym = symtab->addDefined(
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0,
/*size=*/thunkSize, /*isWeakDef=*/false, /*isPrivateExtern=*/true,
- /*isThumb=*/false);
+ /*isThumb=*/false, /*isReferencedDynamically=*/false);
target->populateThunk(thunkInfo.isec, funcSym);
finalizeOne(thunkInfo.isec);
thunks.push_back(thunkInfo.isec);
Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
InputSection *isec, uint64_t value,
uint64_t size, bool isWeakDef,
- bool isPrivateExtern, bool isThumb) {
+ bool isPrivateExtern, bool isThumb,
+ bool isReferencedDynamically) {
Symbol *s;
bool wasInserted;
bool overridesWeakDef = false;
if (!wasInserted) {
if (auto *defined = dyn_cast<Defined>(s)) {
if (isWeakDef) {
- // Both old and new symbol weak (e.g. inline function in two TUs):
- // If one of them isn't private extern, the merged symbol isn't.
if (defined->isWeakDef()) {
+ // Both old and new symbol weak (e.g. inline function in two TUs):
+ // If one of them isn't private extern, the merged symbol isn't.
defined->privateExtern &= isPrivateExtern;
+ defined->referencedDynamically |= isReferencedDynamically;
// FIXME: Handle this for bitcode files.
// FIXME: We currently only do this if both symbols are weak.
// of a name conflict, we fall through to the replaceSymbol() call below.
}
- Defined *defined =
- replaceSymbol<Defined>(s, name, file, isec, value, size, isWeakDef,
- /*isExternal=*/true, isPrivateExtern, isThumb);
+ Defined *defined = replaceSymbol<Defined>(
+ s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
+ isPrivateExtern, isThumb, isReferencedDynamically);
defined->overridesWeakDef = overridesWeakDef;
return defined;
}
Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
uint64_t value, bool isPrivateExtern,
- bool includeInSymtab) {
+ bool includeInSymtab,
+ bool referencedDynamically) {
Defined *s = addDefined(name, nullptr, isec, value, /*size=*/0,
/*isWeakDef=*/false, isPrivateExtern,
- /*isThumb=*/false);
+ /*isThumb=*/false, referencedDynamically);
s->includeInSymtab = includeInSymtab;
return s;
}
public:
Defined *addDefined(StringRef name, InputFile *, InputSection *,
uint64_t value, uint64_t size, bool isWeakDef,
- bool isPrivateExtern, bool isThumb);
+ bool isPrivateExtern, bool isThumb,
+ bool isReferencedDynamically);
Symbol *addUndefined(StringRef name, InputFile *, bool isWeakRef);
const llvm::object::Archive::Symbol &sym);
Defined *addSynthetic(StringRef name, InputSection *, uint64_t value,
- bool isPrivateExtern, bool includeInSymtab);
+ bool isPrivateExtern, bool includeInSymtab,
+ bool referencedDynamically);
ArrayRef<Symbol *> getSymbols() const { return symVector; }
Symbol *find(llvm::CachedHashStringRef name);
public:
Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value,
uint64_t size, bool isWeakDef, bool isExternal, bool isPrivateExtern,
- bool isThumb)
+ bool isThumb, bool isReferencedDynamically)
: Symbol(DefinedKind, name, file), isec(isec), value(value), size(size),
overridesWeakDef(false), privateExtern(isPrivateExtern),
- includeInSymtab(true), thumb(isThumb), weakDef(isWeakDef),
+ includeInSymtab(true), thumb(isThumb),
+ referencedDynamically(isReferencedDynamically), weakDef(isWeakDef),
external(isExternal) {
if (isec)
isec->numRefs++;
bool includeInSymtab : 1;
// Only relevant when compiling for Thumb-supporting arm32 archs.
bool thumb : 1;
+ // Symbols marked referencedDynamically won't be removed from the output's
+ // symbol table by tools like strip. In theory, this could be set on arbitrary
+ // symbols in input object files. In practice, it's used solely for the
+ // synthetic __mh_execute_header symbol.
+ bool referencedDynamically : 1;
private:
const bool weakDef : 1;
make<Defined>("__dyld_private", nullptr, in.imageLoaderCache, 0, 0,
/*isWeakDef=*/false,
/*isExternal=*/false, /*isPrivateExtern=*/false,
- /*isThumb=*/false);
+ /*isThumb=*/false, /*isReferencedDynamically=*/false);
}
ImageLoaderCacheSection::ImageLoaderCacheSection() {
}
nList->n_desc |= defined->thumb ? N_ARM_THUMB_DEF : 0;
nList->n_desc |= defined->isExternalWeakDef() ? N_WEAK_DEF : 0;
+ nList->n_desc |=
+ defined->referencedDynamically ? REFERENCED_DYNAMICALLY : 0;
} else if (auto *dysym = dyn_cast<DylibSymbol>(entry.sym)) {
uint16_t n_desc = nList->n_desc;
int16_t ordinal = ordinalForDylibSymbol(*dysym);
void macho::createSyntheticSymbols() {
auto addHeaderSymbol = [](const char *name) {
- symtab->addSynthetic(name, in.header->isec, 0,
- /*privateExtern=*/true,
- /*includeInSymtab=*/false);
+ symtab->addSynthetic(name, in.header->isec, /*value=*/0,
+ /*privateExtern=*/true, /*includeInSymtab=*/false,
+ /*referencedDynamically=*/false);
};
switch (config->outputType) {
// Otherwise, it's an absolute symbol.
if (config->isPic)
symtab->addSynthetic("__mh_execute_header", in.header->isec, /*value=*/0,
- /*privateExtern=*/false,
- /*includeInSymtab=*/true);
+ /*privateExtern=*/false, /*includeInSymtab=*/true,
+ /*referencedDynamically=*/true);
else
- symtab->addSynthetic("__mh_execute_header",
- /*isec*/ nullptr, /*value=*/0,
- /*privateExtern=*/false,
- /*includeInSymtab=*/true);
+ symtab->addSynthetic("__mh_execute_header", /*isec=*/nullptr, /*value=*/0,
+ /*privateExtern=*/false, /*includeInSymtab=*/true,
+ /*referencedDynamically=*/true);
break;
- // The following symbols are N_SECT symbols, even though the header is not
+ // The following symbols are N_SECT symbols, even though the header is not
// part of any section and that they are private to the bundle/dylib/object
// they are part of.
case MH_BUNDLE:
s = make<Defined>("<internal>", /*file=*/nullptr, referentIsec,
r.addend, /*size=*/0, /*isWeakDef=*/false,
/*isExternal=*/false, /*isPrivateExtern=*/false,
- /*isThumb=*/false);
+ /*isThumb=*/false, /*isReferencedDynamically=*/false);
in.got->addEntry(s);
}
r.referent = s;
--- /dev/null
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+
+# RUN: %lld %t.o -lSystem -o %t.out
+# RUN: llvm-readobj --syms %t.out | FileCheck %s
+
+## ld64 has a "TEMP work around until <rdar://problem/7702923> goes in"
+## that promotes PrivateExtern ReferencedDynamically symbols in dylibs to
+## normal Externs. lld does not do this.
+# RUN: %lld -dylib %t.o -o %t.dylib
+# RUN: llvm-readobj --syms %t.dylib | FileCheck %s
+
+# CHECK: Name: ___crashreporter_info__
+# CHECK-NEXT: PrivateExtern
+# CHECK-NEXT: Type: Section (0xE)
+# CHECK-NEXT: Section: __common
+# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+# CHECK-NEXT: Flags [ (0x10)
+# CHECK-NEXT: ReferencedDynamically (0x10)
+# CHECK-NEXT: ]
+
+## Reduced from lib/Support/PrettyStackTrace.cpp
+.section __TEXT,__text,regular,pure_instructions
+
+.globl _main
+_main:
+ ret
+
+## .private_extern maches what PrettyStackTrace.cpp does, but it makes
+## the ReferencedDynamically pointless: https://reviews.llvm.org/D27683#2763729
+.private_extern ___crashreporter_info__
+.globl ___crashreporter_info__
+.desc ___crashreporter_info__,16
+.zerofill __DATA,__common,___crashreporter_info__,8,3
+.subsections_via_symbols
# CHECK-DAG: ( SECT EXT) [[#%.2d,COMM_ID + 1]] 0000 [[#ZERO]] '_zero'
# CHECK-DAG: ( SECT EXT) [[#%.2d,MORE_TEXT_ID + 1]] 0000 [[#FUN]] '_fun'
# CHECK-DAG: ( SECT EXT) [[#%.2d,TEXT_ID + 1]] 0000 {{[0-9a-f]+}} '_no_debug'
-# CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0000 {{[0-9a-f]+}} '__mh_execute_header'
+# CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0010 {{[0-9a-f]+}} '__mh_execute_header'
# CHECK-EMPTY:
## Check that we don't attempt to emit rebase opcodes for the debug sections
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __text (0x1)
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
-# CHECK-NEXT: Flags [ (0x0)
+# CHECK-NEXT: Flags [ (0x10)
+# CHECK-NEXT: ReferencedDynamically (0x10)
# CHECK-NEXT: ]
# CHECK-NEXT: Value: 0x100000000
# CHECK-NEXT: }