mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-01 12:43:47 +00:00
ELF2: Implement --as-needed.
This patch adds AsNeeded and IsUsed bool fields to SharedFile. AsNeeded bit is set if the DSO is enclosed with --as-needed and --no-as-needed. IsUsed bit is off by default. When we adds a symbol to the symbol table for dynamic linking, we set its SharedFile's IsUsed bit. If AsNeeded is set but IsUsed is not set, we don't want to write that file's SO name to DT_NEEDED field. http://reviews.llvm.org/D13579 llvm-svn: 249998
This commit is contained in:
parent
78ed9b43fd
commit
35da9b6e1c
@ -43,6 +43,7 @@ struct Configuration {
|
||||
std::string RPath;
|
||||
std::vector<llvm::StringRef> SearchPaths;
|
||||
bool AllowMultipleDefinition;
|
||||
bool AsNeeded = false;
|
||||
bool DiscardAll;
|
||||
bool DiscardLocals;
|
||||
bool DiscardNone;
|
||||
|
@ -100,9 +100,12 @@ void LinkerDriver::addFile(StringRef Path) {
|
||||
}
|
||||
Files.push_back(make_unique<ArchiveFile>(MBRef));
|
||||
return;
|
||||
case file_magic::elf_shared_object:
|
||||
Files.push_back(createELFFile<SharedFile>(MBRef));
|
||||
case file_magic::elf_shared_object: {
|
||||
std::unique_ptr<ELFFileBase> File = createELFFile<SharedFile>(MBRef);
|
||||
cast<SharedFileBase>(File.get())->AsNeeded = Config->AsNeeded;
|
||||
Files.push_back(std::move(File));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
Files.push_back(createELFFile<ObjectFile>(MBRef));
|
||||
}
|
||||
@ -187,6 +190,12 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
|
||||
case OPT_script:
|
||||
addFile(Arg->getValue());
|
||||
break;
|
||||
case OPT_as_needed:
|
||||
Config->AsNeeded = true;
|
||||
break;
|
||||
case OPT_no_as_needed:
|
||||
Config->AsNeeded = false;
|
||||
break;
|
||||
case OPT_Bstatic:
|
||||
Config->Static = true;
|
||||
break;
|
||||
|
@ -329,7 +329,7 @@ template <class ELFT> void SharedFile<ELFT>::parse() {
|
||||
error(NameOrErr.getError());
|
||||
StringRef Name = *NameOrErr;
|
||||
|
||||
SymbolBodies.emplace_back(Name, Sym);
|
||||
SymbolBodies.emplace_back(this, Name, Sym);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
||||
if (SymbolIndex < FirstNonLocal)
|
||||
return nullptr;
|
||||
return SymbolBodies[SymbolIndex - FirstNonLocal]->repl();
|
||||
return SymbolBodies[SymbolIndex - FirstNonLocal];
|
||||
}
|
||||
|
||||
Elf_Sym_Range getLocalSymbols();
|
||||
@ -198,6 +198,11 @@ public:
|
||||
StringRef getSoName() const { return SoName; }
|
||||
virtual void parseSoName() = 0;
|
||||
virtual void parse() = 0;
|
||||
|
||||
// Used for --as-needed
|
||||
bool AsNeeded = false;
|
||||
bool IsUsed = false;
|
||||
bool isNeeded() const { return !AsNeeded || IsUsed; }
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
|
@ -46,7 +46,7 @@ void InputSection<ELFT>::relocate(
|
||||
continue;
|
||||
SymVA = getLocalSymVA(Sym, File);
|
||||
} else {
|
||||
SymbolBody &Body = *File.getSymbolBody(SymIndex);
|
||||
SymbolBody &Body = *File.getSymbolBody(SymIndex)->repl();
|
||||
SymVA = getSymVA<ELFT>(Body);
|
||||
if (Target->relocNeedsPlt(Type, Body)) {
|
||||
SymVA = Out<ELFT>::Plt->getEntryAddr(Body);
|
||||
|
@ -155,12 +155,15 @@ void LinkerScript::addFile(StringRef S) {
|
||||
|
||||
void LinkerScript::readAsNeeded() {
|
||||
expect("(");
|
||||
bool Orig = Config->AsNeeded;
|
||||
Config->AsNeeded = true;
|
||||
for (;;) {
|
||||
StringRef Tok = next();
|
||||
if (Tok == ")")
|
||||
return;
|
||||
break;
|
||||
addFile(Tok);
|
||||
}
|
||||
Config->AsNeeded = Orig;
|
||||
}
|
||||
|
||||
void LinkerScript::readEntry() {
|
||||
|
@ -14,6 +14,8 @@ def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
|
||||
|
||||
def allow_shlib_undefined : Flag<["--", "-"], "allow-shlib-undefined">;
|
||||
|
||||
def as_needed : Flag<["--"], "as-needed">;
|
||||
|
||||
def disable_new_dtags : Flag<["--"], "disable-new-dtags">,
|
||||
HelpText<"Disable new dynamic tags">;
|
||||
|
||||
@ -52,6 +54,8 @@ def m : Separate<["-"], "m">,
|
||||
|
||||
def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">;
|
||||
|
||||
def no_as_needed : Flag<["--"], "no-as-needed">;
|
||||
|
||||
def no_whole_archive : Flag<["--"], "no-whole-archive">,
|
||||
HelpText<"Restores the default behavior of loading archive members">;
|
||||
|
||||
@ -111,14 +115,12 @@ def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>;
|
||||
|
||||
// Options listed below are silently ignored now.
|
||||
def O3 : Flag<["-"], "O3">;
|
||||
def as_needed : Flag<["--"], "as-needed">;
|
||||
def build_id : Flag<["--"], "build-id">;
|
||||
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
|
||||
def end_group : Flag<["--"], "end-group">;
|
||||
def gc_sections : Flag<["--"], "gc-sections">;
|
||||
def hash_style : Joined<["--"], "hash-style=">;
|
||||
def no_add_needed : Flag<["--"], "no-add-needed">;
|
||||
def no_as_needed : Flag<["--"], "no-as-needed">;
|
||||
def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;
|
||||
def start_group : Flag<["--"], "start-group">;
|
||||
def strip_all : Flag<["--"], "strip-all">;
|
||||
|
@ -116,8 +116,10 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
OutputSection<ELFT> *OutSec = C.getOutputSection();
|
||||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
const ObjectFile<ELFT> &File = *C.getFile();
|
||||
const SymbolBody *Body = File.getSymbolBody(SymIndex);
|
||||
SymbolBody *Body = File.getSymbolBody(SymIndex);
|
||||
const ELFFile<ELFT> &Obj = File.getObj();
|
||||
if (Body)
|
||||
Body = Body->repl();
|
||||
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
|
||||
@ -279,6 +281,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
|
||||
NumEntries += 2;
|
||||
|
||||
for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) {
|
||||
if (!F->isNeeded())
|
||||
continue;
|
||||
Out<ELFT>::DynStrTab->add(F->getSoName());
|
||||
++NumEntries;
|
||||
}
|
||||
@ -356,7 +360,8 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec);
|
||||
|
||||
for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles())
|
||||
WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getFileOff(F->getSoName()));
|
||||
if (F->isNeeded())
|
||||
WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getFileOff(F->getSoName()));
|
||||
|
||||
if (InitSym)
|
||||
WritePtr(DT_INIT, getSymVA<ELFT>(*InitSym));
|
||||
|
@ -24,6 +24,7 @@ class InputFile;
|
||||
class SymbolBody;
|
||||
template <class ELFT> class ObjectFile;
|
||||
template <class ELFT> class OutputSection;
|
||||
template <class ELFT> class SharedFile;
|
||||
|
||||
// Initializes global objects defined in this file.
|
||||
// Called at the beginning of main().
|
||||
@ -263,8 +264,10 @@ public:
|
||||
return S->kind() == Base::SharedKind;
|
||||
}
|
||||
|
||||
SharedSymbol(StringRef Name, const Elf_Sym &Sym)
|
||||
: Defined<ELFT>(Base::SharedKind, Name, Sym) {}
|
||||
SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym)
|
||||
: Defined<ELFT>(Base::SharedKind, Name, Sym), File(F) {}
|
||||
|
||||
SharedFile<ELFT> *File;
|
||||
};
|
||||
|
||||
// This class represents a symbol defined in an archive file. It is
|
||||
|
@ -174,6 +174,14 @@ void Writer<ELFT>::scanRelocs(
|
||||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
SymbolBody *Body = File.getSymbolBody(SymIndex);
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
|
||||
// Set "used" bit for --as-needed.
|
||||
if (Body && Body->isUndefined() && !Body->isWeak())
|
||||
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl()))
|
||||
S->File->IsUsed = true;
|
||||
|
||||
if (Body)
|
||||
Body = Body->repl();
|
||||
if (Body) {
|
||||
if (Target->relocNeedsPlt(Type, *Body)) {
|
||||
if (Body->isInPlt())
|
||||
@ -186,12 +194,13 @@ void Writer<ELFT>::scanRelocs(
|
||||
Out<ELFT>::Got->addEntry(Body);
|
||||
}
|
||||
}
|
||||
if (canBePreempted(Body)) {
|
||||
|
||||
bool CBP = canBePreempted(Body);
|
||||
if (!CBP && (!Config->Shared || Target->isRelRelative(Type)))
|
||||
continue;
|
||||
if (CBP)
|
||||
Body->setUsedInDynamicReloc();
|
||||
Out<ELFT>::RelaDyn->addReloc({C, RI});
|
||||
} else if (Config->Shared && !Target->isRelRelative(Type)) {
|
||||
Out<ELFT>::RelaDyn->addReloc({C, RI});
|
||||
}
|
||||
Out<ELFT>::RelaDyn->addReloc({C, RI});
|
||||
}
|
||||
}
|
||||
|
||||
|
6
lld/test/elf2/Inputs/shared2.s
Normal file
6
lld/test/elf2/Inputs/shared2.s
Normal file
@ -0,0 +1,6 @@
|
||||
.global bar2
|
||||
.type bar2, @function
|
||||
bar2:
|
||||
|
||||
.global zed2
|
||||
zed2:
|
3
lld/test/elf2/Inputs/shared3.s
Normal file
3
lld/test/elf2/Inputs/shared3.s
Normal file
@ -0,0 +1,3 @@
|
||||
.global baz
|
||||
.type barz, @function
|
||||
baz:
|
43
lld/test/elf2/as-needed.s
Normal file
43
lld/test/elf2/as-needed.s
Normal file
@ -0,0 +1,43 @@
|
||||
// REQUIRES: x86
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared2.s -o %t3.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared3.s -o %t4.o
|
||||
// RUN: ld.lld2 -shared %t2.o -soname shared1 -o %t2.so
|
||||
// RUN: ld.lld2 -shared %t3.o -soname shared2 -o %t3.so
|
||||
// RUN: ld.lld2 -shared %t4.o -soname shared3 -o %t4.so
|
||||
|
||||
/// Check if --as-needed actually works.
|
||||
|
||||
// RUN: ld.lld2 %t.o %t2.so %t3.so %t4.so -o %t2
|
||||
// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
|
||||
|
||||
// RUN: ld.lld2 --as-needed %t.o %t2.so %t3.so %t4.so -o %t2
|
||||
// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
// RUN: ld.lld2 --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2
|
||||
// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
|
||||
|
||||
/// GROUP directive is the same as --as-needed.
|
||||
|
||||
// RUN: echo "GROUP(" %t2.so %t3.so %t4.so ")" > %t.script
|
||||
// RUN: ld.lld2 %t.o %t.script -o %t2
|
||||
// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
|
||||
|
||||
// RUN: echo "GROUP(AS_NEEDED(" %t2.so %t3.so %t4.so "))" > %t.script
|
||||
// RUN: ld.lld2 %t.o %t.script -o %t2
|
||||
// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
// CHECK: NEEDED SharedLibrary (shared1)
|
||||
// CHECK: NEEDED SharedLibrary (shared2)
|
||||
// CHECK: NEEDED SharedLibrary (shared3)
|
||||
|
||||
// CHECK2: NEEDED SharedLibrary (shared1)
|
||||
// CHECK2-NOT: NEEDED SharedLibrary (shared2)
|
||||
// CHECK2-NOT: NEEDED SharedLibrary (shared3)
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
.long bar
|
||||
.long zed
|
||||
.weak baz
|
Loading…
x
Reference in New Issue
Block a user