diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
| commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
| tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /ELF | |
| parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) | |
Notes
Diffstat (limited to 'ELF')
42 files changed, 10917 insertions, 4431 deletions
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 3dcb65ff8957..a1b65adc7400 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -2,25 +2,49 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(ELFOptionsTableGen) -add_lld_library(lldELF2 +add_lld_library(lldELF Driver.cpp DriverUtils.cpp + EhFrame.cpp Error.cpp + ICF.cpp InputFiles.cpp InputSection.cpp + LTO.cpp LinkerScript.cpp MarkLive.cpp OutputSections.cpp + Relocations.cpp + ScriptParser.cpp + Strings.cpp + SymbolListFile.cpp SymbolTable.cpp Symbols.cpp Target.cpp + Thunks.cpp Writer.cpp LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Analysis + BitReader + BitWriter + Codegen + Core + IPO + Linker + LTO Object Option + Passes MC Support + Target + TransformUtils + + LINK_LIBS + lldConfig + ${PTHREAD_LIB} ) -add_dependencies(lldELF2 ELFOptionsTableGen) +add_dependencies(lldELF intrinsics_gen ELFOptionsTableGen) diff --git a/ELF/Config.h b/ELF/Config.h index c279b99b43c1..2ccd95e88775 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -17,10 +17,10 @@ #include <vector> namespace lld { -namespace elf2 { +namespace elf { class InputFile; -class SymbolBody; +struct Symbol; enum ELFKind { ELFNoneKind, @@ -30,60 +30,105 @@ enum ELFKind { ELF64BEKind }; +enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; + +enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore }; + +struct SymbolVersion { + llvm::StringRef Name; + bool IsExternCpp; +}; + +// This struct contains symbols version definition that +// can be found in version script if it is used for link. +struct VersionDefinition { + VersionDefinition(llvm::StringRef Name, size_t Id) : Name(Name), Id(Id) {} + llvm::StringRef Name; + size_t Id; + std::vector<SymbolVersion> Globals; + size_t NameOff; // Offset in string table. +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { - SymbolBody *EntrySym = nullptr; - SymbolBody *MipsGpDisp = nullptr; + Symbol *EntrySym = nullptr; InputFile *FirstElf = nullptr; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; + llvm::StringRef LtoAAPipeline; + llvm::StringRef LtoNewPmPasses; llvm::StringRef OutputFile; llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; - llvm::MapVector<llvm::StringRef, std::vector<llvm::StringRef>> OutputSections; + std::vector<VersionDefinition> VersionDefinitions; + std::vector<llvm::StringRef> DynamicList; std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> Undefined; + std::vector<SymbolVersion> VersionScriptGlobals; + std::vector<uint8_t> BuildIdVector; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; + bool BsymbolicFunctions; + bool Demangle = true; + bool DisableVerify; bool DiscardAll; bool DiscardLocals; bool DiscardNone; + bool EhFrameHdr; bool EnableNewDtags; bool ExportDynamic; + bool FatalWarnings; bool GcSections; bool GnuHash = false; + bool ICF; bool Mips64EL = false; - bool NoInhibitExec; - bool NoUndefined; + bool NoGnuUnique; + bool NoUndefinedVersion; + bool Pic; + bool Pie; bool PrintGcSections; + bool Rela; + bool Relocatable; + bool SaveTemps; bool Shared; bool Static = false; bool StripAll; + bool StripDebug; bool SysvHash = true; + bool Threads; + bool Trace; bool Verbose; + bool WarnCommon; + bool ZCombreloc; bool ZExecStack; bool ZNodelete; bool ZNow; bool ZOrigin; bool ZRelro; + UnresolvedPolicy UnresolvedSymbols; + BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; + uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = -1; - unsigned Optimize = 0; + uint64_t ImageBase; + unsigned LtoJobs; + unsigned LtoO; + unsigned Optimize; }; // The only instance of Configuration struct. extern Configuration *Config; -} // namespace elf2 +} // namespace elf } // namespace lld #endif diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index f00d97851e4a..c6ca2639236f 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -10,119 +10,218 @@ #include "Driver.h" #include "Config.h" #include "Error.h" +#include "ICF.h" #include "InputFiles.h" +#include "InputSection.h" +#include "LinkerScript.h" +#include "Strings.h" +#include "SymbolListFile.h" #include "SymbolTable.h" #include "Target.h" #include "Writer.h" -#include "llvm/ADT/STLExtras.h" +#include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include <cstdlib> #include <utility> using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::sys; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; -Configuration *elf2::Config; -LinkerDriver *elf2::Driver; +Configuration *elf::Config; +LinkerDriver *elf::Driver; + +bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) { + HasError = false; + ErrorOS = &Error; -void elf2::link(ArrayRef<const char *> Args) { Configuration C; LinkerDriver D; + ScriptConfiguration SC; Config = &C; Driver = &D; - Driver->main(Args.slice(1)); + ScriptConfig = &SC; + + Driver->main(Args); + return !HasError; } +// Parses a linker -m option. static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { - if (S == "elf32btsmip") - return {ELF32BEKind, EM_MIPS}; - if (S == "elf32ltsmip") - return {ELF32LEKind, EM_MIPS}; - if (S == "elf32ppc" || S == "elf32ppc_fbsd") - return {ELF32BEKind, EM_PPC}; - if (S == "elf64ppc" || S == "elf64ppc_fbsd") - return {ELF64BEKind, EM_PPC64}; - if (S == "elf_i386") - return {ELF32LEKind, EM_386}; - if (S == "elf_x86_64") - return {ELF64LEKind, EM_X86_64}; - if (S == "aarch64linux") - return {ELF64LEKind, EM_AARCH64}; - if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - error("Windows targets are not supported on the ELF frontend: " + S); - error("Unknown emulation: " + S); + if (S.endswith("_fbsd")) + S = S.drop_back(5); + + std::pair<ELFKind, uint16_t> Ret = + StringSwitch<std::pair<ELFKind, uint16_t>>(S) + .Case("aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM}) + .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) + .Case("elf32btsmip", {ELF32BEKind, EM_MIPS}) + .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS}) + .Case("elf32ppc", {ELF32BEKind, EM_PPC}) + .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) + .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) + .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Case("elf_i386", {ELF32LEKind, EM_386}) + .Case("elf_x86_64", {ELF64LEKind, EM_X86_64}) + .Default({ELFNoneKind, EM_NONE}); + + if (Ret.first == ELFNoneKind) { + if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") + error("Windows targets are not supported on the ELF frontend: " + S); + else + error("unknown emulation: " + S); + } + return Ret; } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. -static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB) { - ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB); - error(FileOrErr, "Failed to parse archive"); - std::unique_ptr<Archive> File = std::move(*FileOrErr); +std::vector<MemoryBufferRef> +LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { + std::unique_ptr<Archive> File = + check(Archive::create(MB), "failed to parse archive"); std::vector<MemoryBufferRef> V; - for (const ErrorOr<Archive::Child> &C : File->children()) { - error(C, "Could not get the child of the archive " + File->getFileName()); - ErrorOr<MemoryBufferRef> MbOrErr = C->getMemoryBufferRef(); - error(MbOrErr, "Could not get the buffer for a child of the archive " + - File->getFileName()); - V.push_back(*MbOrErr); + Error Err; + for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { + Archive::Child C = check(COrErr, "could not get the child of the archive " + + File->getFileName()); + MemoryBufferRef MBRef = + check(C.getMemoryBufferRef(), + "could not get the buffer for a child of the archive " + + File->getFileName()); + V.push_back(MBRef); } + if (Err) + Error(Err); + + // Take ownership of memory buffers created for members of thin archives. + for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) + OwningMBs.push_back(std::move(MB)); + return V; } // Opens and parses a file. Path has to be resolved already. // Newly created memory buffers are owned by this driver. void LinkerDriver::addFile(StringRef Path) { - using namespace llvm::sys::fs; + using namespace sys::fs; if (Config->Verbose) - llvm::outs() << Path << "\n"; - auto MBOrErr = MemoryBuffer::getFile(Path); - error(MBOrErr, "cannot open " + Path); - std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; - MemoryBufferRef MBRef = MB->getMemBufferRef(); - OwningMBs.push_back(std::move(MB)); // take MB ownership + outs() << Path << "\n"; + + Optional<MemoryBufferRef> Buffer = readFile(Path); + if (!Buffer.hasValue()) + return; + MemoryBufferRef MBRef = *Buffer; switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: - readLinkerScript(&Alloc, MBRef); + readLinkerScript(MBRef); return; case file_magic::archive: if (WholeArchive) { for (MemoryBufferRef MB : getArchiveMembers(MBRef)) - Files.push_back(createObjectFile(MB)); + Files.push_back(createObjectFile(MB, Path)); return; } Files.push_back(make_unique<ArchiveFile>(MBRef)); return; case file_magic::elf_shared_object: + if (Config->Relocatable) { + error("attempted static link of dynamic object " + Path); + return; + } Files.push_back(createSharedFile(MBRef)); return; default: - Files.push_back(createObjectFile(MBRef)); + if (InLib) + Files.push_back(make_unique<LazyObjectFile>(MBRef)); + else + Files.push_back(createObjectFile(MBRef)); } } +Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) { + auto MBOrErr = MemoryBuffer::getFile(Path); + if (auto EC = MBOrErr.getError()) { + error(EC, "cannot open " + Path); + return None; + } + std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take MB ownership + + if (Cpio) + Cpio->append(relativeToRoot(Path), MBRef.getBuffer()); + + return MBRef; +} + +// Add a given library by searching it from input search paths. +void LinkerDriver::addLibrary(StringRef Name) { + std::string Path = searchLibrary(Name); + if (Path.empty()) + error("unable to find library -l" + Name); + else + addFile(Path); +} + +// This function is called on startup. We need this for LTO since +// LTO calls LLVM functions to compile bitcode files to native code. +// Technically this can be delayed until we read bitcode files, but +// we don't bother to do lazily because the initialization is fast. +static void initLLVM(opt::InputArgList &Args) { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // This is a flag to discard all but GlobalValue names. + // We want to enable it by default because it saves memory. + // Disable it only when a developer option (-save-temps) is given. + Driver->Context.setDiscardValueNames(!Config->SaveTemps); + Driver->Context.enableDebugTypeODRUniquing(); + + // Parse and evaluate -mllvm options. + std::vector<const char *> V; + V.push_back("lld (LLVM option parsing)"); + for (auto *Arg : Args.filtered(OPT_mllvm)) + V.push_back(Arg->getValue()); + cl::ParseCommandLineOptions(V.size(), V.data()); +} + // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { - // Traditional linkers can generate re-linkable object files instead - // of executables or DSOs. We don't support that since the feature - // does not seem to provide more value than the static archiver. - if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); - // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) - error("The .gnu.hash section is not compatible with the MIPS target."); + error("the .gnu.hash section is not compatible with the MIPS target."); if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) error("-e option is not valid for AMDGPU."); + + if (Config->Pie && Config->Shared) + error("-shared and -pie may not be used together"); + + if (Config->Relocatable) { + if (Config->Shared) + error("-r and -shared may not be used together"); + if (Config->GcSections) + error("-r and --gc-sections may not be used together"); + if (Config->ICF) + error("-r and --icf may not be used together"); + if (Config->Pie) + error("-r and -pie may not be used together"); + } } static StringRef @@ -132,6 +231,22 @@ getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { return Default; } +static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { + int V = Default; + if (auto *Arg = Args.getLastArg(Key)) { + StringRef S = Arg->getValue(); + if (S.getAsInteger(10, V)) + error(Arg->getSpelling() + ": number expected, but got " + S); + } + return V; +} + +static const char *getReproduceOption(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_reproduce)) + return Arg->getValue(); + return getenv("LLD_REPRODUCE"); +} + static bool hasZOption(opt::InputArgList &Args, StringRef Key) { for (auto *Arg : Args.filtered(OPT_z)) if (Key == Arg->getValue()) @@ -140,12 +255,33 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { } void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { - initSymbols(); + ELFOptTable Parser; + opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); + return; + } + if (Args.hasArg(OPT_version)) { + outs() << getVersionString(); + return; + } + + if (const char *Path = getReproduceOption(Args)) { + // Note that --reproduce is a debug option so you can ignore it + // if you are trying to understand the whole picture of the code. + Cpio.reset(CpioFile::create(Path)); + if (Cpio) { + Cpio->append("response.txt", createResponseFile(Args)); + Cpio->append("version.txt", getVersionString()); + } + } - opt::InputArgList Args = parseArgs(&Alloc, ArgsArr); readConfigs(Args); + initLLVM(Args); createFiles(Args); checkOptions(Args); + if (HasError) + return; switch (Config->EKind) { case ELF32LEKind: @@ -165,6 +301,25 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { } } +static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) { + if (Args.hasArg(OPT_noinhibit_exec)) + return UnresolvedPolicy::Warn; + if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs")) + return UnresolvedPolicy::NoUndef; + if (Config->Relocatable) + return UnresolvedPolicy::Ignore; + + if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) { + StringRef S = Arg->getValue(); + if (S == "ignore-all" || S == "ignore-in-object-files") + return UnresolvedPolicy::Ignore; + if (S == "ignore-in-shared-libs" || S == "report-all") + return UnresolvedPolicy::Error; + error("unknown --unresolved-symbols value: " + S); + } + return UnresolvedPolicy::Error; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -185,38 +340,66 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); + Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->Demangle = !Args.hasArg(OPT_no_demangle); + Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->DiscardAll = Args.hasArg(OPT_discard_all); Config->DiscardLocals = Args.hasArg(OPT_discard_locals); Config->DiscardNone = Args.hasArg(OPT_discard_none); + Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr); Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); Config->ExportDynamic = Args.hasArg(OPT_export_dynamic); + Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings); Config->GcSections = Args.hasArg(OPT_gc_sections); - Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); - Config->NoUndefined = Args.hasArg(OPT_no_undefined); + Config->ICF = Args.hasArg(OPT_icf); + Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); + Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); + Config->Pie = Args.hasArg(OPT_pie); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); + Config->Relocatable = Args.hasArg(OPT_relocatable); + Config->SaveTemps = Args.hasArg(OPT_save_temps); Config->Shared = Args.hasArg(OPT_shared); Config->StripAll = Args.hasArg(OPT_strip_all); + Config->StripDebug = Args.hasArg(OPT_strip_debug); + Config->Threads = Args.hasArg(OPT_threads); + Config->Trace = Args.hasArg(OPT_trace); Config->Verbose = Args.hasArg(OPT_verbose); + Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->DynamicLinker = getString(Args, OPT_dynamic_linker); Config->Entry = getString(Args, OPT_entry); Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); + Config->LtoAAPipeline = getString(Args, OPT_lto_aa_pipeline); + Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); + Config->Optimize = getInteger(Args, OPT_O, 1); + Config->LtoO = getInteger(Args, OPT_lto_O, 2); + if (Config->LtoO > 3) + error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O)); + Config->LtoJobs = getInteger(Args, OPT_lto_jobs, 1); + if (Config->LtoJobs == 0) + error("number of threads must be > 0"); + + Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecStack = hasZOption(Args, "execstack"); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); - if (auto *Arg = Args.getLastArg(OPT_O)) { - StringRef Val = Arg->getValue(); - if (Val.getAsInteger(10, Config->Optimize)) - error("Invalid optimization level"); - } + if (Config->Relocatable) + Config->StripAll = false; + + // --strip-all implies --strip-debug. + if (Config->StripAll) + Config->StripDebug = true; + + // Config->Pic is true if we are generating position-independent code. + Config->Pic = Config->Pie || Config->Shared; if (auto *Arg = Args.getLastArg(OPT_hash_style)) { StringRef S = Arg->getValue(); @@ -226,19 +409,52 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") - error("Unknown hash style: " + S); + error("unknown hash style: " + S); + } + + // Parse --build-id or --build-id=<style>. + if (Args.hasArg(OPT_build_id)) + Config->BuildId = BuildIdKind::Fnv1; + if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) { + StringRef S = Arg->getValue(); + if (S == "md5") { + Config->BuildId = BuildIdKind::Md5; + } else if (S == "sha1") { + Config->BuildId = BuildIdKind::Sha1; + } else if (S == "none") { + Config->BuildId = BuildIdKind::None; + } else if (S.startswith("0x")) { + Config->BuildId = BuildIdKind::Hexstring; + Config->BuildIdVector = parseHex(S.substr(2)); + } else { + error("unknown --build-id style: " + S); + } } for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); + + Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); + + if (auto *Arg = Args.getLastArg(OPT_dynamic_list)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + parseDynamicList(*Buffer); + + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->DynamicList.push_back(Arg->getValue()); + + if (auto *Arg = Args.getLastArg(OPT_version_script)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + parseVersionScript(*Buffer); } void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: - addFile(searchLibrary(Arg->getValue())); + addLibrary(Arg->getValue()); break; + case OPT_alias_script_T: case OPT_INPUT: case OPT_script: addFile(Arg->getValue()); @@ -261,75 +477,112 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_no_whole_archive: WholeArchive = false; break; + case OPT_start_lib: + InLib = true; + break; + case OPT_end_lib: + InLib = false; + break; } } - if (Files.empty()) + if (Files.empty() && !HasError) error("no input files."); + + // If -m <machine_type> was not given, infer it from object files. + if (Config->EKind == ELFNoneKind) { + for (std::unique_ptr<InputFile> &F : Files) { + if (F->EKind == ELFNoneKind) + continue; + Config->EKind = F->EKind; + Config->EMachine = F->EMachine; + break; + } + } } +// Do actual linking. Note that when this function is called, +// all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable<ELFT> Symtab; - Target.reset(createTarget()); + elf::Symtab<ELFT>::X = &Symtab; - if (!Config->Shared) { - // Add entry symbol. - // - // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid - // having and undefined symbol. - if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU) - Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; + std::unique_ptr<TargetInfo> TI(createTarget()); + Target = TI.get(); + LinkerScript<ELFT> LS; + Script<ELFT>::X = &LS; - // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol - // is magical and is used to produce a R_386_GOTPC relocation. - // The R_386_GOTPC relocation value doesn't actually depend on the - // symbol value, so it could use an index of STN_UNDEF which, according - // to the spec, means the symbol value is 0. - // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in - // the object file. - // The situation is even stranger on x86_64 where the assembly doesn't - // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as - // an undefined symbol in the .o files. - // Given that the symbol is effectively unused, we just create a dummy - // hidden one to avoid the undefined symbol error. - Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); - } + Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64; + Config->Mips64EL = + (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind); + + // Add entry symbol. Note that AMDGPU binaries have no entry points. + if (Config->Entry.empty() && !Config->Shared && !Config->Relocatable && + Config->EMachine != EM_AMDGPU) + Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; + // Default output filename is "a.out" by the Unix tradition. + if (Config->OutputFile.empty()) + Config->OutputFile = "a.out"; + + // Handle --trace-symbol. + for (auto *Arg : Args.filtered(OPT_trace_symbol)) + Symtab.trace(Arg->getValue()); + + // Set either EntryAddr (if S is a number) or EntrySym (otherwise). if (!Config->Entry.empty()) { - // Set either EntryAddr (if S is a number) or EntrySym (otherwise). StringRef S = Config->Entry; if (S.getAsInteger(0, Config->EntryAddr)) Config->EntrySym = Symtab.addUndefined(S); } - if (Config->EMachine == EM_MIPS) { - // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and gp pointer into GOT. Use 'strong' variant of - // the addIgnored to prevent '_gp_disp' substitution. - Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp"); - - // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer - // so that it points to an absolute address which is relative to GOT. - // See "Global Data Symbols" in Chapter 6 in the following document: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp); + // Initialize Config->ImageBase. + if (auto *Arg = Args.getLastArg(OPT_image_base)) { + StringRef S = Arg->getValue(); + if (S.getAsInteger(0, Config->ImageBase)) + error(Arg->getSpelling() + ": number expected, but got " + S); + else if ((Config->ImageBase % Target->PageSize) != 0) + warning(Arg->getSpelling() + ": address isn't multiple of page size"); + } else { + Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase; } for (std::unique_ptr<InputFile> &F : Files) Symtab.addFile(std::move(F)); + if (HasError) + return; // There were duplicate symbols or incompatible files + + Symtab.scanUndefinedFlags(); + Symtab.scanShlibUndefined(); + Symtab.scanDynamicList(); + Symtab.scanVersionScript(); + Symtab.scanSymbolVersions(); - for (StringRef S : Config->Undefined) - Symtab.addUndefinedOpt(S); + Symtab.addCombinedLtoObject(); + if (HasError) + return; for (auto *Arg : Args.filtered(OPT_wrap)) Symtab.wrap(Arg->getValue()); - if (Config->OutputFile.empty()) - Config->OutputFile = "a.out"; - // Write the result to the file. - Symtab.scanShlibUndefined(); if (Config->GcSections) - markLive<ELFT>(&Symtab); + markLive<ELFT>(); + if (Config->ICF) + doIcf<ELFT>(); + + // MergeInputSection::splitIntoPieces needs to be called before + // any call of MergeInputSection::getOffset. Do that. + for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : + Symtab.getObjectFiles()) + for (InputSectionBase<ELFT> *S : F->getSections()) { + if (!S || S == &InputSection<ELFT>::Discarded || !S->Live) + continue; + if (S->Compressed) + S->uncompress(); + if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) + MS->splitIntoPieces(); + } + writeResult<ELFT>(&Symtab); } diff --git a/ELF/Driver.h b/ELF/Driver.h index 720ef46dc710..6b9b9bb208e5 100644 --- a/ELF/Driver.h +++ b/ELF/Driver.h @@ -12,36 +12,54 @@ #include "SymbolTable.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/raw_ostream.h" namespace lld { -namespace elf2 { +namespace elf { extern class LinkerDriver *Driver; -// Entry point of the ELF linker. -void link(ArrayRef<const char *> Args); +class CpioFile; class LinkerDriver { public: void main(ArrayRef<const char *> Args); void addFile(StringRef Path); + void addLibrary(StringRef Name); + llvm::LLVMContext Context; // to parse bitcode ifles + std::unique_ptr<CpioFile> Cpio; // for reproduce private: + std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB); + llvm::Optional<MemoryBufferRef> readFile(StringRef Path); void readConfigs(llvm::opt::InputArgList &Args); void createFiles(llvm::opt::InputArgList &Args); template <class ELFT> void link(llvm::opt::InputArgList &Args); - llvm::BumpPtrAllocator Alloc; + // True if we are in --whole-archive and --no-whole-archive. bool WholeArchive = false; + + // True if we are in --start-lib and --end-lib. + bool InLib = false; + + llvm::BumpPtrAllocator Alloc; std::vector<std::unique_ptr<InputFile>> Files; std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs; }; // Parses command line options. -llvm::opt::InputArgList parseArgs(llvm::BumpPtrAllocator *A, - ArrayRef<const char *> Args); +class ELFOptTable : public llvm::opt::OptTable { +public: + ELFOptTable(); + llvm::opt::InputArgList parse(ArrayRef<const char *> Argv); + +private: + llvm::BumpPtrAllocator Alloc; +}; // Create enum with OPT_xxx values for each option in Options.td enum { @@ -51,14 +69,43 @@ enum { #undef OPTION }; -// Parses a linker script. Calling this function updates the Symtab and Config. -void readLinkerScript(llvm::BumpPtrAllocator *A, MemoryBufferRef MB); +// This is the class to create a .cpio file for --reproduce. +// +// If "--reproduce foo" is given, we create a file "foo.cpio" and +// copy all input files to the archive, along with a response file +// to re-run the same command with the same inputs. +// It is useful for reporting issues to LLD developers. +// +// Cpio as a file format is a deliberate choice. It's standardized in +// POSIX and very easy to create. cpio command is available virtually +// on all Unix systems. See +// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07 +// for the format details. +class CpioFile { +public: + static CpioFile *create(StringRef OutputPath); + void append(StringRef Path, StringRef Data); + +private: + CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename); + + std::unique_ptr<llvm::raw_fd_ostream> OS; + llvm::StringSet<> Seen; + std::string Basename; +}; + +void printHelp(const char *Argv0); +std::string getVersionString(); +std::vector<uint8_t> parseHexstring(StringRef S); + +std::string createResponseFile(const llvm::opt::InputArgList &Args); +std::string relativeToRoot(StringRef Path); std::string findFromSearchPaths(StringRef Path); std::string searchLibrary(StringRef Path); std::string buildSysrootedPath(llvm::StringRef Dir, llvm::StringRef File); -} // namespace elf2 +} // namespace elf } // namespace lld #endif diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp index 965ed4f00a61..3f18259b4ae7 100644 --- a/ELF/DriverUtils.cpp +++ b/ELF/DriverUtils.cpp @@ -15,16 +15,20 @@ #include "Driver.h" #include "Error.h" +#include "lld/Config/Version.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/StringSaver.h" using namespace llvm; +using namespace llvm::sys; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; // Create OptTable @@ -34,55 +38,208 @@ using namespace lld::elf2; #undef PREFIX // Create table mapping all options defined in Options.td -static const opt::OptTable::Info infoTable[] = { +static const opt::OptTable::Info OptInfo[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ { \ X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \ OPT_##ALIAS, X6 \ - } \ - , + }, #include "Options.inc" #undef OPTION }; -class ELFOptTable : public opt::OptTable { -public: - ELFOptTable() : OptTable(infoTable) {} -}; +ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} + +static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { + StringRef S = Arg->getValue(); + if (S != "windows" && S != "posix") + error("invalid response file quoting: " + S); + if (S == "windows") + return cl::TokenizeWindowsCommandLine; + return cl::TokenizeGNUCommandLine; + } + if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) + return cl::TokenizeWindowsCommandLine; + return cl::TokenizeGNUCommandLine; +} // Parses a given list of options. -opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, - ArrayRef<const char *> Argv) { +opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. - ELFOptTable Table; unsigned MissingIndex; unsigned MissingCount; + SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); + + // We need to get the quoting style for response files before parsing all + // options so we parse here before and ignore all the options but + // --rsp-quoting. + opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); // Expand response files. '@<filename>' is replaced by the file's contents. - SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); - StringSaver Saver(*A); - llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, Vec); + StringSaver Saver(Alloc); + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); // Parse options and then do error checking. - opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + Args = this->ParseArgs(Vec, MissingIndex, MissingCount); if (MissingCount) error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + "\", expected " + Twine(MissingCount) + (MissingCount == 1 ? " argument.\n" : " arguments")); - iterator_range<opt::arg_iterator> Unknowns = Args.filtered(OPT_UNKNOWN); - for (auto *Arg : Unknowns) - warning("warning: unknown argument: " + Arg->getSpelling()); - if (Unknowns.begin() != Unknowns.end()) - error("unknown argument(s) found"); - + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) + error("unknown argument: " + Arg->getSpelling()); return Args; } -std::string elf2::findFromSearchPaths(StringRef Path) { +void elf::printHelp(const char *Argv0) { + ELFOptTable Table; + Table.PrintHelp(outs(), Argv0, "lld", false); +} + +std::string elf::getVersionString() { + std::string Version = getLLDVersion(); + std::string Repo = getLLDRepositoryVersion(); + if (Repo.empty()) + return "LLD " + Version + "\n"; + return "LLD " + Version + " " + Repo + "\n"; +} + +// Makes a given pathname an absolute path first, and then remove +// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", +// assuming that the current directory is "/home/john/bar". +std::string elf::relativeToRoot(StringRef Path) { + SmallString<128> Abs = Path; + if (std::error_code EC = fs::make_absolute(Abs)) + fatal("make_absolute failed: " + EC.message()); + path::remove_dots(Abs, /*remove_dot_dot=*/true); + + // This is Windows specific. root_name() returns a drive letter + // (e.g. "c:") or a UNC name (//net). We want to keep it as part + // of the result. + SmallString<128> Res; + StringRef Root = path::root_name(Abs); + if (Root.endswith(":")) + Res = Root.drop_back(); + else if (Root.startswith("//")) + Res = Root.substr(2); + + path::append(Res, path::relative_path(Abs)); + return Res.str(); +} + +CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S) + : OS(std::move(OS)), Basename(S) {} + +CpioFile *CpioFile::create(StringRef OutputPath) { + std::string Path = (OutputPath + ".cpio").str(); + std::error_code EC; + auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None); + if (EC) { + error(EC, "--reproduce: failed to open " + Path); + return nullptr; + } + return new CpioFile(std::move(OS), path::filename(OutputPath)); +} + +static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { + // The c_dev/c_ino pair should be unique according to the spec, + // but no one seems to care. + OS << "070707"; // c_magic + OS << "000000"; // c_dev + OS << "000000"; // c_ino + OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- + OS << "000000"; // c_uid + OS << "000000"; // c_gid + OS << "000001"; // c_nlink + OS << "000000"; // c_rdev + OS << "00000000000"; // c_mtime + OS << format("%06o", Path.size() + 1); // c_namesize + OS << format("%011o", Data.size()); // c_filesize + OS << Path << '\0'; // c_name + OS << Data; // c_filedata +} + +void CpioFile::append(StringRef Path, StringRef Data) { + if (!Seen.insert(Path).second) + return; + + // Construct an in-archive filename so that /home/foo/bar is stored + // as baz/home/foo/bar where baz is the basename of the output file. + // (i.e. in that case we are creating baz.cpio.) + SmallString<128> Fullpath; + path::append(Fullpath, Basename, Path); + + // Use unix path separators so the cpio can be extracted on both unix and + // windows. + std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/'); + + writeMember(*OS, Fullpath, Data); + + // Print the trailer and seek back. + // This way we have a valid archive if we crash. + uint64_t Pos = OS->tell(); + writeMember(*OS, "TRAILER!!!", ""); + OS->seek(Pos); +} + +// Quote a given string if it contains a space character. +static std::string quote(StringRef S) { + if (S.find(' ') == StringRef::npos) + return S; + return ("\"" + S + "\"").str(); +} + +static std::string rewritePath(StringRef S) { + if (fs::exists(S)) + return relativeToRoot(S); + return S; +} + +static std::string stringize(opt::Arg *Arg) { + std::string K = Arg->getSpelling(); + if (Arg->getNumValues() == 0) + return K; + std::string V = quote(Arg->getValue()); + if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) + return K + V; + return K + " " + V; +} + +// Reconstructs command line arguments so that so that you can re-run +// the same command with the same inputs. This is for --reproduce. +std::string elf::createResponseFile(const opt::InputArgList &Args) { + SmallString<0> Data; + raw_svector_ostream OS(Data); + + // Copy the command line to the output while rewriting paths. + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_reproduce: + break; + case OPT_INPUT: + OS << quote(rewritePath(Arg->getValue())) << "\n"; + break; + case OPT_L: + case OPT_dynamic_list: + case OPT_rpath: + case OPT_alias_script_T: + case OPT_script: + case OPT_version_script: + OS << Arg->getSpelling() << " " + << quote(rewritePath(Arg->getValue())) << "\n"; + break; + default: + OS << stringize(Arg) << "\n"; + } + } + return Data.str(); +} + +std::string elf::findFromSearchPaths(StringRef Path) { for (StringRef Dir : Config->SearchPaths) { std::string FullPath = buildSysrootedPath(Dir, Path); - if (sys::fs::exists(FullPath)) + if (fs::exists(FullPath)) return FullPath; } return ""; @@ -90,31 +247,30 @@ std::string elf2::findFromSearchPaths(StringRef Path) { // Searches a given library from input search paths, which are filled // from -L command line switches. Returns a path to an existent library file. -std::string elf2::searchLibrary(StringRef Path) { - std::vector<std::string> Names; - if (Path[0] == ':') { - Names.push_back(Path.drop_front()); - } else { - if (!Config->Static) - Names.push_back(("lib" + Path + ".so").str()); - Names.push_back(("lib" + Path + ".a").str()); - } - for (const std::string &Name : Names) { - std::string S = findFromSearchPaths(Name); - if (!S.empty()) +std::string elf::searchLibrary(StringRef Path) { + if (Path.startswith(":")) + return findFromSearchPaths(Path.substr(1)); + for (StringRef Dir : Config->SearchPaths) { + if (!Config->Static) { + std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str()); + if (fs::exists(S)) + return S; + } + std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str()); + if (fs::exists(S)) return S; } - error("Unable to find library -l" + Path); + return ""; } // Makes a path by concatenating Dir and File. // If Dir starts with '=' the result will be preceded by Sysroot, // which can be set with --sysroot command line switch. -std::string elf2::buildSysrootedPath(StringRef Dir, StringRef File) { +std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) { SmallString<128> Path; if (Dir.startswith("=")) - sys::path::append(Path, Config->Sysroot, Dir.substr(1), File); + path::append(Path, Config->Sysroot, Dir.substr(1), File); else - sys::path::append(Path, Dir, File); + path::append(Path, Dir, File); return Path.str(); } diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp new file mode 100644 index 000000000000..b130ac1ca22d --- /dev/null +++ b/ELF/EhFrame.cpp @@ -0,0 +1,167 @@ +//===- EhFrame.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// .eh_frame section contains information on how to unwind the stack when +// an exception is thrown. The section consists of sequence of CIE and FDE +// records. The linker needs to merge CIEs and associate FDEs to CIEs. +// That means the linker has to understand the format of the section. +// +// This file contains a few utility functions to read .eh_frame contents. +// +//===----------------------------------------------------------------------===// + +#include "EhFrame.h" +#include "Error.h" + +#include "llvm/Object/ELF.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::dwarf; +using namespace llvm::object; +using namespace llvm::support::endian; + +namespace lld { +namespace elf { + +// .eh_frame section is a sequence of records. Each record starts with +// a 4 byte length field. This function reads the length. +template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> D) { + const endianness E = ELFT::TargetEndianness; + if (D.size() < 4) + fatal("CIE/FDE too small"); + + // First 4 bytes of CIE/FDE is the size of the record. + // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead, + // but we do not support that format yet. + uint64_t V = read32<E>(D.data()); + if (V == UINT32_MAX) + fatal("CIE/FDE too large"); + uint64_t Size = V + 4; + if (Size > D.size()) + fatal("CIE/FIE ends past the end of the section"); + return Size; +} + +// Read a byte and advance D by one byte. +static uint8_t readByte(ArrayRef<uint8_t> &D) { + if (D.empty()) + fatal("corrupted or unsupported CIE information"); + uint8_t B = D.front(); + D = D.slice(1); + return B; +} + +// Skip an integer encoded in the LEB128 format. +// Actual number is not of interest because only the runtime needs it. +// But we need to be at least able to skip it so that we can read +// the field that follows a LEB128 number. +static void skipLeb128(ArrayRef<uint8_t> &D) { + while (!D.empty()) { + uint8_t Val = D.front(); + D = D.slice(1); + if ((Val & 0x80) == 0) + return; + } + fatal("corrupted or unsupported CIE information"); +} + +template <class ELFT> static size_t getAugPSize(unsigned Enc) { + switch (Enc & 0x0f) { + case DW_EH_PE_absptr: + case DW_EH_PE_signed: + return ELFT::Is64Bits ? 8 : 4; + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: + return 2; + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: + return 4; + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + return 8; + } + fatal("unknown FDE encoding"); +} + +template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) { + uint8_t Enc = readByte(D); + if ((Enc & 0xf0) == DW_EH_PE_aligned) + fatal("DW_EH_PE_aligned encoding is not supported"); + size_t Size = getAugPSize<ELFT>(Enc); + if (Size >= D.size()) + fatal("corrupted CIE"); + D = D.slice(Size); +} + +template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> D) { + if (D.size() < 8) + fatal("CIE too small"); + D = D.slice(8); + + uint8_t Version = readByte(D); + if (Version != 1 && Version != 3) + fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version)); + + const unsigned char *AugEnd = std::find(D.begin(), D.end(), '\0'); + if (AugEnd == D.end()) + fatal("corrupted CIE"); + StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin()); + D = D.slice(Aug.size() + 1); + + // Code alignment factor should always be 1 for .eh_frame. + if (readByte(D) != 1) + fatal("CIE code alignment must be 1"); + + // Skip data alignment factor. + skipLeb128(D); + + // Skip the return address register. In CIE version 1 this is a single + // byte. In CIE version 3 this is an unsigned LEB128. + if (Version == 1) + readByte(D); + else + skipLeb128(D); + + // We only care about an 'R' value, but other records may precede an 'R' + // record. Unfortunately records are not in TLV (type-length-value) format, + // so we need to teach the linker how to skip records for each type. + for (char C : Aug) { + if (C == 'R') + return readByte(D); + if (C == 'z') { + skipLeb128(D); + continue; + } + if (C == 'P') { + skipAugP<ELFT>(D); + continue; + } + if (C == 'L') { + readByte(D); + continue; + } + fatal("unknown .eh_frame augmentation string: " + Aug); + } + return DW_EH_PE_absptr; +} + +template size_t readEhRecordSize<ELF32LE>(ArrayRef<uint8_t>); +template size_t readEhRecordSize<ELF32BE>(ArrayRef<uint8_t>); +template size_t readEhRecordSize<ELF64LE>(ArrayRef<uint8_t>); +template size_t readEhRecordSize<ELF64BE>(ArrayRef<uint8_t>); + +template uint8_t getFdeEncoding<ELF32LE>(ArrayRef<uint8_t>); +template uint8_t getFdeEncoding<ELF32BE>(ArrayRef<uint8_t>); +template uint8_t getFdeEncoding<ELF64LE>(ArrayRef<uint8_t>); +template uint8_t getFdeEncoding<ELF64BE>(ArrayRef<uint8_t>); +} +} diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h new file mode 100644 index 000000000000..0d5a2ff2f417 --- /dev/null +++ b/ELF/EhFrame.h @@ -0,0 +1,22 @@ +//===- EhFrame.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_EHFRAME_H +#define LLD_ELF_EHFRAME_H + +#include "lld/Core/LLVM.h" + +namespace lld { +namespace elf { +template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> Data); +template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> Data); +} +} + +#endif diff --git a/ELF/Error.cpp b/ELF/Error.cpp index e0701f7f4cc6..59a49c17b97c 100644 --- a/ELF/Error.cpp +++ b/ELF/Error.cpp @@ -8,31 +8,58 @@ //===----------------------------------------------------------------------===// #include "Error.h" +#include "Config.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" +using namespace llvm; + namespace lld { -namespace elf2 { +namespace elf { + +bool HasError; +raw_ostream *ErrorOS; -void warning(const Twine &Msg) { llvm::errs() << Msg << "\n"; } +void log(const Twine &Msg) { + if (Config->Verbose) + outs() << Msg << "\n"; +} + +void warning(const Twine &Msg) { + if (Config->FatalWarnings) + error(Msg); + else + *ErrorOS << Msg << "\n"; +} void error(const Twine &Msg) { - llvm::errs() << Msg << "\n"; - exit(1); + *ErrorOS << Msg << "\n"; + HasError = true; } void error(std::error_code EC, const Twine &Prefix) { - if (!EC) - return; error(Prefix + ": " + EC.message()); } -void error(std::error_code EC) { - if (!EC) - return; - error(EC.message()); +void fatal(const Twine &Msg) { + *ErrorOS << Msg << "\n"; + exit(1); +} + +void fatal(const Twine &Msg, const Twine &Prefix) { + fatal(Prefix + ": " + Msg); +} + +void check(std::error_code EC) { + if (EC) + fatal(EC.message()); +} + +void check(Error Err) { + check(errorToErrorCode(std::move(Err))); } -} // namespace elf2 +} // namespace elf } // namespace lld diff --git a/ELF/Error.h b/ELF/Error.h index b1d2e7a8fc5b..552f50498464 100644 --- a/ELF/Error.h +++ b/ELF/Error.h @@ -13,20 +13,49 @@ #include "lld/Core/LLVM.h" namespace lld { -namespace elf2 { +namespace elf { +extern bool HasError; +extern llvm::raw_ostream *ErrorOS; + +void log(const Twine &Msg); void warning(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg); +void error(const Twine &Msg); void error(std::error_code EC, const Twine &Prefix); -void error(std::error_code EC); template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) { error(V.getError(), Prefix); } -template <typename T> void error(const ErrorOr<T> &V) { error(V.getError()); } -} // namespace elf2 +LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); +LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg, const Twine &Prefix); + +template <class T> T check(ErrorOr<T> E) { + if (auto EC = E.getError()) + fatal(EC.message()); + return std::move(*E); +} + +template <class T> T check(Expected<T> E) { + if (!E) + fatal(errorToErrorCode(E.takeError()).message()); + return std::move(*E); +} + +template <class T> T check(ErrorOr<T> E, const Twine &Prefix) { + if (auto EC = E.getError()) + fatal(EC.message(), Prefix); + return std::move(*E); +} + +template <class T> T check(Expected<T> E, const Twine &Prefix) { + if (!E) + fatal(errorToErrorCode(E.takeError()).message(), Prefix); + return std::move(*E); +} + +} // namespace elf } // namespace lld #endif diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp new file mode 100644 index 000000000000..10a2603b3b3e --- /dev/null +++ b/ELF/ICF.cpp @@ -0,0 +1,345 @@ +//===- ICF.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Identical Code Folding is a feature to merge sections not by name (which +// is regular comdat handling) but by contents. If two non-writable sections +// have the same data, relocations, attributes, etc., then the two +// are considered identical and merged by the linker. This optimization +// makes outputs smaller. +// +// ICF is theoretically a problem of reducing graphs by merging as many +// identical subgraphs as possible if we consider sections as vertices and +// relocations as edges. It may sound simple, but it is a bit more +// complicated than you might think. The order of processing sections +// matters because merging two sections can make other sections, whose +// relocations now point to the same section, mergeable. Graphs may contain +// cycles. We need a sophisticated algorithm to do this properly and +// efficiently. +// +// What we do in this file is this. We split sections into groups. Sections +// in the same group are considered identical. +// +// We begin by optimistically putting all sections into a single equivalence +// class. Then we apply a series of checks that split this initial +// equivalence class into more and more refined equivalence classes based on +// the properties by which a section can be distinguished. +// +// We begin by checking that the section contents and flags are the +// same. This only needs to be done once since these properties don't depend +// on the current equivalence class assignment. +// +// Then we split the equivalence classes based on checking that their +// relocations are the same, where relocation targets are compared by their +// equivalence class, not the concrete section. This may need to be done +// multiple times because as the equivalence classes are refined, two +// sections that had a relocation target in the same equivalence class may +// now target different equivalence classes, and hence these two sections +// must be put in different equivalence classes (whereas in the previous +// iteration they were not since the relocation target was the same.) +// +// Our algorithm is smart enough to merge the following mutually-recursive +// functions. +// +// void foo() { bar(); } +// void bar() { foo(); } +// +// This algorithm is so-called "optimistic" algorithm described in +// http://research.google.com/pubs/pub36912.html. (Note that what GNU +// gold implemented is different from the optimistic algorithm.) +// +//===----------------------------------------------------------------------===// + +#include "ICF.h" +#include "Config.h" +#include "OutputSections.h" +#include "SymbolTable.h" + +#include "llvm/ADT/Hashing.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lld; +using namespace lld::elf; +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; + +namespace lld { +namespace elf { +template <class ELFT> class ICF { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; + typedef Elf_Rel_Impl<ELFT, false> Elf_Rel; + + using Comparator = std::function<bool(const InputSection<ELFT> *, + const InputSection<ELFT> *)>; + +public: + void run(); + +private: + uint64_t NextId = 1; + + static void setLive(SymbolTable<ELFT> *S); + static uint64_t relSize(InputSection<ELFT> *S); + static uint64_t getHash(InputSection<ELFT> *S); + static bool isEligible(InputSectionBase<ELFT> *Sec); + static std::vector<InputSection<ELFT> *> getSections(); + + void segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End, + Comparator Eq); + + void forEachGroup(std::vector<InputSection<ELFT> *> &V, Comparator Eq); + + template <class RelTy> + static bool relocationEq(ArrayRef<RelTy> RA, ArrayRef<RelTy> RB); + + template <class RelTy> + static bool variableEq(const InputSection<ELFT> *A, + const InputSection<ELFT> *B, ArrayRef<RelTy> RA, + ArrayRef<RelTy> RB); + + static bool equalsConstant(const InputSection<ELFT> *A, + const InputSection<ELFT> *B); + + static bool equalsVariable(const InputSection<ELFT> *A, + const InputSection<ELFT> *B); +}; +} +} + +// Returns a hash value for S. Note that the information about +// relocation targets is not included in the hash value. +template <class ELFT> uint64_t ICF<ELFT>::getHash(InputSection<ELFT> *S) { + uint64_t Flags = S->getSectionHdr()->sh_flags; + uint64_t H = hash_combine(Flags, S->getSize()); + for (const Elf_Shdr *Rel : S->RelocSections) + H = hash_combine(H, (uint64_t)Rel->sh_size); + return H; +} + +// Returns true if Sec is subject of ICF. +template <class ELFT> bool ICF<ELFT>::isEligible(InputSectionBase<ELFT> *Sec) { + if (!Sec || Sec == &InputSection<ELFT>::Discarded || !Sec->Live) + return false; + auto *S = dyn_cast<InputSection<ELFT>>(Sec); + if (!S) + return false; + + // .init and .fini contains instructions that must be executed to + // initialize and finalize the process. They cannot and should not + // be merged. + StringRef Name = S->getSectionName(); + if (Name == ".init" || Name == ".fini") + return false; + + const Elf_Shdr &H = *S->getSectionHdr(); + return (H.sh_flags & SHF_ALLOC) && (~H.sh_flags & SHF_WRITE); +} + +template <class ELFT> +std::vector<InputSection<ELFT> *> ICF<ELFT>::getSections() { + std::vector<InputSection<ELFT> *> V; + for (const std::unique_ptr<ObjectFile<ELFT>> &F : + Symtab<ELFT>::X->getObjectFiles()) + for (InputSectionBase<ELFT> *S : F->getSections()) + if (isEligible(S)) + V.push_back(cast<InputSection<ELFT>>(S)); + return V; +} + +// All sections between Begin and End must have the same group ID before +// you call this function. This function compare sections between Begin +// and End using Eq and assign new group IDs for new groups. +template <class ELFT> +void ICF<ELFT>::segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End, + Comparator Eq) { + // This loop rearranges [Begin, End) so that all sections that are + // equal in terms of Eq are contiguous. The algorithm is quadratic in + // the worst case, but that is not an issue in practice because the + // number of distinct sections in [Begin, End) is usually very small. + InputSection<ELFT> **I = Begin; + for (;;) { + InputSection<ELFT> *Head = *I; + auto Bound = std::stable_partition( + I + 1, End, [&](InputSection<ELFT> *S) { return Eq(Head, S); }); + if (Bound == End) + return; + uint64_t Id = NextId++; + for (; I != Bound; ++I) + (*I)->GroupId = Id; + } +} + +template <class ELFT> +void ICF<ELFT>::forEachGroup(std::vector<InputSection<ELFT> *> &V, + Comparator Eq) { + for (InputSection<ELFT> **I = V.data(), **E = I + V.size(); I != E;) { + InputSection<ELFT> *Head = *I; + auto Bound = std::find_if(I + 1, E, [&](InputSection<ELFT> *S) { + return S->GroupId != Head->GroupId; + }); + segregate(I, Bound, Eq); + I = Bound; + } +} + +// Compare two lists of relocations. +template <class ELFT> +template <class RelTy> +bool ICF<ELFT>::relocationEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) { + const RelTy *IA = RelsA.begin(); + const RelTy *EA = RelsA.end(); + const RelTy *IB = RelsB.begin(); + const RelTy *EB = RelsB.end(); + if (EA - IA != EB - IB) + return false; + for (; IA != EA; ++IA, ++IB) + if (IA->r_offset != IB->r_offset || + IA->getType(Config->Mips64EL) != IB->getType(Config->Mips64EL) || + getAddend<ELFT>(*IA) != getAddend<ELFT>(*IB)) + return false; + return true; +} + +// Compare "non-moving" part of two InputSections, namely everything +// except relocation targets. +template <class ELFT> +bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A, + const InputSection<ELFT> *B) { + if (A->RelocSections.size() != B->RelocSections.size()) + return false; + + for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) { + const Elf_Shdr *RA = A->RelocSections[I]; + const Elf_Shdr *RB = B->RelocSections[I]; + ELFFile<ELFT> &FileA = A->File->getObj(); + ELFFile<ELFT> &FileB = B->File->getObj(); + if (RA->sh_type == SHT_RELA) { + if (!relocationEq(FileA.relas(RA), FileB.relas(RB))) + return false; + } else { + if (!relocationEq(FileA.rels(RA), FileB.rels(RB))) + return false; + } + } + + return A->getSectionHdr()->sh_flags == B->getSectionHdr()->sh_flags && + A->getSize() == B->getSize() && + A->getSectionData() == B->getSectionData(); +} + +template <class ELFT> +template <class RelTy> +bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, + const InputSection<ELFT> *B, ArrayRef<RelTy> RelsA, + ArrayRef<RelTy> RelsB) { + const RelTy *IA = RelsA.begin(); + const RelTy *EA = RelsA.end(); + const RelTy *IB = RelsB.begin(); + for (; IA != EA; ++IA, ++IB) { + SymbolBody &SA = A->File->getRelocTargetSym(*IA); + SymbolBody &SB = B->File->getRelocTargetSym(*IB); + if (&SA == &SB) + continue; + + // Or, the symbols should be pointing to the same section + // in terms of the group ID. + auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA); + auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB); + if (!DA || !DB) + return false; + if (DA->Value != DB->Value) + return false; + InputSection<ELFT> *X = dyn_cast<InputSection<ELFT>>(DA->Section); + InputSection<ELFT> *Y = dyn_cast<InputSection<ELFT>>(DB->Section); + if (X && Y && X->GroupId && X->GroupId == Y->GroupId) + continue; + return false; + } + return true; +} + +// Compare "moving" part of two InputSections, namely relocation targets. +template <class ELFT> +bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A, + const InputSection<ELFT> *B) { + for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) { + const Elf_Shdr *RA = A->RelocSections[I]; + const Elf_Shdr *RB = B->RelocSections[I]; + ELFFile<ELFT> &FileA = A->File->getObj(); + ELFFile<ELFT> &FileB = B->File->getObj(); + if (RA->sh_type == SHT_RELA) { + if (!variableEq(A, B, FileA.relas(RA), FileB.relas(RB))) + return false; + } else { + if (!variableEq(A, B, FileA.rels(RA), FileB.rels(RB))) + return false; + } + } + return true; +} + +// The main function of ICF. +template <class ELFT> void ICF<ELFT>::run() { + // Initially, we use hash values as section group IDs. Therefore, + // if two sections have the same ID, they are likely (but not + // guaranteed) to have the same static contents in terms of ICF. + std::vector<InputSection<ELFT> *> V = getSections(); + for (InputSection<ELFT> *S : V) + // Set MSB on to avoid collisions with serial group IDs + S->GroupId = getHash(S) | (uint64_t(1) << 63); + + // From now on, sections in V are ordered so that sections in + // the same group are consecutive in the vector. + std::stable_sort(V.begin(), V.end(), + [](InputSection<ELFT> *A, InputSection<ELFT> *B) { + return A->GroupId < B->GroupId; + }); + + // Compare static contents and assign unique IDs for each static content. + forEachGroup(V, equalsConstant); + + // Split groups by comparing relocations until we get a convergence. + int Cnt = 1; + for (;;) { + ++Cnt; + uint64_t Id = NextId; + forEachGroup(V, equalsVariable); + if (Id == NextId) + break; + } + log("ICF needed " + Twine(Cnt) + " iterations."); + + // Merge sections in the same group. + for (auto I = V.begin(), E = V.end(); I != E;) { + InputSection<ELFT> *Head = *I++; + auto Bound = std::find_if(I, E, [&](InputSection<ELFT> *S) { + return Head->GroupId != S->GroupId; + }); + if (I == Bound) + continue; + log("selected " + Head->getSectionName()); + while (I != Bound) { + InputSection<ELFT> *S = *I++; + log(" removed " + S->getSectionName()); + Head->replace(S); + } + } +} + +// ICF entry point function. +template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); } + +template void elf::doIcf<ELF32LE>(); +template void elf::doIcf<ELF32BE>(); +template void elf::doIcf<ELF64LE>(); +template void elf::doIcf<ELF64BE>(); diff --git a/ELF/ICF.h b/ELF/ICF.h new file mode 100644 index 000000000000..502e128c8109 --- /dev/null +++ b/ELF/ICF.h @@ -0,0 +1,19 @@ +//===- ICF.h --------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_ICF_H +#define LLD_ELF_ICF_H + +namespace lld { +namespace elf { +template <class ELFT> void doIcf(); +} +} + +#endif diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 6a908d450f60..57e556395937 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -8,10 +8,17 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "InputSection.h" +#include "Driver.h" #include "Error.h" +#include "InputSection.h" +#include "SymbolTable.h" #include "Symbols.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/Analysis.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; @@ -19,43 +26,52 @@ using namespace llvm::object; using namespace llvm::sys::fs; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; -namespace { -class ECRAII { - std::error_code EC; - -public: - std::error_code &getEC() { return EC; } - ~ECRAII() { error(EC); } -}; +// Returns "(internal)", "foo.a(bar.o)" or "baz.o". +std::string elf::getFilename(const InputFile *F) { + if (!F) + return "(internal)"; + if (!F->ArchiveName.empty()) + return (F->ArchiveName + "(" + F->getName() + ")").str(); + return F->getName(); } template <class ELFT> -ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef M) - : InputFile(K, M), ELFObj(MB.getBuffer(), ECRAII().getEC()) {} +static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) { + std::error_code EC; + ELFFile<ELFT> F(MB.getBuffer(), EC); + if (EC) + error(EC, "failed to read " + MB.getBufferIdentifier()); + return F; +} -template <class ELFT> -ELFKind ELFFileBase<ELFT>::getELFKind() { +template <class ELFT> static ELFKind getELFKind() { if (ELFT::TargetEndianness == support::little) return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; } template <class ELFT> -typename ELFFileBase<ELFT>::Elf_Sym_Range -ELFFileBase<ELFT>::getSymbolsHelper(bool Local) { +ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) + : InputFile(K, MB), ELFObj(createELFObj<ELFT>(MB)) { + EKind = getELFKind<ELFT>(); + EMachine = ELFObj.getHeader()->e_machine; +} + +template <class ELFT> +typename ELFT::SymRange ELFFileBase<ELFT>::getElfSymbols(bool OnlyGlobals) { if (!Symtab) return Elf_Sym_Range(nullptr, nullptr); Elf_Sym_Range Syms = ELFObj.symbols(Symtab); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); uint32_t FirstNonLocal = Symtab->sh_info; if (FirstNonLocal > NumSymbols) - error("Invalid sh_info in symbol table"); - if (!Local) - return make_range(Syms.begin() + FirstNonLocal, Syms.end()); - // +1 to skip over dummy symbol. - return make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal); + fatal(getFilename(this) + ": invalid sh_info in symbol table"); + + if (OnlyGlobals) + return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end()); + return makeArrayRef(Syms.begin(), Syms.end()); } template <class ELFT> @@ -63,7 +79,7 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { uint32_t I = Sym.st_shndx; if (I == ELF::SHN_XINDEX) return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX); - if (I >= ELF::SHN_LORESERVE || I == ELF::SHN_ABS) + if (I >= ELF::SHN_LORESERVE) return 0; return I; } @@ -71,44 +87,46 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { template <class ELFT> void ELFFileBase<ELFT>::initStringTable() { if (!Symtab) return; - ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab); - error(StringTableOrErr); - StringTable = *StringTableOrErr; + StringTable = check(ELFObj.getStringTableForSymtab(*Symtab)); } template <class ELFT> -typename ELFFileBase<ELFT>::Elf_Sym_Range -ELFFileBase<ELFT>::getNonLocalSymbols() { - return getSymbolsHelper(false); +elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M) + : ELFFileBase<ELFT>(Base::ObjectKind, M) {} + +template <class ELFT> +ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() { + if (!this->Symtab) + return this->SymbolBodies; + uint32_t FirstNonLocal = this->Symtab->sh_info; + return makeArrayRef(this->SymbolBodies).slice(FirstNonLocal); } template <class ELFT> -ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M) - : ELFFileBase<ELFT>(Base::ObjectKind, M) {} +ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() { + if (!this->Symtab) + return this->SymbolBodies; + uint32_t FirstNonLocal = this->Symtab->sh_info; + return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1); +} template <class ELFT> -typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() { - return this->getSymbolsHelper(true); +ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() { + if (!this->Symtab) + return this->SymbolBodies; + return makeArrayRef(this->SymbolBodies).slice(1); } -template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const { - if (MipsReginfo) +template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const { + if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo) + return MipsOptions->Reginfo->ri_gp_value; + if (!ELFT::Is64Bits && MipsReginfo && MipsReginfo->Reginfo) return MipsReginfo->Reginfo->ri_gp_value; return 0; } template <class ELFT> -const typename ObjectFile<ELFT>::Elf_Sym * -ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) { - uint32_t FirstNonLocal = this->Symtab->sh_info; - if (SymIndex >= FirstNonLocal) - return nullptr; - Elf_Sym_Range Syms = this->ELFObj.symbols(this->Symtab); - return Syms.begin() + SymIndex; -} - -template <class ELFT> -void ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) { +void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); @@ -118,63 +136,57 @@ void ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) { // They are identified and deduplicated by group name. This function // returns a group name. template <class ELFT> -StringRef ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) { +StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->ELFObj; - uint32_t SymtabdSectionIndex = Sec.sh_link; - ErrorOr<const Elf_Shdr *> SecOrErr = Obj.getSection(SymtabdSectionIndex); - error(SecOrErr); - const Elf_Shdr *SymtabSec = *SecOrErr; - uint32_t SymIndex = Sec.sh_info; - const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex); - ErrorOr<StringRef> StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec); - error(StringTableOrErr); - ErrorOr<StringRef> SignatureOrErr = Sym->getName(*StringTableOrErr); - error(SignatureOrErr); - return *SignatureOrErr; + const Elf_Shdr *Symtab = check(Obj.getSection(Sec.sh_link)); + const Elf_Sym *Sym = Obj.getSymbol(Symtab, Sec.sh_info); + StringRef Strtab = check(Obj.getStringTableForSymtab(*Symtab)); + return check(Sym->getName(Strtab)); } template <class ELFT> -ArrayRef<typename ObjectFile<ELFT>::uint32_X> -ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { +ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word> +elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->ELFObj; - ErrorOr<ArrayRef<uint32_X>> EntriesOrErr = - Obj.template getSectionContentsAsArray<uint32_X>(&Sec); - error(EntriesOrErr); - ArrayRef<uint32_X> Entries = *EntriesOrErr; + ArrayRef<Elf_Word> Entries = + check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec)); if (Entries.empty() || Entries[0] != GRP_COMDAT) - error("Unsupported SHT_GROUP format"); + fatal(getFilename(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } template <class ELFT> -static bool shouldMerge(const typename ELFFile<ELFT>::Elf_Shdr &Sec) { - typedef typename ELFFile<ELFT>::uintX_t uintX_t; +bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { + // We don't merge sections if -O0 (default is -O1). This makes sometimes + // the linker significantly faster, although the output will be bigger. + if (Config->Optimize == 0) + return false; + uintX_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) - error("Writable SHF_MERGE sections are not supported"); + fatal(getFilename(this) + ": writable SHF_MERGE section is not supported"); uintX_t EntSize = Sec.sh_entsize; if (!EntSize || Sec.sh_size % EntSize) - error("SHF_MERGE section size must be a multiple of sh_entsize"); + fatal(getFilename(this) + + ": SHF_MERGE section size must be a multiple of sh_entsize"); - // Don't try to merge if the aligment is larger than the sh_entsize. + // Don't try to merge if the alignment is larger than the sh_entsize and this + // is not SHF_STRINGS. // - // If this is not a SHF_STRINGS, we would need to pad after every entity. It - // would be equivalent for the producer of the .o to just set a larger + // Since this is not a SHF_STRINGS, we would need to pad after every entity. + // It would be equivalent for the producer of the .o to just set a larger // sh_entsize. - // - // If this is a SHF_STRINGS, the larger alignment makes sense. Unfortunately - // it would complicate tail merging. This doesn't seem that common to - // justify the effort. - if (Sec.sh_addralign > EntSize) - return false; + if (Flags & SHF_STRINGS) + return true; - return true; + return Sec.sh_addralign <= EntSize; } template <class ELFT> -void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) { +void elf::ObjectFile<ELFT>::initializeSections( + DenseSet<StringRef> &ComdatGroups) { uint64_t Size = this->ELFObj.getNumSections(); Sections.resize(Size); unsigned I = -1; @@ -191,53 +203,85 @@ void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) { continue; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) - error("Invalid section index in group"); + fatal(getFilename(this) + ": invalid section index in group: " + + Twine(SecIndex)); Sections[SecIndex] = &InputSection<ELFT>::Discarded; } break; case SHT_SYMTAB: this->Symtab = &Sec; break; - case SHT_SYMTAB_SHNDX: { - ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec); - error(ErrorOrTable); - this->SymtabSHNDX = *ErrorOrTable; + case SHT_SYMTAB_SHNDX: + this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec)); break; - } case SHT_STRTAB: case SHT_NULL: break; case SHT_RELA: case SHT_REL: { - uint32_t RelocatedSectionIndex = Sec.sh_info; - if (RelocatedSectionIndex >= Size) - error("Invalid relocated section index"); - InputSectionBase<ELFT> *RelocatedSection = - Sections[RelocatedSectionIndex]; - if (!RelocatedSection) - error("Unsupported relocation reference"); - if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) { + // This section contains relocation information. + // If -r is given, we do not interpret or apply relocation + // but just copy relocation sections to output. + if (Config->Relocatable) { + Sections[I] = new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec); + break; + } + + // Find the relocation target section and associate this + // section with it. + InputSectionBase<ELFT> *Target = getRelocTarget(Sec); + if (!Target) + break; + if (auto *S = dyn_cast<InputSection<ELFT>>(Target)) { S->RelocSections.push_back(&Sec); - } else if (auto *S = dyn_cast<EHInputSection<ELFT>>(RelocatedSection)) { + break; + } + if (auto *S = dyn_cast<EhInputSection<ELFT>>(Target)) { if (S->RelocSection) - error("Multiple relocation sections to .eh_frame are not supported"); + fatal( + getFilename(this) + + ": multiple relocation sections to .eh_frame are not supported"); S->RelocSection = &Sec; - } else { - error("Relocations pointing to SHF_MERGE are not supported"); + break; } - break; + fatal(getFilename(this) + + ": relocations pointing to SHF_MERGE are not supported"); } + case SHT_ARM_ATTRIBUTES: + // FIXME: ARM meta-data section. At present attributes are ignored, + // they can be used to reason about object compatibility. + Sections[I] = &InputSection<ELFT>::Discarded; + break; default: Sections[I] = createInputSection(Sec); } } } -template <class ELFT> InputSectionBase<ELFT> * -ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { - ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec); - error(NameOrErr); - StringRef Name = *NameOrErr; +template <class ELFT> +InputSectionBase<ELFT> * +elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { + uint32_t Idx = Sec.sh_info; + if (Idx >= Sections.size()) + fatal(getFilename(this) + ": invalid relocated section index: " + + Twine(Idx)); + InputSectionBase<ELFT> *Target = Sections[Idx]; + + // Strictly speaking, a relocation section must be included in the + // group of the section it relocates. However, LLVM 3.3 and earlier + // would fail to do so, so we gracefully handle that case. + if (Target == &InputSection<ELFT>::Discarded) + return nullptr; + + if (!Target) + fatal(getFilename(this) + ": unsupported relocation reference"); + return Target; +} + +template <class ELFT> +InputSectionBase<ELFT> * +elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { + StringRef Name = check(this->ELFObj.getSectionName(&Sec)); // .note.GNU-stack is a marker section to control the presence of // PT_GNU_STACK segment in outputs. Since the presence of the segment @@ -246,98 +290,129 @@ ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { if (Name == ".note.GNU-stack") return &InputSection<ELFT>::Discarded; - // A MIPS object file has a special section that contains register - // usage info, which needs to be handled by the linker specially. - if (Config->EMachine == EM_MIPS && Name == ".reginfo") { - MipsReginfo = new (Alloc) MipsReginfoInputSection<ELFT>(this, &Sec); - return MipsReginfo; + if (Name == ".note.GNU-split-stack") { + error("objects using splitstacks are not supported"); + return &InputSection<ELFT>::Discarded; + } + + if (Config->StripDebug && Name.startswith(".debug")) + return &InputSection<ELFT>::Discarded; + + // A MIPS object file has a special sections that contain register + // usage info, which need to be handled by the linker specially. + if (Config->EMachine == EM_MIPS) { + if (Name == ".reginfo") { + MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec)); + return MipsReginfo.get(); + } + if (Name == ".MIPS.options") { + MipsOptions.reset(new MipsOptionsInputSection<ELFT>(this, &Sec)); + return MipsOptions.get(); + } } - if (Name == ".eh_frame") - return new (EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec); - if (shouldMerge<ELFT>(Sec)) + // The linker merges EH (exception handling) frames and creates a + // .eh_frame_hdr section for runtime. So we handle them with a special + // class. For relocatable outputs, they are just passed through. + if (Name == ".eh_frame" && !Config->Relocatable) + return new (EHAlloc.Allocate()) EhInputSection<ELFT>(this, &Sec); + + if (shouldMerge(Sec)) return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec); - return new (Alloc) InputSection<ELFT>(this, &Sec); + return new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec); } -template <class ELFT> void ObjectFile<ELFT>::initializeSymbols() { +template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() { this->initStringTable(); - Elf_Sym_Range Syms = this->getNonLocalSymbols(); + Elf_Sym_Range Syms = this->getElfSymbols(false); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) - SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym)); + SymbolBodies.push_back(createSymbolBody(&Sym)); } template <class ELFT> InputSectionBase<ELFT> * -ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { +elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { uint32_t Index = this->getSectionIndex(Sym); if (Index == 0) return nullptr; if (Index >= Sections.size() || !Sections[Index]) - error("Invalid section index"); - return Sections[Index]; + fatal(getFilename(this) + ": invalid section index: " + Twine(Index)); + InputSectionBase<ELFT> *S = Sections[Index]; + if (S == &InputSectionBase<ELFT>::Discarded) + return S; + return S->Repl; } template <class ELFT> -SymbolBody *ObjectFile<ELFT>::createSymbolBody(StringRef StringTable, - const Elf_Sym *Sym) { - ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable); - error(NameOrErr); - StringRef Name = *NameOrErr; +SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { + int Binding = Sym->getBinding(); + InputSectionBase<ELFT> *Sec = getSection(*Sym); + if (Binding == STB_LOCAL) { + if (Sym->st_shndx == SHN_UNDEF) + return new (this->Alloc) + Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this); + return new (this->Alloc) DefinedRegular<ELFT>(*Sym, Sec); + } + + StringRef Name = check(Sym->getName(this->StringTable)); switch (Sym->st_shndx) { case SHN_UNDEF: - return new (Alloc) UndefinedElf<ELFT>(Name, *Sym); + return elf::Symtab<ELFT>::X + ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(), + /*CanOmitFromDynSym*/ false, this) + ->body(); case SHN_COMMON: - return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value, - Sym->getBinding() == llvm::ELF::STB_WEAK, - Sym->getVisibility()); + return elf::Symtab<ELFT>::X + ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other, + Sym->getType(), this) + ->body(); } - switch (Sym->getBinding()) { + switch (Binding) { default: - error("unexpected binding"); + fatal(getFilename(this) + ": unexpected binding: " + Twine(Binding)); case STB_GLOBAL: case STB_WEAK: - case STB_GNU_UNIQUE: { - InputSectionBase<ELFT> *Sec = getSection(*Sym); + case STB_GNU_UNIQUE: if (Sec == &InputSection<ELFT>::Discarded) - return new (Alloc) UndefinedElf<ELFT>(Name, *Sym); - return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec); - } + return elf::Symtab<ELFT>::X + ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(), + /*CanOmitFromDynSym*/ false, this) + ->body(); + return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body(); } } -void ArchiveFile::parse() { - ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB); - error(FileOrErr, "Failed to parse archive"); - File = std::move(*FileOrErr); - - // Allocate a buffer for Lazy objects. - size_t NumSyms = File->getNumberOfSymbols(); - LazySymbols.reserve(NumSyms); +template <class ELFT> void ArchiveFile::parse() { + File = check(Archive::create(MB), "failed to parse archive"); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) - LazySymbols.emplace_back(this, Sym); + Symtab<ELFT>::X->addLazyArchive(this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { - ErrorOr<Archive::Child> COrErr = Sym->getMember(); - error(COrErr, "Could not get the member for symbol " + Sym->getName()); - const Archive::Child &C = *COrErr; + Archive::Child C = + check(Sym->getMember(), + "could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return MemoryBufferRef(); - ErrorOr<MemoryBufferRef> RefOrErr = C.getMemoryBufferRef(); - if (!RefOrErr) - error(RefOrErr, "Could not get the buffer for the member defining symbol " + - Sym->getName()); - return *RefOrErr; + MemoryBufferRef Ret = + check(C.getMemoryBufferRef(), + "could not get the buffer for the member defining symbol " + + Sym->getName()); + + if (C.getParent()->isThin() && Driver->Cpio) + Driver->Cpio->append(relativeToRoot(check(C.getFullName())), + Ret.getBuffer()); + + return Ret; } template <class ELFT> @@ -345,21 +420,19 @@ SharedFile<ELFT>::SharedFile(MemoryBufferRef M) : ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {} template <class ELFT> -const typename ELFFile<ELFT>::Elf_Shdr * +const typename ELFT::Shdr * SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const { uint32_t Index = this->getSectionIndex(Sym); if (Index == 0) return nullptr; - ErrorOr<const Elf_Shdr *> Ret = this->ELFObj.getSection(Index); - error(Ret); - return *Ret; + return check(this->ELFObj.getSection(Index)); } // Partially parse the shared object file so that we can call // getSoName on this object. template <class ELFT> void SharedFile<ELFT>::parseSoName() { - typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn; - typedef typename ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Dyn Elf_Dyn; + typedef typename ELFT::uint uintX_t; const Elf_Shdr *DynamicSec = nullptr; const ELFFile<ELFT> Obj = this->ELFObj; @@ -373,12 +446,15 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { case SHT_DYNAMIC: DynamicSec = &Sec; break; - case SHT_SYMTAB_SHNDX: { - ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec); - error(ErrorOrTable); - this->SymtabSHNDX = *ErrorOrTable; + case SHT_SYMTAB_SHNDX: + this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec)); + break; + case SHT_GNU_versym: + this->VersymSec = &Sec; + break; + case SHT_GNU_verdef: + this->VerdefSec = &Sec; break; - } } } @@ -395,83 +471,358 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { if (Dyn.d_tag == DT_SONAME) { uintX_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) - error("Invalid DT_SONAME entry"); + fatal(getFilename(this) + ": invalid DT_SONAME entry"); SoName = StringRef(this->StringTable.data() + Val); return; } } } +// Parse the version definitions in the object file if present. Returns a vector +// whose nth element contains a pointer to the Elf_Verdef for version identifier +// n. Version identifiers that are not definitions map to nullptr. The array +// always has at least length 1. +template <class ELFT> +std::vector<const typename ELFT::Verdef *> +SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { + std::vector<const Elf_Verdef *> Verdefs(1); + // We only need to process symbol versions for this DSO if it has both a + // versym and a verdef section, which indicates that the DSO contains symbol + // version definitions. + if (!VersymSec || !VerdefSec) + return Verdefs; + + // The location of the first global versym entry. + Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() + + VersymSec->sh_offset) + + this->Symtab->sh_info; + + // We cannot determine the largest verdef identifier without inspecting + // every Elf_Verdef, but both bfd and gold assign verdef identifiers + // sequentially starting from 1, so we predict that the largest identifier + // will be VerdefCount. + unsigned VerdefCount = VerdefSec->sh_info; + Verdefs.resize(VerdefCount + 1); + + // Build the Verdefs array by following the chain of Elf_Verdef objects + // from the start of the .gnu.version_d section. + const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset; + for (unsigned I = 0; I != VerdefCount; ++I) { + auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef); + Verdef += CurVerdef->vd_next; + unsigned VerdefIndex = CurVerdef->vd_ndx; + if (Verdefs.size() <= VerdefIndex) + Verdefs.resize(VerdefIndex + 1); + Verdefs[VerdefIndex] = CurVerdef; + } + + return Verdefs; +} + // Fully parse the shared object file. This must be called after parseSoName(). template <class ELFT> void SharedFile<ELFT>::parseRest() { - Elf_Sym_Range Syms = this->getNonLocalSymbols(); - uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); - SymbolBodies.reserve(NumSymbols); + // Create mapping from version identifiers to Elf_Verdef entries. + const Elf_Versym *Versym = nullptr; + std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym); + + Elf_Sym_Range Syms = this->getElfSymbols(true); for (const Elf_Sym &Sym : Syms) { - ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable); - error(NameOrErr.getError()); - StringRef Name = *NameOrErr; + unsigned VersymIndex = 0; + if (Versym) { + VersymIndex = Versym->vs_index; + ++Versym; + } - if (Sym.isUndefined()) + StringRef Name = check(Sym.getName(this->StringTable)); + if (Sym.isUndefined()) { Undefs.push_back(Name); - else - SymbolBodies.emplace_back(this, Name, Sym); + continue; + } + + if (Versym) { + // Ignore local symbols and non-default versions. + if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN)) + continue; + } + + const Elf_Verdef *V = + VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; + elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); } } -template <typename T> -static std::unique_ptr<InputFile> createELFFileAux(MemoryBufferRef MB) { - std::unique_ptr<T> Ret = llvm::make_unique<T>(MB); +static ELFKind getELFKind(MemoryBufferRef MB) { + std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context); + Triple TheTriple(TripleStr); + bool Is64Bits = TheTriple.isArch64Bit(); + if (TheTriple.isLittleEndian()) + return Is64Bits ? ELF64LEKind : ELF32LEKind; + return Is64Bits ? ELF64BEKind : ELF32BEKind; +} - if (!Config->FirstElf) - Config->FirstElf = Ret.get(); +static uint8_t getMachineKind(MemoryBufferRef MB) { + std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context); + switch (Triple(TripleStr).getArch()) { + case Triple::aarch64: + return EM_AARCH64; + case Triple::arm: + return EM_ARM; + case Triple::mips: + case Triple::mipsel: + case Triple::mips64: + case Triple::mips64el: + return EM_MIPS; + case Triple::ppc: + return EM_PPC; + case Triple::ppc64: + return EM_PPC64; + case Triple::x86: + return EM_386; + case Triple::x86_64: + return EM_X86_64; + default: + fatal(MB.getBufferIdentifier() + + ": could not infer e_machine from bitcode target triple " + + TripleStr); + } +} + +BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) { + EKind = getELFKind(MB); + EMachine = getMachineKind(MB); +} + +static uint8_t getGvVisibility(const GlobalValue *GV) { + switch (GV->getVisibility()) { + case GlobalValue::DefaultVisibility: + return STV_DEFAULT; + case GlobalValue::HiddenVisibility: + return STV_HIDDEN; + case GlobalValue::ProtectedVisibility: + return STV_PROTECTED; + } + llvm_unreachable("unknown visibility"); +} + +template <class ELFT> +Symbol *BitcodeFile::createSymbol(const DenseSet<const Comdat *> &KeptComdats, + const IRObjectFile &Obj, + const BasicSymbolRef &Sym) { + const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl()); + + SmallString<64> Name; + raw_svector_ostream OS(Name); + Sym.printName(OS); + StringRef NameRef = Saver.save(StringRef(Name)); + + uint32_t Flags = Sym.getFlags(); + bool IsWeak = Flags & BasicSymbolRef::SF_Weak; + uint32_t Binding = IsWeak ? STB_WEAK : STB_GLOBAL; + + uint8_t Type = STT_NOTYPE; + bool CanOmitFromDynSym = false; + // FIXME: Expose a thread-local flag for module asm symbols. + if (GV) { + if (GV->isThreadLocal()) + Type = STT_TLS; + CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV); + } + + uint8_t Visibility; + if (GV) + Visibility = getGvVisibility(GV); + else + // FIXME: Set SF_Hidden flag correctly for module asm symbols, and expose + // protected visibility. + Visibility = STV_DEFAULT; + + if (GV) + if (const Comdat *C = GV->getComdat()) + if (!KeptComdats.count(C)) + return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, this); + + const Module &M = Obj.getModule(); + if (Flags & BasicSymbolRef::SF_Undefined) + return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, this); + if (Flags & BasicSymbolRef::SF_Common) { + // FIXME: Set SF_Common flag correctly for module asm symbols, and expose + // size and alignment. + assert(GV); + const DataLayout &DL = M.getDataLayout(); + uint64_t Size = DL.getTypeAllocSize(GV->getValueType()); + return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(), + Binding, Visibility, STT_OBJECT, this); + } + return Symtab<ELFT>::X->addBitcode(NameRef, IsWeak, Visibility, Type, + CanOmitFromDynSym, this); +} + +bool BitcodeFile::shouldSkip(uint32_t Flags) { + return !(Flags & BasicSymbolRef::SF_Global) || + (Flags & BasicSymbolRef::SF_FormatSpecific); +} + +template <class ELFT> +void BitcodeFile::parse(DenseSet<StringRef> &ComdatGroups) { + Obj = check(IRObjectFile::create(MB, Driver->Context)); + const Module &M = Obj->getModule(); - if (Config->EKind == ELFNoneKind) { - Config->EKind = Ret->getELFKind(); - Config->EMachine = Ret->getEMachine(); + DenseSet<const Comdat *> KeptComdats; + for (const auto &P : M.getComdatSymbolTable()) { + StringRef N = Saver.save(P.first()); + if (ComdatGroups.insert(N).second) + KeptComdats.insert(&P.second); } - return std::move(Ret); + for (const BasicSymbolRef &Sym : Obj->symbols()) + if (!shouldSkip(Sym.getFlags())) + Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym)); } template <template <class> class T> static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) { - std::pair<unsigned char, unsigned char> Type = getElfArchType(MB.getBuffer()); - if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB) - error("Invalid data encoding: " + MB.getBufferIdentifier()); + unsigned char Size; + unsigned char Endian; + std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); + if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) + fatal("invalid data encoding: " + MB.getBufferIdentifier()); - if (Type.first == ELF::ELFCLASS32) { - if (Type.second == ELF::ELFDATA2LSB) - return createELFFileAux<T<ELF32LE>>(MB); - return createELFFileAux<T<ELF32BE>>(MB); - } - if (Type.first == ELF::ELFCLASS64) { - if (Type.second == ELF::ELFDATA2LSB) - return createELFFileAux<T<ELF64LE>>(MB); - return createELFFileAux<T<ELF64BE>>(MB); - } - error("Invalid file class: " + MB.getBufferIdentifier()); + std::unique_ptr<InputFile> Obj; + if (Size == ELFCLASS32 && Endian == ELFDATA2LSB) + Obj.reset(new T<ELF32LE>(MB)); + else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB) + Obj.reset(new T<ELF32BE>(MB)); + else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB) + Obj.reset(new T<ELF64LE>(MB)); + else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB) + Obj.reset(new T<ELF64BE>(MB)); + else + fatal("invalid file class: " + MB.getBufferIdentifier()); + + if (!Config->FirstElf) + Config->FirstElf = Obj.get(); + return Obj; +} + +static bool isBitcode(MemoryBufferRef MB) { + using namespace sys::fs; + return identify_magic(MB.getBuffer()) == file_magic::bitcode; } -std::unique_ptr<InputFile> elf2::createObjectFile(MemoryBufferRef MB) { - return createELFFile<ObjectFile>(MB); +std::unique_ptr<InputFile> elf::createObjectFile(MemoryBufferRef MB, + StringRef ArchiveName) { + std::unique_ptr<InputFile> F; + if (isBitcode(MB)) + F.reset(new BitcodeFile(MB)); + else + F = createELFFile<ObjectFile>(MB); + F->ArchiveName = ArchiveName; + return F; } -std::unique_ptr<InputFile> elf2::createSharedFile(MemoryBufferRef MB) { +std::unique_ptr<InputFile> elf::createSharedFile(MemoryBufferRef MB) { return createELFFile<SharedFile>(MB); } -template class elf2::ELFFileBase<ELF32LE>; -template class elf2::ELFFileBase<ELF32BE>; -template class elf2::ELFFileBase<ELF64LE>; -template class elf2::ELFFileBase<ELF64BE>; +MemoryBufferRef LazyObjectFile::getBuffer() { + if (Seen) + return MemoryBufferRef(); + Seen = true; + return MB; +} + +template <class ELFT> +void LazyObjectFile::parse() { + for (StringRef Sym : getSymbols()) + Symtab<ELFT>::X->addLazyObject(Sym, *this); +} + +template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + + const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB); + for (const Elf_Shdr &Sec : Obj.sections()) { + if (Sec.sh_type != SHT_SYMTAB) + continue; + Elf_Sym_Range Syms = Obj.symbols(&Sec); + uint32_t FirstNonLocal = Sec.sh_info; + StringRef StringTable = check(Obj.getStringTableForSymtab(Sec)); + std::vector<StringRef> V; + for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) + if (Sym.st_shndx != SHN_UNDEF) + V.push_back(check(Sym.getName(StringTable))); + return V; + } + return {}; +} + +std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { + LLVMContext Context; + std::unique_ptr<IRObjectFile> Obj = + check(IRObjectFile::create(this->MB, Context)); + std::vector<StringRef> V; + for (const BasicSymbolRef &Sym : Obj->symbols()) { + uint32_t Flags = Sym.getFlags(); + if (BitcodeFile::shouldSkip(Flags)) + continue; + if (Flags & BasicSymbolRef::SF_Undefined) + continue; + SmallString<64> Name; + raw_svector_ostream OS(Name); + Sym.printName(OS); + V.push_back(Saver.save(StringRef(Name))); + } + return V; +} + +// Returns a vector of globally-visible defined symbol names. +std::vector<StringRef> LazyObjectFile::getSymbols() { + if (isBitcode(this->MB)) + return getBitcodeSymbols(); + + unsigned char Size; + unsigned char Endian; + std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer()); + if (Size == ELFCLASS32) { + if (Endian == ELFDATA2LSB) + return getElfSymbols<ELF32LE>(); + return getElfSymbols<ELF32BE>(); + } + if (Endian == ELFDATA2LSB) + return getElfSymbols<ELF64LE>(); + return getElfSymbols<ELF64BE>(); +} + +template void ArchiveFile::parse<ELF32LE>(); +template void ArchiveFile::parse<ELF32BE>(); +template void ArchiveFile::parse<ELF64LE>(); +template void ArchiveFile::parse<ELF64BE>(); + +template void BitcodeFile::parse<ELF32LE>(DenseSet<StringRef> &); +template void BitcodeFile::parse<ELF32BE>(DenseSet<StringRef> &); +template void BitcodeFile::parse<ELF64LE>(DenseSet<StringRef> &); +template void BitcodeFile::parse<ELF64BE>(DenseSet<StringRef> &); + +template void LazyObjectFile::parse<ELF32LE>(); +template void LazyObjectFile::parse<ELF32BE>(); +template void LazyObjectFile::parse<ELF64LE>(); +template void LazyObjectFile::parse<ELF64BE>(); + +template class elf::ELFFileBase<ELF32LE>; +template class elf::ELFFileBase<ELF32BE>; +template class elf::ELFFileBase<ELF64LE>; +template class elf::ELFFileBase<ELF64BE>; -template class elf2::ObjectFile<ELF32LE>; -template class elf2::ObjectFile<ELF32BE>; -template class elf2::ObjectFile<ELF64LE>; -template class elf2::ObjectFile<ELF64BE>; +template class elf::ObjectFile<ELF32LE>; +template class elf::ObjectFile<ELF32BE>; +template class elf::ObjectFile<ELF64LE>; +template class elf::ObjectFile<ELF64BE>; -template class elf2::SharedFile<ELF32LE>; -template class elf2::SharedFile<ELF32BE>; -template class elf2::SharedFile<ELF64LE>; -template class elf2::SharedFile<ELF64BE>; +template class elf::SharedFile<ELF32LE>; +template class elf::SharedFile<ELF32BE>; +template class elf::SharedFile<ELF64LE>; +template class elf::SharedFile<ELF64BE>; diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 45d403c0125c..79cb751494b3 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -18,11 +18,16 @@ #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Comdat.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Support/StringSaver.h" + +#include <map> namespace lld { -namespace elf2 { +namespace elf { using llvm::object::Archive; @@ -33,25 +38,45 @@ class SymbolBody; // The root class of input files. class InputFile { public: - enum Kind { ObjectKind, SharedKind, ArchiveKind }; + enum Kind { + ObjectKind, + SharedKind, + LazyObjectKind, + ArchiveKind, + BitcodeKind, + }; + Kind kind() const { return FileKind; } StringRef getName() const { return MB.getBufferIdentifier(); } + MemoryBufferRef MB; + + // Filename of .a which contained this file. If this file was + // not in an archive file, it is the empty string. We use this + // string for creating error messages. + StringRef ArchiveName; + + // If this is an architecture-specific file, the following members + // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. + ELFKind EKind = ELFNoneKind; + uint16_t EMachine = llvm::ELF::EM_NONE; protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - MemoryBufferRef MB; private: const Kind FileKind; }; +// Returns "(internal)", "foo.a(bar.o)" or "baz.o". +std::string getFilename(const InputFile *F); + template <typename ELFT> class ELFFileBase : public InputFile { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); static bool classof(const InputFile *F) { @@ -59,11 +84,9 @@ public: return K == ObjectKind || K == SharedKind; } - static ELFKind getELFKind(); const llvm::object::ELFFile<ELFT> &getObj() const { return ELFObj; } llvm::object::ELFFile<ELFT> &getObj() { return ELFObj; } - uint16_t getEMachine() const { return getObj().getHeader()->e_machine; } uint8_t getOSABI() const { return getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; } @@ -72,39 +95,36 @@ public: uint32_t getSectionIndex(const Elf_Sym &Sym) const; + Elf_Sym_Range getElfSymbols(bool OnlyGlobals); + protected: llvm::object::ELFFile<ELFT> ELFObj; const Elf_Shdr *Symtab = nullptr; ArrayRef<Elf_Word> SymtabSHNDX; StringRef StringTable; void initStringTable(); - Elf_Sym_Range getNonLocalSymbols(); - Elf_Sym_Range getSymbolsHelper(bool); }; // .o file. template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> { typedef ELFFileBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - - // uint32 in ELFT's byte order - typedef llvm::support::detail::packed_endian_specific_integral< - uint32_t, ELFT::TargetEndianness, 2> - uint32_X; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::uint uintX_t; StringRef getShtGroupSignature(const Elf_Shdr &Sec); - ArrayRef<uint32_X> getShtGroupEntries(const Elf_Shdr &Sec); + ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec); public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjectKind; } - ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; } + ArrayRef<SymbolBody *> getSymbols(); + ArrayRef<SymbolBody *> getLocalSymbols(); + ArrayRef<SymbolBody *> getNonLocalSymbols(); explicit ObjectFile(MemoryBufferRef M); void parse(llvm::DenseSet<StringRef> &ComdatGroups); @@ -112,15 +132,14 @@ public: ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; } InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const; - SymbolBody *getSymbolBody(uint32_t SymbolIndex) const { - uint32_t FirstNonLocal = this->Symtab->sh_info; - if (SymbolIndex < FirstNonLocal) - return nullptr; - return SymbolBodies[SymbolIndex - FirstNonLocal]; + SymbolBody &getSymbolBody(uint32_t SymbolIndex) const { + return *SymbolBodies[SymbolIndex]; } - Elf_Sym_Range getLocalSymbols(); - const Elf_Sym *getLocalSymbol(uintX_t SymIndex); + template <typename RelT> SymbolBody &getRelocTargetSym(const RelT &Rel) const { + uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL); + return getSymbolBody(SymIndex); + } const Elf_Shdr *getSymbolTable() const { return this->Symtab; }; @@ -129,12 +148,22 @@ public: // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. uint32_t getMipsGp0() const; + // The number is the offset in the string table. It will be used as the + // st_name of the symbol. + std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms; + + // SymbolBodies and Thunks for sections in this file are allocated + // using this buffer. + llvm::BumpPtrAllocator Alloc; + private: void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups); void initializeSymbols(); + InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec); - SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym); + bool shouldMerge(const Elf_Shdr &Sec); + SymbolBody *createSymbolBody(const Elf_Sym *Sym); // List of all sections defined by this file. std::vector<InputSectionBase<ELFT> *> Sections; @@ -143,49 +172,97 @@ private: std::vector<SymbolBody *> SymbolBodies; // MIPS .reginfo section defined by this file. - MipsReginfoInputSection<ELFT> *MipsReginfo = nullptr; + std::unique_ptr<MipsReginfoInputSection<ELFT>> MipsReginfo; + // MIPS .MIPS.options section defined by this file. + std::unique_ptr<MipsOptionsInputSection<ELFT>> MipsOptions; - llvm::BumpPtrAllocator Alloc; + llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc; llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc; - llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc; + llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc; +}; + +// LazyObjectFile is analogous to ArchiveFile in the sense that +// the file contains lazy symbols. The difference is that +// LazyObjectFile wraps a single file instead of multiple files. +// +// This class is used for --start-lib and --end-lib options which +// instruct the linker to link object files between them with the +// archive file semantics. +class LazyObjectFile : public InputFile { +public: + explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {} + + static bool classof(const InputFile *F) { + return F->kind() == LazyObjectKind; + } + + template <class ELFT> void parse(); + MemoryBufferRef getBuffer(); + +private: + std::vector<StringRef> getSymbols(); + template <class ELFT> std::vector<StringRef> getElfSymbols(); + std::vector<StringRef> getBitcodeSymbols(); + + llvm::BumpPtrAllocator Alloc; + llvm::StringSaver Saver{Alloc}; + bool Seen = false; }; +// An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - void parse(); + template <class ELFT> void parse(); // Returns a memory buffer for a given symbol. An empty memory buffer // is returned if we have already returned the same memory buffer. // (So that we don't instantiate same members more than once.) MemoryBufferRef getMember(const Archive::Symbol *Sym); - llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; } - private: std::unique_ptr<Archive> File; - std::vector<Lazy> LazySymbols; llvm::DenseSet<uint64_t> Seen; }; +class BitcodeFile : public InputFile { +public: + explicit BitcodeFile(MemoryBufferRef M); + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } + template <class ELFT> + void parse(llvm::DenseSet<StringRef> &ComdatGroups); + ArrayRef<Symbol *> getSymbols() { return Symbols; } + static bool shouldSkip(uint32_t Flags); + std::unique_ptr<llvm::object::IRObjectFile> Obj; + +private: + std::vector<Symbol *> Symbols; + llvm::BumpPtrAllocator Alloc; + llvm::StringSaver Saver{Alloc}; + template <class ELFT> + Symbol *createSymbol(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats, + const llvm::object::IRObjectFile &Obj, + const llvm::object::BasicSymbolRef &Sym); +}; + // .so file. template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { typedef ELFFileBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::Versym Elf_Versym; + typedef typename ELFT::Verdef Elf_Verdef; - std::vector<SharedSymbol<ELFT>> SymbolBodies; std::vector<StringRef> Undefs; StringRef SoName; + const Elf_Shdr *VersymSec = nullptr; + const Elf_Shdr *VerdefSec = nullptr; public: StringRef getSoName() const { return SoName; } - llvm::MutableArrayRef<SharedSymbol<ELFT>> getSharedSymbols() { - return SymbolBodies; - } const Elf_Shdr *getSection(const Elf_Sym &Sym) const; llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; } @@ -197,6 +274,19 @@ public: void parseSoName(); void parseRest(); + std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym); + + struct NeededVer { + // The string table offset of the version name in the output file. + size_t StrTab; + + // The version identifier for this version name. + uint16_t Index; + }; + + // Mapping from Elf_Verdef data structures to information about Elf_Vernaux + // data structures in the output file. + std::map<const Elf_Verdef *, NeededVer> VerdefMap; // Used for --as-needed bool AsNeeded = false; @@ -204,10 +294,11 @@ public: bool isNeeded() const { return !AsNeeded || IsUsed; } }; -std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB); +std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB, + StringRef ArchiveName = ""); std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB); -} // namespace elf2 +} // namespace elf } // namespace lld #endif diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index f6aa51b47b98..6564e7995a89 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -9,86 +9,118 @@ #include "InputSection.h" #include "Config.h" +#include "EhFrame.h" #include "Error.h" #include "InputFiles.h" +#include "LinkerScript.h" #include "OutputSections.h" #include "Target.h" +#include "Thunks.h" + +#include "llvm/Support/Compression.h" +#include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support::endian; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; + +template <class ELFT> bool elf::isDiscarded(InputSectionBase<ELFT> *S) { + return !S || S == &InputSection<ELFT>::Discarded || !S->Live || + Script<ELFT>::X->isDiscarded(S); +} template <class ELFT> -InputSectionBase<ELFT>::InputSectionBase(ObjectFile<ELFT> *File, +InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header, Kind SectionKind) - : Header(Header), File(File), SectionKind(SectionKind) {} + : Header(Header), File(File), SectionKind(SectionKind), Repl(this), + Compressed(Header->sh_flags & SHF_COMPRESSED) { + // The garbage collector sets sections' Live bits. + // If GC is disabled, all sections are considered live by default. + Live = !Config->GcSections; + + // The ELF spec states that a value of 0 means the section has + // no alignment constraits. + Alignment = std::max<uintX_t>(Header->sh_addralign, 1); +} + +template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const { + if (auto *D = dyn_cast<InputSection<ELFT>>(this)) + if (D->getThunksSize() > 0) + return D->getThunkOff() + D->getThunksSize(); + return Header->sh_size; +} template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const { - ErrorOr<StringRef> Name = File->getObj().getSectionName(this->Header); - error(Name); - return *Name; + return check(File->getObj().getSectionName(this->Header)); } template <class ELFT> ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const { - ErrorOr<ArrayRef<uint8_t>> Ret = - this->File->getObj().getSectionContents(this->Header); - error(Ret); - return *Ret; + if (Compressed) + return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(), + Uncompressed.size()); + return check(this->File->getObj().getSectionContents(this->Header)); } template <class ELFT> -typename ELFFile<ELFT>::uintX_t -InputSectionBase<ELFT>::getOffset(uintX_t Offset) { +typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { switch (SectionKind) { case Regular: return cast<InputSection<ELFT>>(this)->OutSecOff + Offset; case EHFrame: - return cast<EHInputSection<ELFT>>(this)->getOffset(Offset); + return cast<EhInputSection<ELFT>>(this)->getOffset(Offset); case Merge: return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset); case MipsReginfo: - // MIPS .reginfo sections are consumed by the linker, - // so it should never be copied to output. - llvm_unreachable("MIPS .reginfo reached writeTo()."); + case MipsOptions: + // MIPS .reginfo and .MIPS.options sections are consumed by the linker, + // and the linker produces a single output section. It is possible that + // input files contain section symbol points to the corresponding input + // section. Redirect it to the produced output section. + if (Offset != 0) + fatal("Unsupported reference to the middle of '" + getSectionName() + + "' section"); + return this->OutSec->getVA(); } - llvm_unreachable("Invalid section kind"); + llvm_unreachable("invalid section kind"); } -template <class ELFT> -typename ELFFile<ELFT>::uintX_t -InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) { - return getOffset(Sym.st_value); -} +template <class ELFT> void InputSectionBase<ELFT>::uncompress() { + if (!zlib::isAvailable()) + fatal("build lld with zlib to enable compressed sections support"); -// Returns a section that Rel relocation is pointing to. -template <class ELFT> -InputSectionBase<ELFT> * -InputSectionBase<ELFT>::getRelocTarget(const Elf_Rel &Rel) { - // Global symbol - uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL); - if (SymbolBody *B = File->getSymbolBody(SymIndex)) - if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B->repl())) - return D->Section; - // Local symbol - if (const Elf_Sym *Sym = File->getLocalSymbol(SymIndex)) - if (InputSectionBase<ELFT> *Sec = File->getSection(*Sym)) - return Sec; - return nullptr; + // A compressed section consists of a header of Elf_Chdr type + // followed by compressed data. + ArrayRef<uint8_t> Data = + check(this->File->getObj().getSectionContents(this->Header)); + if (Data.size() < sizeof(Elf_Chdr)) + fatal("corrupt compressed section"); + + auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data()); + Data = Data.slice(sizeof(Elf_Chdr)); + + if (Hdr->ch_type != ELFCOMPRESS_ZLIB) + fatal("unsupported compression type"); + + StringRef Buf((const char *)Data.data(), Data.size()); + if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK) + fatal("error uncompressing section"); } template <class ELFT> -InputSectionBase<ELFT> * -InputSectionBase<ELFT>::getRelocTarget(const Elf_Rela &Rel) { - return getRelocTarget(reinterpret_cast<const Elf_Rel &>(Rel)); +typename ELFT::uint +InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const { + return getOffset(Sym.Value); } template <class ELFT> -InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header) +InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F, + const Elf_Shdr *Header) : InputSectionBase<ELFT>(F, Header, Base::Regular) {} template <class ELFT> @@ -97,267 +129,494 @@ bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { } template <class ELFT> -template <bool isRela> -uint8_t * -InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, - uint32_t Type, - RelIteratorRange<isRela> Rels) { - // Some MIPS relocations use addend calculated from addend of the relocation - // itself and addend of paired relocation. ABI requires to compute such - // combined addend in case of REL relocation record format only. - // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (isRela || Config->EMachine != EM_MIPS) - return nullptr; - if (Type == R_MIPS_HI16) - Type = R_MIPS_LO16; - else if (Type == R_MIPS_PCHI16) - Type = R_MIPS_PCLO16; - else if (Type == R_MICROMIPS_HI16) - Type = R_MICROMIPS_LO16; - else - return nullptr; - for (const auto &RI : Rels) { - if (RI.getType(Config->Mips64EL) != Type) - continue; - if (RI.getSymbol(Config->Mips64EL) != SymIndex) - continue; - uintX_t Offset = getOffset(RI.r_offset); - if (Offset == (uintX_t)-1) - return nullptr; - return Buf + Offset; - } - return nullptr; +InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() { + assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL); + ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections(); + return Sections[this->Header->sh_info]; } template <class ELFT> -static typename llvm::object::ELFFile<ELFT>::uintX_t -getSymSize(SymbolBody &Body) { - if (auto *SS = dyn_cast<DefinedElf<ELFT>>(&Body)) - return SS->Sym.st_size; - return 0; +void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) { + Thunks.push_back(T); +} + +template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const { + return this->Header->sh_size; } +template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const { + uint64_t Total = 0; + for (const Thunk<ELFT> *T : Thunks) + Total += T->size(); + return Total; +} + +// This is used for -r. We can't use memcpy to copy relocations because we need +// to update symbol table offset and section index for each relocation. So we +// copy relocations one by one. template <class ELFT> -template <bool isRela> -void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd, - RelIteratorRange<isRela> Rels) { - typedef Elf_Rel_Impl<ELFT, isRela> RelType; - size_t Num = Rels.end() - Rels.begin(); - for (size_t I = 0; I < Num; ++I) { - const RelType &RI = *(Rels.begin() + I); - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - uint32_t Type = RI.getType(Config->Mips64EL); - uintX_t Offset = getOffset(RI.r_offset); - if (Offset == (uintX_t)-1) - continue; +template <class RelTy> +void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { + InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection(); + + for (const RelTy &Rel : Rels) { + uint32_t Type = Rel.getType(Config->Mips64EL); + SymbolBody &Body = this->File->getRelocTargetSym(Rel); + + RelTy *P = reinterpret_cast<RelTy *>(Buf); + Buf += sizeof(RelTy); + + P->r_offset = RelocatedSection->getOffset(Rel.r_offset); + P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL); + } +} + +// Page(Expr) is the page address of the expression Expr, defined +// as (Expr & ~0xFFF). (This applies even if the machine page size +// supported by the platform has a different value.) +static uint64_t getAArch64Page(uint64_t Expr) { + return Expr & (~static_cast<uint64_t>(0xFFF)); +} +template <class ELFT> +static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, + typename ELFT::uint P, + const SymbolBody &Body, RelExpr Expr) { + typedef typename ELFT::uint uintX_t; + + switch (Expr) { + case R_HINT: + llvm_unreachable("cannot relocate hint relocs"); + case R_TLSLD: + return Out<ELFT>::Got->getTlsIndexOff() + A - + Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t); + case R_TLSLD_PC: + return Out<ELFT>::Got->getTlsIndexVA() + A - P; + case R_THUNK_ABS: + return Body.getThunkVA<ELFT>() + A; + case R_THUNK_PC: + case R_THUNK_PLT_PC: + return Body.getThunkVA<ELFT>() + A - P; + case R_PPC_TOC: + return getPPC64TocBase() + A; + case R_TLSGD: + return Out<ELFT>::Got->getGlobalDynOffset(Body) + A - + Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t); + case R_TLSGD_PC: + return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P; + case R_TLSDESC: + return Out<ELFT>::Got->getGlobalDynAddr(Body) + A; + case R_TLSDESC_PAGE: + return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) - + getAArch64Page(P); + case R_PLT: + return Body.getPltVA<ELFT>() + A; + case R_PLT_PC: + case R_PPC_PLT_OPD: + return Body.getPltVA<ELFT>() + A - P; + case R_SIZE: + return Body.getSize<ELFT>() + A; + case R_GOTREL: + return Body.getVA<ELFT>(A) - Out<ELFT>::Got->getVA(); + case R_RELAX_TLS_GD_TO_IE_END: + case R_GOT_FROM_END: + return Body.getGotOffset<ELFT>() + A - + Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t); + case R_RELAX_TLS_GD_TO_IE_ABS: + case R_GOT: + return Body.getGotVA<ELFT>() + A; + case R_RELAX_TLS_GD_TO_IE_PAGE_PC: + case R_GOT_PAGE_PC: + return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P); + case R_RELAX_TLS_GD_TO_IE: + case R_GOT_PC: + return Body.getGotVA<ELFT>() + A - P; + case R_GOTONLY_PC: + return Out<ELFT>::Got->getVA() + A - P; + case R_RELAX_TLS_LD_TO_LE: + case R_RELAX_TLS_IE_TO_LE: + case R_RELAX_TLS_GD_TO_LE: + case R_TLS: + if (Target->TcbSize) + return Body.getVA<ELFT>(A) + + alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align); + return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz; + case R_RELAX_TLS_GD_TO_LE_NEG: + case R_NEG_TLS: + return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A); + case R_ABS: + case R_RELAX_GOT_PC_NOPIC: + return Body.getVA<ELFT>(A); + case R_GOT_OFF: + return Body.getGotOffset<ELFT>() + A; + case R_MIPS_GOT_LOCAL_PAGE: + // If relocation against MIPS local symbol requires GOT entry, this entry + // should be initialized by 'page address'. This address is high 16-bits + // of sum the symbol's value and the addend. + return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A)); + case R_MIPS_GOT_OFF: + // In case of MIPS if a GOT relocation has non-zero addend this addend + // should be applied to the GOT entry content not to the GOT entry offset. + // That is why we use separate expression type. + return Out<ELFT>::Got->getMipsGotOffset(Body, A); + case R_MIPS_TLSGD: + return Out<ELFT>::Got->getGlobalDynOffset(Body) + + Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset; + case R_MIPS_TLSLD: + return Out<ELFT>::Got->getTlsIndexOff() + + Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset; + case R_PPC_OPD: { + uint64_t SymVA = Body.getVA<ELFT>(A); + // If we have an undefined weak symbol, we might get here with a symbol + // address of zero. That could overflow, but the code must be unreachable, + // so don't bother doing anything at all. + if (!SymVA) + return 0; + if (Out<ELF64BE>::Opd) { + // If this is a local call, and we currently have the address of a + // function-descriptor, get the underlying code address instead. + uint64_t OpdStart = Out<ELF64BE>::Opd->getVA(); + uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize(); + bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd; + if (InOpd) + SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]); + } + return SymVA - P; + } + case R_PC: + case R_RELAX_GOT_PC: + return Body.getVA<ELFT>(A) - P; + case R_PLT_PAGE_PC: + case R_PAGE_PC: + return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P); + } + llvm_unreachable("Invalid expression"); +} + +// This function applies relocations to sections without SHF_ALLOC bit. +// Such sections are never mapped to memory at runtime. Debug sections are +// an example. Relocations in non-alloc sections are much easier to +// handle than in allocated sections because it will never need complex +// treatement such as GOT or PLT (because at runtime no one refers them). +// So, we handle relocations for non-alloc sections directly in this +// function as a performance optimization. +template <class ELFT> +template <class RelTy> +void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { + const unsigned Bits = sizeof(uintX_t) * 8; + for (const RelTy &Rel : Rels) { + uint32_t Type = Rel.getType(Config->Mips64EL); + uintX_t Offset = this->getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; - uintX_t AddrLoc = OutSec->getVA() + Offset; - auto NextRelocs = llvm::make_range(&RI, Rels.end()); + uintX_t Addend = getAddend<ELFT>(Rel); + if (!RelTy::IsRela) + Addend += Target->getImplicitAddend(BufLoc, Type); - if (Target->isTlsLocalDynamicReloc(Type) && - !Target->isTlsOptimized(Type, nullptr)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out<ELFT>::Got->getLocalTlsIndexVA() + - getAddend<ELFT>(RI)); - continue; + SymbolBody &Sym = this->File->getRelocTargetSym(Rel); + if (Target->getRelExpr(Type, Sym) != R_ABS) { + error(this->getSectionName() + " has non-ABS reloc"); + return; } - const Elf_Shdr *SymTab = File->getSymbolTable(); - SymbolBody *Body = nullptr; - if (SymIndex >= SymTab->sh_info) - Body = File->getSymbolBody(SymIndex)->repl(); + uintX_t AddrLoc = this->OutSec->getVA() + Offset; + uint64_t SymVA = + SignExtend64<Bits>(getSymVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS)); + Target->relocateOne(BufLoc, Type, SymVA); + } +} - if (Target->isTlsOptimized(Type, Body)) { - uintX_t SymVA; - if (!Body) - SymVA = getLocalRelTarget(*File, RI, 0); - else if (Target->relocNeedsGot(Type, *Body)) - SymVA = Out<ELFT>::Got->getEntryAddr(*Body); +template <class ELFT> +void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) { + // scanReloc function in Writer.cpp constructs Relocations + // vector only for SHF_ALLOC'ed sections. For other sections, + // we handle relocations directly here. + auto *IS = dyn_cast<InputSection<ELFT>>(this); + if (IS && !(IS->Header->sh_flags & SHF_ALLOC)) { + for (const Elf_Shdr *RelSec : IS->RelocSections) { + if (RelSec->sh_type == SHT_RELA) + IS->relocateNonAlloc(Buf, IS->File->getObj().relas(RelSec)); else - SymVA = getSymVA<ELFT>(*Body); - // By optimizing TLS relocations, it is sometimes needed to skip - // relocations that immediately follow TLS relocations. This function - // knows how many slots we need to skip. - I += Target->relocateTlsOptimize(BufLoc, BufEnd, Type, AddrLoc, SymVA, - *Body); - continue; + IS->relocateNonAlloc(Buf, IS->File->getObj().rels(RelSec)); } + return; + } - // Handle relocations for local symbols -- they never get - // resolved so we don't allocate a SymbolBody. - uintX_t A = getAddend<ELFT>(RI); - if (!Body) { - uintX_t SymVA = getLocalRelTarget(*File, RI, A); - // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 relocations - // because they use the following expression to calculate the relocation's - // result for local symbol: S + A + GP0 - G. - if (Config->EMachine == EM_MIPS && - (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)) - SymVA += File->getMipsGp0(); - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, - findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); - continue; - } + const unsigned Bits = sizeof(uintX_t) * 8; + for (const Relocation<ELFT> &Rel : Relocations) { + uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset); + uint8_t *BufLoc = Buf + Offset; + uint32_t Type = Rel.Type; + uintX_t A = Rel.Addend; - if (Target->isTlsGlobalDynamicReloc(Type) && - !Target->isTlsOptimized(Type, Body)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out<ELFT>::Got->getGlobalDynAddr(*Body) + - getAddend<ELFT>(RI)); - continue; - } + uintX_t AddrLoc = OutSec->getVA() + Offset; + RelExpr Expr = Rel.Expr; + uint64_t SymVA = + SignExtend64<Bits>(getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr)); - uintX_t SymVA = getSymVA<ELFT>(*Body); - if (Target->relocNeedsPlt(Type, *Body)) { - SymVA = Out<ELFT>::Plt->getEntryAddr(*Body); - } else if (Target->relocNeedsGot(Type, *Body)) { - SymVA = Out<ELFT>::Got->getEntryAddr(*Body); - if (Body->isTls()) - Type = Target->getTlsGotReloc(Type); - } else if (!Target->needsCopyRel(Type, *Body) && - isa<SharedSymbol<ELFT>>(*Body)) { - continue; - } else if (Target->isTlsDynReloc(Type, *Body)) { - continue; - } else if (Target->isSizeReloc(Type) && canBePreempted(Body, false)) { - // A SIZE relocation is supposed to set a symbol size, but if a symbol - // can be preempted, the size at runtime may be different than link time. - // If that's the case, we leave the field alone rather than filling it - // with a possibly incorrect value. - continue; - } else if (Config->EMachine == EM_MIPS) { - if (Type == R_MIPS_HI16 && Body == Config->MipsGpDisp) - SymVA = getMipsGpAddr<ELFT>() - AddrLoc; - else if (Type == R_MIPS_LO16 && Body == Config->MipsGpDisp) - SymVA = getMipsGpAddr<ELFT>() - AddrLoc + 4; + switch (Expr) { + case R_RELAX_GOT_PC: + case R_RELAX_GOT_PC_NOPIC: + Target->relaxGot(BufLoc, SymVA); + break; + case R_RELAX_TLS_IE_TO_LE: + Target->relaxTlsIeToLe(BufLoc, Type, SymVA); + break; + case R_RELAX_TLS_LD_TO_LE: + Target->relaxTlsLdToLe(BufLoc, Type, SymVA); + break; + case R_RELAX_TLS_GD_TO_LE: + case R_RELAX_TLS_GD_TO_LE_NEG: + Target->relaxTlsGdToLe(BufLoc, Type, SymVA); + break; + case R_RELAX_TLS_GD_TO_IE: + case R_RELAX_TLS_GD_TO_IE_ABS: + case R_RELAX_TLS_GD_TO_IE_PAGE_PC: + case R_RELAX_TLS_GD_TO_IE_END: + Target->relaxTlsGdToIe(BufLoc, Type, SymVA); + break; + case R_PPC_PLT_OPD: + // Patch a nop (0x60000000) to a ld. + if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) + write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) + // fallthrough + default: + Target->relocateOne(BufLoc, Type, SymVA); + break; } - uintX_t Size = getSymSize<ELFT>(*Body); - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, - findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); } } template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) { if (this->Header->sh_type == SHT_NOBITS) return; + ELFFile<ELFT> &EObj = this->File->getObj(); + + // If -r is given, then an InputSection may be a relocation section. + if (this->Header->sh_type == SHT_RELA) { + copyRelocations(Buf + OutSecOff, EObj.relas(this->Header)); + return; + } + if (this->Header->sh_type == SHT_REL) { + copyRelocations(Buf + OutSecOff, EObj.rels(this->Header)); + return; + } + // Copy section contents from source object file to output file. ArrayRef<uint8_t> Data = this->getSectionData(); memcpy(Buf + OutSecOff, Data.data(), Data.size()); - ELFFile<ELFT> &EObj = this->File->getObj(); - uint8_t *BufEnd = Buf + OutSecOff + Data.size(); // Iterate over all relocation sections that apply to this section. - for (const Elf_Shdr *RelSec : this->RelocSections) { - if (RelSec->sh_type == SHT_RELA) - this->relocate(Buf, BufEnd, EObj.relas(RelSec)); - else - this->relocate(Buf, BufEnd, EObj.rels(RelSec)); + uint8_t *BufEnd = Buf + OutSecOff + Data.size(); + this->relocate(Buf, BufEnd); + + // The section might have a data/code generated by the linker and need + // to be written after the section. Usually these are thunks - small piece + // of code used to jump between "incompatible" functions like PIC and non-PIC + // or if the jump target too far and its address does not fit to the short + // jump istruction. + if (!Thunks.empty()) { + Buf += OutSecOff + getThunkOff(); + for (const Thunk<ELFT> *T : Thunks) { + T->writeTo(Buf); + Buf += T->size(); + } } } template <class ELFT> +void InputSection<ELFT>::replace(InputSection<ELFT> *Other) { + this->Alignment = std::max(this->Alignment, Other->Alignment); + Other->Repl = this->Repl; + Other->Live = false; +} + +template <class ELFT> SplitInputSection<ELFT>::SplitInputSection( - ObjectFile<ELFT> *File, const Elf_Shdr *Header, + elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header, typename InputSectionBase<ELFT>::Kind SectionKind) : InputSectionBase<ELFT>(File, Header, SectionKind) {} template <class ELFT> -EHInputSection<ELFT>::EHInputSection(ObjectFile<ELFT> *F, +EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F, const Elf_Shdr *Header) : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) { // Mark .eh_frame sections as live by default because there are // usually no relocations that point to .eh_frames. Otherwise, - // the garbage collector would drop all .eh_frame sections. + // the garbage collector would drop all .eh_frame sections. this->Live = true; } template <class ELFT> -bool EHInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { +bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { return S->SectionKind == InputSectionBase<ELFT>::EHFrame; } +// .eh_frame is a sequence of CIE or FDE records. +// This function splits an input section into records and returns them. template <class ELFT> -typename EHInputSection<ELFT>::uintX_t -EHInputSection<ELFT>::getOffset(uintX_t Offset) { +void EhInputSection<ELFT>::split() { + ArrayRef<uint8_t> Data = this->getSectionData(); + for (size_t Off = 0, End = Data.size(); Off != End;) { + size_t Size = readEhRecordSize<ELFT>(Data.slice(Off)); + this->Pieces.emplace_back(Off, Data.slice(Off, Size)); + // The empty record is the end marker. + if (Size == 4) + break; + Off += Size; + } +} + +template <class ELFT> +typename ELFT::uint EhInputSection<ELFT>::getOffset(uintX_t Offset) const { // The file crtbeginT.o has relocations pointing to the start of an empty // .eh_frame that is known to be the first in the link. It does that to // identify the start of the output .eh_frame. Handle this special case. if (this->getSectionHdr()->sh_size == 0) return Offset; - std::pair<uintX_t, uintX_t> *I = this->getRangeAndSize(Offset).first; - uintX_t Base = I->second; - if (Base == uintX_t(-1)) + const SectionPiece *Piece = this->getSectionPiece(Offset); + if (Piece->OutputOff == size_t(-1)) return -1; // Not in the output - uintX_t Addend = Offset - I->first; - return Base + Addend; + uintX_t Addend = Offset - Piece->InputOff; + return Piece->OutputOff + Addend; +} + +static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) { + // Optimize the common case. + StringRef S((const char *)A.data(), A.size()); + if (EntSize == 1) + return S.find(0); + + for (unsigned I = 0, N = S.size(); I != N; I += EntSize) { + const char *B = S.begin() + I; + if (std::all_of(B, B + EntSize, [](char C) { return C == 0; })) + return I; + } + return StringRef::npos; +} + +// Split SHF_STRINGS section. Such section is a sequence of +// null-terminated strings. +static std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> Data, + size_t EntSize) { + std::vector<SectionPiece> V; + size_t Off = 0; + while (!Data.empty()) { + size_t End = findNull(Data, EntSize); + if (End == StringRef::npos) + fatal("string is not null terminated"); + size_t Size = End + EntSize; + V.emplace_back(Off, Data.slice(0, Size)); + Data = Data.slice(Size); + Off += Size; + } + return V; +} + +// Split non-SHF_STRINGS section. Such section is a sequence of +// fixed size records. +static std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> Data, + size_t EntSize) { + std::vector<SectionPiece> V; + size_t Size = Data.size(); + assert((Size % EntSize) == 0); + for (unsigned I = 0, N = Size; I != N; I += EntSize) + V.emplace_back(I, Data.slice(I, EntSize)); + return V; } template <class ELFT> -MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F, +MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F, const Elf_Shdr *Header) : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {} +template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() { + ArrayRef<uint8_t> Data = this->getSectionData(); + uintX_t EntSize = this->Header->sh_entsize; + if (this->Header->sh_flags & SHF_STRINGS) + this->Pieces = splitStrings(Data, EntSize); + else + this->Pieces = splitNonStrings(Data, EntSize); + + if (Config->GcSections) + for (uintX_t Off : LiveOffsets) + this->getSectionPiece(Off)->Live = true; +} + template <class ELFT> bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { return S->SectionKind == InputSectionBase<ELFT>::Merge; } +// Do binary search to get a section piece at a given input offset. +template <class ELFT> +SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) { + auto *This = static_cast<const SplitInputSection<ELFT> *>(this); + return const_cast<SectionPiece *>(This->getSectionPiece(Offset)); +} + template <class ELFT> -std::pair<std::pair<typename ELFFile<ELFT>::uintX_t, - typename ELFFile<ELFT>::uintX_t> *, - typename ELFFile<ELFT>::uintX_t> -SplitInputSection<ELFT>::getRangeAndSize(uintX_t Offset) { +const SectionPiece * +SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const { ArrayRef<uint8_t> D = this->getSectionData(); StringRef Data((const char *)D.data(), D.size()); uintX_t Size = Data.size(); if (Offset >= Size) - error("Entry is past the end of the section"); + fatal("entry is past the end of the section"); // Find the element this offset points to. auto I = std::upper_bound( - Offsets.begin(), Offsets.end(), Offset, - [](const uintX_t &A, const std::pair<uintX_t, uintX_t> &B) { - return A < B.first; - }); - uintX_t End = I == Offsets.end() ? Data.size() : I->first; + Pieces.begin(), Pieces.end(), Offset, + [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; }); --I; - return std::make_pair(&*I, End); + return &*I; } +// Returns the offset in an output section for a given input offset. +// Because contents of a mergeable section is not contiguous in output, +// it is not just an addition to a base output offset. template <class ELFT> -typename MergeInputSection<ELFT>::uintX_t -MergeInputSection<ELFT>::getOffset(uintX_t Offset) { - std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> T = - this->getRangeAndSize(Offset); - std::pair<uintX_t, uintX_t> *I = T.first; - uintX_t End = T.second; - uintX_t Start = I->first; +typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const { + auto It = OffsetMap.find(Offset); + if (It != OffsetMap.end()) + return It->second; - // Compute the Addend and if the Base is cached, return. - uintX_t Addend = Offset - Start; - uintX_t &Base = I->second; - if (Base != uintX_t(-1)) - return Base + Addend; + // If Offset is not at beginning of a section piece, it is not in the map. + // In that case we need to search from the original section piece vector. + const SectionPiece &Piece = *this->getSectionPiece(Offset); + assert(Piece.Live); + uintX_t Addend = Offset - Piece.InputOff; + return Piece.OutputOff + Addend; +} - // Map the base to the offset in the output section and cache it. - ArrayRef<uint8_t> D = this->getSectionData(); - StringRef Data((const char *)D.data(), D.size()); - StringRef Entry = Data.substr(Start, End - Start); - Base = - static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Entry); - return Base + Addend; +// Create a map from input offsets to output offsets for all section pieces. +// It is called after finalize(). +template <class ELFT> void MergeInputSection<ELFT>::finalizePieces() { + OffsetMap.grow(this->Pieces.size()); + for (SectionPiece &Piece : this->Pieces) { + if (!Piece.Live) + continue; + if (Piece.OutputOff == size_t(-1)) { + // Offsets of tail-merged strings are computed lazily. + auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec); + ArrayRef<uint8_t> D = Piece.data(); + StringRef S((const char *)D.data(), D.size()); + Piece.OutputOff = OutSec->getOffset(S); + } + OffsetMap[Piece.InputOff] = Piece.OutputOff; + } } template <class ELFT> -MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(ObjectFile<ELFT> *F, +MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(elf::ObjectFile<ELFT> *F, const Elf_Shdr *Hdr) : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) { // Initialize this->Reginfo. ArrayRef<uint8_t> D = this->getSectionData(); - if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) - error("Invalid size of .reginfo section"); + if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) { + error("invalid size of .reginfo section"); + return; + } Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data()); } @@ -366,31 +625,67 @@ bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo; } -namespace lld { -namespace elf2 { -template class InputSectionBase<object::ELF32LE>; -template class InputSectionBase<object::ELF32BE>; -template class InputSectionBase<object::ELF64LE>; -template class InputSectionBase<object::ELF64BE>; +template <class ELFT> +MipsOptionsInputSection<ELFT>::MipsOptionsInputSection(elf::ObjectFile<ELFT> *F, + const Elf_Shdr *Hdr) + : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsOptions) { + // Find ODK_REGINFO option in the section's content. + ArrayRef<uint8_t> D = this->getSectionData(); + while (!D.empty()) { + if (D.size() < sizeof(Elf_Mips_Options<ELFT>)) { + error("invalid size of .MIPS.options section"); + break; + } + auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(D.data()); + if (O->kind == ODK_REGINFO) { + Reginfo = &O->getRegInfo(); + break; + } + D = D.slice(O->size); + } +} + +template <class ELFT> +bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { + return S->SectionKind == InputSectionBase<ELFT>::MipsOptions; +} + +template bool elf::isDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *); +template bool elf::isDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *); +template bool elf::isDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *); +template bool elf::isDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *); -template class InputSection<object::ELF32LE>; -template class InputSection<object::ELF32BE>; -template class InputSection<object::ELF64LE>; -template class InputSection<object::ELF64BE>; +template class elf::InputSectionBase<ELF32LE>; +template class elf::InputSectionBase<ELF32BE>; +template class elf::InputSectionBase<ELF64LE>; +template class elf::InputSectionBase<ELF64BE>; -template class EHInputSection<object::ELF32LE>; -template class EHInputSection<object::ELF32BE>; -template class EHInputSection<object::ELF64LE>; -template class EHInputSection<object::ELF64BE>; +template class elf::InputSection<ELF32LE>; +template class elf::InputSection<ELF32BE>; +template class elf::InputSection<ELF64LE>; +template class elf::InputSection<ELF64BE>; -template class MergeInputSection<object::ELF32LE>; -template class MergeInputSection<object::ELF32BE>; -template class MergeInputSection<object::ELF64LE>; -template class MergeInputSection<object::ELF64BE>; +template class elf::SplitInputSection<ELF32LE>; +template class elf::SplitInputSection<ELF32BE>; +template class elf::SplitInputSection<ELF64LE>; +template class elf::SplitInputSection<ELF64BE>; -template class MipsReginfoInputSection<object::ELF32LE>; -template class MipsReginfoInputSection<object::ELF32BE>; -template class MipsReginfoInputSection<object::ELF64LE>; -template class MipsReginfoInputSection<object::ELF64BE>; -} -} +template class elf::EhInputSection<ELF32LE>; +template class elf::EhInputSection<ELF32BE>; +template class elf::EhInputSection<ELF64LE>; +template class elf::EhInputSection<ELF64BE>; + +template class elf::MergeInputSection<ELF32LE>; +template class elf::MergeInputSection<ELF32BE>; +template class elf::MergeInputSection<ELF64LE>; +template class elf::MergeInputSection<ELF64BE>; + +template class elf::MipsReginfoInputSection<ELF32LE>; +template class elf::MipsReginfoInputSection<ELF32BE>; +template class elf::MipsReginfoInputSection<ELF64LE>; +template class elf::MipsReginfoInputSection<ELF64BE>; + +template class elf::MipsOptionsInputSection<ELF32LE>; +template class elf::MipsOptionsInputSection<ELF32BE>; +template class elf::MipsOptionsInputSection<ELF64LE>; +template class elf::MipsOptionsInputSection<ELF64BE>; diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 26956c72a960..61a89c540c5d 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -11,12 +11,22 @@ #define LLD_ELF_INPUT_SECTION_H #include "Config.h" +#include "Relocations.h" +#include "Thunks.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" namespace lld { -namespace elf2 { +namespace elf { +template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S); + +class SymbolBody; + +template <class ELFT> class ICF; +template <class ELFT> class DefinedRegular; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; template <class ELFT> class OutputSectionBase; @@ -24,120 +34,148 @@ template <class ELFT> class OutputSectionBase; // This corresponds to a section of an input file. template <class ELFT> class InputSectionBase { protected: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Chdr Elf_Chdr; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; const Elf_Shdr *Header; // The file this section is from. ObjectFile<ELFT> *File; + // If a section is compressed, this vector has uncompressed section data. + SmallVector<char, 0> Uncompressed; + public: - enum Kind { Regular, EHFrame, Merge, MipsReginfo }; + enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; Kind SectionKind; + InputSectionBase() : Repl(this) {} + InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header, Kind SectionKind); OutputSectionBase<ELFT> *OutSec = nullptr; + uint32_t Alignment; // Used for garbage collection. - // Live bit makes sense only when Config->GcSections is true. - bool isLive() const { return !Config->GcSections || Live; } - bool Live = false; + bool Live; + + // This pointer points to the "real" instance of this instance. + // Usually Repl == this. However, if ICF merges two sections, + // Repl pointer of one section points to another section. So, + // if you need to get a pointer to this instance, do not use + // this but instead this->Repl. + InputSectionBase<ELFT> *Repl; // Returns the size of this section (even if this is a common or BSS.) - size_t getSize() const { return Header->sh_size; } + size_t getSize() const; static InputSectionBase<ELFT> Discarded; StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } ObjectFile<ELFT> *getFile() const { return File; } - - // The writer sets and uses the addresses. - uintX_t getAlign() { - // The ELF spec states that a value of 0 means the section has no alignment - // constraits. - return std::max<uintX_t>(Header->sh_addralign, 1); - } - - uintX_t getOffset(const Elf_Sym &Sym); + uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const; // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; ArrayRef<uint8_t> getSectionData() const; - // Returns a section that Rel is pointing to. Used by the garbage collector. - InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel); - InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel); + void uncompress(); + + void relocate(uint8_t *Buf, uint8_t *BufEnd); + std::vector<Relocation<ELFT>> Relocations; + + bool Compressed; +}; + +template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded; + +// SectionPiece represents a piece of splittable section contents. +struct SectionPiece { + SectionPiece(size_t Off, ArrayRef<uint8_t> Data) + : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()), + Live(!Config->GcSections) {} - template <bool isRela> - using RelIteratorRange = - llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>; + ArrayRef<uint8_t> data() { return {Data, Size}; } + size_t size() const { return Size; } - template <bool isRela> - void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange<isRela> Rels); + size_t InputOff; + size_t OutputOff = -1; private: - template <bool isRela> - uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type, - RelIteratorRange<isRela> Rels); -}; + // We use bitfields because SplitInputSection is accessed by + // std::upper_bound very often. + // We want to save bits to make it cache friendly. + const uint8_t *Data; + uint32_t Size : 31; -template <class ELFT> -InputSectionBase<ELFT> - InputSectionBase<ELFT>::Discarded(nullptr, nullptr, - InputSectionBase<ELFT>::Regular); +public: + uint32_t Live : 1; +}; // Usually sections are copied to the output as atomic chunks of data, // but some special types of sections are split into small pieces of data // and each piece is copied to a different place in the output. // This class represents such special sections. template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; public: SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header, typename InputSectionBase<ELFT>::Kind SectionKind); - // For each piece of data, we maintain the offsets in the input section and - // in the output section. The latter may be -1 if it is not assigned yet. - std::vector<std::pair<uintX_t, uintX_t>> Offsets; + // Splittable sections are handled as a sequence of data + // rather than a single large blob of data. + std::vector<SectionPiece> Pieces; - std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> - getRangeAndSize(uintX_t Offset); + // Returns the SectionPiece at a given input section offset. + SectionPiece *getSectionPiece(uintX_t Offset); + const SectionPiece *getSectionPiece(uintX_t Offset) const; }; // This corresponds to a SHF_MERGE section of an input file. template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Shdr Elf_Shdr; public: MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase<ELFT> *S); - // Translate an offset in the input section to an offset in the output - // section. - uintX_t getOffset(uintX_t Offset); + void splitIntoPieces(); + + // Mark the piece at a given offset live. Used by GC. + void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); } + + // Translate an offset in the input section to an offset + // in the output section. + uintX_t getOffset(uintX_t Offset) const; + + void finalizePieces(); + +private: + llvm::DenseMap<uintX_t, uintX_t> OffsetMap; + llvm::DenseSet<uintX_t> LiveOffsets; }; // This corresponds to a .eh_frame section of an input file. -template <class ELFT> class EHInputSection : public SplitInputSection<ELFT> { +template <class ELFT> class EhInputSection : public SplitInputSection<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - EHInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase<ELFT> *S); + void split(); // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; // Relocation section that refer to this one. const Elf_Shdr *RelocSection = nullptr; @@ -145,12 +183,13 @@ public: // This corresponds to a non SHF_MERGE section of an input file. template <class ELFT> class InputSection : public InputSectionBase<ELFT> { + friend ICF<ELFT>; typedef InputSectionBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; public: InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); @@ -160,13 +199,41 @@ public: void writeTo(uint8_t *Buf); // Relocation sections that refer to this one. - SmallVector<const Elf_Shdr *, 1> RelocSections; + llvm::TinyPtrVector<const Elf_Shdr *> RelocSections; // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; static bool classof(const InputSectionBase<ELFT> *S); + + InputSectionBase<ELFT> *getRelocatedSection(); + + // Register thunk related to the symbol. When the section is written + // to a mmap'ed file, target is requested to write an actual thunk code. + // Now thunks is supported for MIPS and ARM target only. + void addThunk(const Thunk<ELFT> *T); + + // The offset of synthetic thunk code from beginning of this section. + uint64_t getThunkOff() const; + + // Size of chunk with thunks code. + uint64_t getThunksSize() const; + + template <class RelTy> + void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + +private: + template <class RelTy> + void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + + // Called by ICF to merge two input sections. + void replace(InputSection<ELFT> *Other); + + // Used by ICF. + uint64_t GroupId = 0; + + llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks; }; // MIPS .reginfo section provides information on the registers used by the code @@ -177,16 +244,27 @@ public: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf template <class ELFT> class MipsReginfoInputSection : public InputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::Shdr Elf_Shdr; public: MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr); static bool classof(const InputSectionBase<ELFT> *S); - const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo; + const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr; +}; + +template <class ELFT> +class MipsOptionsInputSection : public InputSectionBase<ELFT> { + typedef typename ELFT::Shdr Elf_Shdr; + +public: + MipsOptionsInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr); + static bool classof(const InputSectionBase<ELFT> *S); + + const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr; }; -} // namespace elf2 +} // namespace elf } // namespace lld #endif diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp new file mode 100644 index 000000000000..0e8006a3b32a --- /dev/null +++ b/ELF/LTO.cpp @@ -0,0 +1,325 @@ +//===- LTO.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTO.h" +#include "Config.h" +#include "Driver.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LoopPassManager.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/ParallelCG.h" +#include "llvm/IR/AutoUpgrade.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/LTO/legacy/UpdateCompilerUsed.h" +#include "llvm/Linker/IRMover.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +// This is for use when debugging LTO. +static void saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error(EC, "cannot create " + Path); + OS << Buffer; +} + +// This is for use when debugging LTO. +static void saveBCFile(Module &M, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error(EC, "cannot create " + Path); + WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); +} + +static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) { + PassBuilder PB(&TM); + + AAManager AA; + + // Parse a custom AA pipeline if asked to. + if (!PB.parseAAPipeline(AA, Config->LtoAAPipeline)) { + error("Unable to parse AA pipeline description: " + Config->LtoAAPipeline); + return; + } + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + // Register the AA manager first so that our version is the one used. + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + if (!Config->DisableVerify) + MPM.addPass(VerifierPass()); + + // Now, add all the passes we've been requested to. + if (!PB.parsePassPipeline(MPM, Config->LtoNewPmPasses)) { + error("unable to parse pass pipeline description: " + + Config->LtoNewPmPasses); + return; + } + + if (!Config->DisableVerify) + MPM.addPass(VerifierPass()); + MPM.run(M, MAM); +} + +static void runOldLtoPasses(Module &M, TargetMachine &TM) { + // Note that the gold plugin has a similar piece of code, so + // it is probably better to move this code to a common place. + legacy::PassManager LtoPasses; + LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); + PassManagerBuilder PMB; + PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); + PMB.Inliner = createFunctionInliningPass(); + PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify; + PMB.LoopVectorize = true; + PMB.SLPVectorize = true; + PMB.OptLevel = Config->LtoO; + PMB.populateLTOPassManager(LtoPasses); + LtoPasses.run(M); +} + +static void runLTOPasses(Module &M, TargetMachine &TM) { + if (!Config->LtoNewPmPasses.empty()) { + // The user explicitly asked for a set of passes to be run. + // This needs the new PM to work as there's no clean way to + // pass a set of passes to run in the legacy PM. + runNewCustomLtoPasses(M, TM); + if (HasError) + return; + } else { + // Run the 'default' set of LTO passes. This code still uses + // the legacy PM as the new one is not the default. + runOldLtoPasses(M, TM); + } + + if (Config->SaveTemps) + saveBCFile(M, Config->OutputFile + ".lto.opt.bc"); +} + +static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used, + Symbol *S, GlobalValue *GV) { + if (S->IsUsedInRegularObj || Used.count(GV)) + return false; + return !S->includeInDynsym(); +} + +BitcodeCompiler::BitcodeCompiler() + : Combined(new Module("ld-temp.o", Driver->Context)) {} + +static void undefine(Symbol *S) { + replaceBody<Undefined>(S, S->body()->getName(), STV_DEFAULT, S->body()->Type, + nullptr); +} + +static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV, + StringSet<> &AsmUndefinedRefs) { + // GV associated => not an assembly symbol, bail out. + if (GV) + return; + + // This is an undefined reference to a symbol in asm. We put that in + // compiler.used, so that we can preserve it from being dropped from + // the output, without necessarily preventing its internalization. + SmallString<64> Name; + raw_svector_ostream OS(Name); + Sym.printName(OS); + AsmUndefinedRefs.insert(Name.str()); +} + +void BitcodeCompiler::add(BitcodeFile &F) { + std::unique_ptr<IRObjectFile> Obj = std::move(F.Obj); + std::vector<GlobalValue *> Keep; + unsigned BodyIndex = 0; + ArrayRef<Symbol *> Syms = F.getSymbols(); + + Module &M = Obj->getModule(); + if (M.getDataLayoutStr().empty()) + fatal("invalid bitcode file: " + F.getName() + " has no datalayout"); + + // Discard non-compatible debug infos if necessary. + M.materializeMetadata(); + UpgradeDebugInfo(M); + + // If a symbol appears in @llvm.used, the linker is required + // to treat the symbol as there is a reference to the symbol + // that it cannot see. Therefore, we can't internalize. + SmallPtrSet<GlobalValue *, 8> Used; + collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false); + + for (const BasicSymbolRef &Sym : Obj->symbols()) { + uint32_t Flags = Sym.getFlags(); + GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); + if (GV && GV->hasAppendingLinkage()) + Keep.push_back(GV); + if (BitcodeFile::shouldSkip(Flags)) + continue; + Symbol *S = Syms[BodyIndex++]; + if (Flags & BasicSymbolRef::SF_Undefined) { + handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs); + continue; + } + auto *B = dyn_cast<DefinedBitcode>(S->body()); + if (!B || B->file() != &F) + continue; + + // We collect the set of symbols we want to internalize here + // and change the linkage after the IRMover executed, i.e. after + // we imported the symbols and satisfied undefined references + // to it. We can't just change linkage here because otherwise + // the IRMover will just rename the symbol. + if (GV && shouldInternalize(Used, S, GV)) + InternalizedSyms.insert(GV->getName()); + + // At this point we know that either the combined LTO object will provide a + // definition of a symbol, or we will internalize it. In either case, we + // need to undefine the symbol. In the former case, the real definition + // needs to be able to replace the original definition without conflicting. + // In the latter case, we need to allow the combined LTO object to provide a + // definition with the same name, for example when doing parallel codegen. + undefine(S); + + if (!GV) + // Module asm symbol. + continue; + + switch (GV->getLinkage()) { + default: + break; + case GlobalValue::LinkOnceAnyLinkage: + GV->setLinkage(GlobalValue::WeakAnyLinkage); + break; + case GlobalValue::LinkOnceODRLinkage: + GV->setLinkage(GlobalValue::WeakODRLinkage); + break; + } + + Keep.push_back(GV); + } + + IRMover Mover(*Combined); + if (Error E = Mover.move(Obj->takeModule(), Keep, + [](GlobalValue &, IRMover::ValueAdder) {})) { + handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) { + fatal("failed to link module " + F.getName() + ": " + EIB.message()); + }); + } +} + +static void internalize(GlobalValue &GV) { + assert(!GV.hasLocalLinkage() && + "Trying to internalize a symbol with local linkage!"); + GV.setLinkage(GlobalValue::InternalLinkage); +} + +std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::runSplitCodegen( + const std::function<std::unique_ptr<TargetMachine>()> &TMFactory) { + unsigned NumThreads = Config->LtoJobs; + OwningData.resize(NumThreads); + + std::list<raw_svector_ostream> OSs; + std::vector<raw_pwrite_stream *> OSPtrs; + for (SmallString<0> &Obj : OwningData) { + OSs.emplace_back(Obj); + OSPtrs.push_back(&OSs.back()); + } + + splitCodeGen(std::move(Combined), OSPtrs, {}, TMFactory); + + std::vector<std::unique_ptr<InputFile>> ObjFiles; + for (SmallString<0> &Obj : OwningData) + ObjFiles.push_back(createObjectFile( + MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object"))); + + // If -save-temps is given, we need to save temporary objects to files. + // This is for debugging. + if (Config->SaveTemps) { + if (NumThreads == 1) { + saveBuffer(OwningData[0], Config->OutputFile + ".lto.o"); + } else { + for (unsigned I = 0; I < NumThreads; ++I) + saveBuffer(OwningData[I], Config->OutputFile + Twine(I) + ".lto.o"); + } + } + + return ObjFiles; +} + +// Merge all the bitcode files we have seen, codegen the result +// and return the resulting ObjectFile. +std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::compile() { + for (const auto &Name : InternalizedSyms) { + GlobalValue *GV = Combined->getNamedValue(Name.first()); + assert(GV); + internalize(*GV); + } + + std::string TheTriple = Combined->getTargetTriple(); + std::string Msg; + const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg); + if (!T) + fatal("target not found: " + Msg); + + // LLD supports the new relocations. + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + Options.RelaxELFRelocations = true; + + auto CreateTargetMachine = [&]() { + return std::unique_ptr<TargetMachine>(T->createTargetMachine( + TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static)); + }; + + std::unique_ptr<TargetMachine> TM = CreateTargetMachine(); + + // Update llvm.compiler.used so that optimizations won't strip + // off AsmUndefinedReferences. + updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs); + + if (Config->SaveTemps) + saveBCFile(*Combined, Config->OutputFile + ".lto.bc"); + + runLTOPasses(*Combined, *TM); + if (HasError) + return {}; + + return runSplitCodegen(CreateTargetMachine); +} diff --git a/ELF/LTO.h b/ELF/LTO.h new file mode 100644 index 000000000000..81dffb6004b2 --- /dev/null +++ b/ELF/LTO.h @@ -0,0 +1,54 @@ +//===- LTO.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a way to combine bitcode files into one ELF +// file by compiling them using LLVM. +// +// If LTO is in use, your input files are not in regular ELF files +// but instead LLVM bitcode files. In that case, the linker has to +// convert bitcode files into the native format so that we can create +// an ELF file that contains native code. This file provides that +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_LTO_H +#define LLD_ELF_LTO_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/Module.h" +#include "llvm/Linker/IRMover.h" + +namespace lld { +namespace elf { + +class BitcodeFile; +class InputFile; + +class BitcodeCompiler { +public: + BitcodeCompiler(); + void add(BitcodeFile &F); + std::vector<std::unique_ptr<InputFile>> compile(); + +private: + std::vector<std::unique_ptr<InputFile>> runSplitCodegen( + const std::function<std::unique_ptr<llvm::TargetMachine>()> &TMFactory); + + std::unique_ptr<llvm::Module> Combined; + std::vector<SmallString<0>> OwningData; + llvm::StringSet<> InternalizedSyms; + llvm::StringSet<> AsmUndefinedRefs; +}; +} +} + +#endif diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index a6df9ed48cdc..61abdc185e11 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -13,154 +13,366 @@ // //===----------------------------------------------------------------------===// +#include "LinkerScript.h" #include "Config.h" #include "Driver.h" +#include "InputSection.h" +#include "OutputSections.h" +#include "ScriptParser.h" +#include "Strings.h" +#include "Symbols.h" #include "SymbolTable.h" +#include "Target.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/StringSaver.h" using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; +ScriptConfiguration *elf::ScriptConfig; + +// This is an operator-precedence parser to parse and evaluate +// a linker script expression. For each linker script arithmetic +// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser +// is created and ran. namespace { -class LinkerScript { +class ExprParser : public ScriptParserBase { public: - LinkerScript(BumpPtrAllocator *A, StringRef S, bool B) - : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {} - void run(); + ExprParser(std::vector<StringRef> &Tokens, uint64_t Dot) + : ScriptParserBase(Tokens), Dot(Dot) {} + + uint64_t run(); private: - static std::vector<StringRef> tokenize(StringRef S); - static StringRef skipSpace(StringRef S); - StringRef next(); - bool skip(StringRef Tok); - bool atEOF() { return Tokens.size() == Pos; } - void expect(StringRef Expect); + uint64_t parsePrimary(); + uint64_t parseTernary(uint64_t Cond); + uint64_t apply(StringRef Op, uint64_t L, uint64_t R); + uint64_t parseExpr1(uint64_t Lhs, int MinPrec); + uint64_t parseExpr(); - void addFile(StringRef Path); + uint64_t Dot; +}; +} - void readAsNeeded(); - void readEntry(); - void readExtern(); - void readGroup(); - void readInclude(); - void readOutput(); - void readOutputArch(); - void readOutputFormat(); - void readSearchDir(); - void readSections(); +static int precedence(StringRef Op) { + return StringSwitch<int>(Op) + .Case("*", 4) + .Case("/", 4) + .Case("+", 3) + .Case("-", 3) + .Case("<", 2) + .Case(">", 2) + .Case(">=", 2) + .Case("<=", 2) + .Case("==", 2) + .Case("!=", 2) + .Case("&", 1) + .Default(-1); +} - void readOutputSectionDescription(); +static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) { + return ExprParser(Tokens, Dot).run(); +} - StringSaver Saver; - std::vector<StringRef> Tokens; - size_t Pos = 0; - bool IsUnderSysroot; -}; +uint64_t ExprParser::run() { + uint64_t V = parseExpr(); + if (!atEOF() && !Error) + setError("stray token: " + peek()); + return V; } -void LinkerScript::run() { - while (!atEOF()) { - StringRef Tok = next(); - if (Tok == ";") - continue; - if (Tok == "ENTRY") { - readEntry(); - } else if (Tok == "EXTERN") { - readExtern(); - } else if (Tok == "GROUP" || Tok == "INPUT") { - readGroup(); - } else if (Tok == "INCLUDE") { - readInclude(); - } else if (Tok == "OUTPUT") { - readOutput(); - } else if (Tok == "OUTPUT_ARCH") { - readOutputArch(); - } else if (Tok == "OUTPUT_FORMAT") { - readOutputFormat(); - } else if (Tok == "SEARCH_DIR") { - readSearchDir(); - } else if (Tok == "SECTIONS") { - readSections(); - } else { - error("unknown directive: " + Tok); +// This is a part of the operator-precedence parser to evaluate +// arithmetic expressions in SECTIONS command. This function evaluates an +// integer literal, a parenthesized expression, the ALIGN function, +// or the special variable ".". +uint64_t ExprParser::parsePrimary() { + StringRef Tok = next(); + if (Tok == ".") + return Dot; + if (Tok == "(") { + uint64_t V = parseExpr(); + expect(")"); + return V; + } + if (Tok == "ALIGN") { + expect("("); + uint64_t V = parseExpr(); + expect(")"); + return alignTo(Dot, V); + } + uint64_t V = 0; + if (Tok.getAsInteger(0, V)) + setError("malformed number: " + Tok); + return V; +} + +uint64_t ExprParser::parseTernary(uint64_t Cond) { + next(); + uint64_t V = parseExpr(); + expect(":"); + uint64_t W = parseExpr(); + return Cond ? V : W; +} + +uint64_t ExprParser::apply(StringRef Op, uint64_t L, uint64_t R) { + if (Op == "*") + return L * R; + if (Op == "/") { + if (R == 0) { + error("division by zero"); + return 0; } + return L / R; } + if (Op == "+") + return L + R; + if (Op == "-") + return L - R; + if (Op == "<") + return L < R; + if (Op == ">") + return L > R; + if (Op == ">=") + return L >= R; + if (Op == "<=") + return L <= R; + if (Op == "==") + return L == R; + if (Op == "!=") + return L != R; + if (Op == "&") + return L & R; + llvm_unreachable("invalid operator"); } -// Split S into linker script tokens. -std::vector<StringRef> LinkerScript::tokenize(StringRef S) { - std::vector<StringRef> Ret; - for (;;) { - S = skipSpace(S); - if (S.empty()) - return Ret; +// This is a part of the operator-precedence parser. +// This function assumes that the remaining token stream starts +// with an operator. +uint64_t ExprParser::parseExpr1(uint64_t Lhs, int MinPrec) { + while (!atEOF()) { + // Read an operator and an expression. + StringRef Op1 = peek(); + if (Op1 == "?") + return parseTernary(Lhs); + if (precedence(Op1) < MinPrec) + return Lhs; + next(); + uint64_t Rhs = parsePrimary(); - // Quoted token - if (S.startswith("\"")) { - size_t E = S.find("\"", 1); - if (E == StringRef::npos) - error("unclosed quote"); - Ret.push_back(S.substr(1, E)); - S = S.substr(E + 1); - continue; + // Evaluate the remaining part of the expression first if the + // next operator has greater precedence than the previous one. + // For example, if we have read "+" and "3", and if the next + // operator is "*", then we'll evaluate 3 * ... part first. + while (!atEOF()) { + StringRef Op2 = peek(); + if (precedence(Op2) <= precedence(Op1)) + break; + Rhs = parseExpr1(Rhs, precedence(Op2)); } - // Unquoted token - size_t Pos = S.find_first_not_of( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789_.$/\\~=+[]*?-:"); - // A character that cannot start a word (which is usually a - // punctuation) forms a single character token. - if (Pos == 0) - Pos = 1; - Ret.push_back(S.substr(0, Pos)); - S = S.substr(Pos); + Lhs = apply(Op1, Lhs, Rhs); } + return Lhs; } -// Skip leading whitespace characters or /**/-style comments. -StringRef LinkerScript::skipSpace(StringRef S) { - for (;;) { - if (S.startswith("/*")) { - size_t E = S.find("*/", 2); - if (E == StringRef::npos) - error("unclosed comment in a linker script"); - S = S.substr(E + 2); +// Reads and evaluates an arithmetic expression. +uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); } + +template <class ELFT> +StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) { + for (SectionRule &R : Opt.Sections) + if (globMatch(R.SectionPattern, S->getSectionName())) + return R.Dest; + return ""; +} + +template <class ELFT> +bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) { + return getOutputSection(S) == "/DISCARD/"; +} + +template <class ELFT> +bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) { + for (StringRef Pat : Opt.KeptSections) + if (globMatch(Pat, S->getSectionName())) + return true; + return false; +} + +template <class ELFT> +void LinkerScript<ELFT>::assignAddresses( + ArrayRef<OutputSectionBase<ELFT> *> Sections) { + // Orphan sections are sections present in the input files which + // are not explicitly placed into the output file by the linker script. + // We place orphan sections at end of file. + // Other linkers places them using some heuristics as described in + // https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections. + for (OutputSectionBase<ELFT> *Sec : Sections) { + StringRef Name = Sec->getName(); + if (getSectionIndex(Name) == INT_MAX) + Opt.Commands.push_back({SectionKind, {}, Name}); + } + + // Assign addresses as instructed by linker script SECTIONS sub-commands. + Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize(); + uintX_t MinVA = std::numeric_limits<uintX_t>::max(); + uintX_t ThreadBssOffset = 0; + + for (SectionsCommand &Cmd : Opt.Commands) { + if (Cmd.Kind == AssignmentKind) { + uint64_t Val = evalExpr(Cmd.Expr, Dot); + + if (Cmd.Name == ".") { + Dot = Val; + } else { + auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name)); + D->Value = Val; + } continue; } - size_t Size = S.size(); - S = S.ltrim(); - if (S.size() == Size) - return S; + + // Find all the sections with required name. There can be more than + // ont section with such name, if the alignment, flags or type + // attribute differs. + assert(Cmd.Kind == SectionKind); + for (OutputSectionBase<ELFT> *Sec : Sections) { + if (Sec->getName() != Cmd.Name) + continue; + + if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { + uintX_t TVA = Dot + ThreadBssOffset; + TVA = alignTo(TVA, Sec->getAlignment()); + Sec->setVA(TVA); + ThreadBssOffset = TVA - Dot + Sec->getSize(); + continue; + } + + if (Sec->getFlags() & SHF_ALLOC) { + Dot = alignTo(Dot, Sec->getAlignment()); + Sec->setVA(Dot); + MinVA = std::min(MinVA, Dot); + Dot += Sec->getSize(); + continue; + } + } } + + // ELF and Program headers need to be right before the first section in + // memory. + // Set their addresses accordingly. + MinVA = alignDown(MinVA - Out<ELFT>::ElfHeader->getSize() - + Out<ELFT>::ProgramHeaders->getSize(), + Target->PageSize); + Out<ELFT>::ElfHeader->setVA(MinVA); + Out<ELFT>::ProgramHeaders->setVA(Out<ELFT>::ElfHeader->getSize() + MinVA); } -StringRef LinkerScript::next() { - if (atEOF()) - error("unexpected EOF"); - return Tokens[Pos++]; +template <class ELFT> +ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) { + auto I = Opt.Filler.find(Name); + if (I == Opt.Filler.end()) + return {}; + return I->second; } -bool LinkerScript::skip(StringRef Tok) { - if (atEOF()) - error("unexpected EOF"); - if (Tok != Tokens[Pos]) - return false; - ++Pos; - return true; +// Returns the index of the given section name in linker script +// SECTIONS commands. Sections are laid out as the same order as they +// were in the script. If a given name did not appear in the script, +// it returns INT_MAX, so that it will be laid out at end of file. +template <class ELFT> +int LinkerScript<ELFT>::getSectionIndex(StringRef Name) { + auto Begin = Opt.Commands.begin(); + auto End = Opt.Commands.end(); + auto I = std::find_if(Begin, End, [&](SectionsCommand &N) { + return N.Kind == SectionKind && N.Name == Name; + }); + return I == End ? INT_MAX : (I - Begin); } -void LinkerScript::expect(StringRef Expect) { - StringRef Tok = next(); - if (Tok != Expect) - error(Expect + " expected, but got " + Tok); +// A compartor to sort output sections. Returns -1 or 1 if +// A or B are mentioned in linker script. Otherwise, returns 0. +template <class ELFT> +int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) { + int I = getSectionIndex(A); + int J = getSectionIndex(B); + if (I == INT_MAX && J == INT_MAX) + return 0; + return I < J ? -1 : 1; } -void LinkerScript::addFile(StringRef S) { +template <class ELFT> +void LinkerScript<ELFT>::addScriptedSymbols() { + for (SectionsCommand &Cmd : Opt.Commands) + if (Cmd.Kind == AssignmentKind) + if (Cmd.Name != "." && Symtab<ELFT>::X->find(Cmd.Name) == nullptr) + Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT); +} + +class elf::ScriptParser : public ScriptParserBase { + typedef void (ScriptParser::*Handler)(); + +public: + ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {} + + void run(); + +private: + void addFile(StringRef Path); + + void readAsNeeded(); + void readEntry(); + void readExtern(); + void readGroup(); + void readInclude(); + void readNothing() {} + void readOutput(); + void readOutputArch(); + void readOutputFormat(); + void readSearchDir(); + void readSections(); + + void readLocationCounterValue(); + void readOutputSectionDescription(StringRef OutSec); + void readSymbolAssignment(StringRef Name); + std::vector<StringRef> readSectionsCommandExpr(); + + const static StringMap<Handler> Cmd; + ScriptConfiguration &Opt = *ScriptConfig; + StringSaver Saver = {ScriptConfig->Alloc}; + bool IsUnderSysroot; +}; + +const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = { + {"ENTRY", &ScriptParser::readEntry}, + {"EXTERN", &ScriptParser::readExtern}, + {"GROUP", &ScriptParser::readGroup}, + {"INCLUDE", &ScriptParser::readInclude}, + {"INPUT", &ScriptParser::readGroup}, + {"OUTPUT", &ScriptParser::readOutput}, + {"OUTPUT_ARCH", &ScriptParser::readOutputArch}, + {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat}, + {"SEARCH_DIR", &ScriptParser::readSearchDir}, + {"SECTIONS", &ScriptParser::readSections}, + {";", &ScriptParser::readNothing}}; + +void ScriptParser::run() { + while (!atEOF()) { + StringRef Tok = next(); + if (Handler Fn = Cmd.lookup(Tok)) + (this->*Fn)(); + else + setError("unknown directive: " + Tok); + } +} + +void ScriptParser::addFile(StringRef S) { if (IsUnderSysroot && S.startswith("/")) { SmallString<128> Path; (Config->Sysroot + S).toStringRef(Path); @@ -178,22 +390,23 @@ void LinkerScript::addFile(StringRef S) { else Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1))); } else if (S.startswith("-l")) { - Driver->addFile(searchLibrary(S.substr(2))); + Driver->addLibrary(S.substr(2)); } else if (sys::fs::exists(S)) { Driver->addFile(S); } else { std::string Path = findFromSearchPaths(S); if (Path.empty()) - error("Unable to find " + S); - Driver->addFile(Saver.save(Path)); + setError("unable to find " + S); + else + Driver->addFile(Saver.save(Path)); } } -void LinkerScript::readAsNeeded() { +void ScriptParser::readAsNeeded() { expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") break; @@ -202,7 +415,7 @@ void LinkerScript::readAsNeeded() { Config->AsNeeded = Orig; } -void LinkerScript::readEntry() { +void ScriptParser::readEntry() { // -e <symbol> takes predecence over ENTRY(<symbol>). expect("("); StringRef Tok = next(); @@ -211,9 +424,9 @@ void LinkerScript::readEntry() { expect(")"); } -void LinkerScript::readExtern() { +void ScriptParser::readExtern() { expect("("); - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") return; @@ -221,9 +434,9 @@ void LinkerScript::readExtern() { } } -void LinkerScript::readGroup() { +void ScriptParser::readGroup() { expect("("); - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") return; @@ -235,17 +448,20 @@ void LinkerScript::readGroup() { } } -void LinkerScript::readInclude() { +void ScriptParser::readInclude() { StringRef Tok = next(); auto MBOrErr = MemoryBuffer::getFile(Tok); - error(MBOrErr, "cannot open " + Tok); + if (!MBOrErr) { + setError("cannot open " + Tok); + return; + } std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); std::vector<StringRef> V = tokenize(S); Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); } -void LinkerScript::readOutput() { +void ScriptParser::readOutput() { // -o <file> takes predecence over OUTPUT(<file>). expect("("); StringRef Tok = next(); @@ -254,52 +470,119 @@ void LinkerScript::readOutput() { expect(")"); } -void LinkerScript::readOutputArch() { +void ScriptParser::readOutputArch() { // Error checking only for now. expect("("); next(); expect(")"); } -void LinkerScript::readOutputFormat() { +void ScriptParser::readOutputFormat() { // Error checking only for now. expect("("); next(); StringRef Tok = next(); if (Tok == ")") return; - if (Tok != ",") - error("unexpected token: " + Tok); + if (Tok != ",") { + setError("unexpected token: " + Tok); + return; + } next(); expect(","); next(); expect(")"); } -void LinkerScript::readSearchDir() { +void ScriptParser::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); expect(")"); } -void LinkerScript::readSections() { +void ScriptParser::readSections() { + Opt.DoLayout = true; expect("{"); - while (!skip("}")) - readOutputSectionDescription(); + while (!Error && !skip("}")) { + StringRef Tok = peek(); + if (Tok == ".") { + readLocationCounterValue(); + continue; + } + next(); + if (peek() == "=") + readSymbolAssignment(Tok); + else + readOutputSectionDescription(Tok); + } } -void LinkerScript::readOutputSectionDescription() { - StringRef Name = next(); - std::vector<StringRef> &InputSections = Config->OutputSections[Name]; +void ScriptParser::readLocationCounterValue() { + expect("."); + expect("="); + std::vector<StringRef> Expr = readSectionsCommandExpr(); + if (Expr.empty()) + error("error in location counter expression"); + else + Opt.Commands.push_back({AssignmentKind, std::move(Expr), "."}); +} +void ScriptParser::readOutputSectionDescription(StringRef OutSec) { + Opt.Commands.push_back({SectionKind, {}, OutSec}); expect(":"); expect("{"); - while (!skip("}")) { - next(); // Skip input file name. - expect("("); - while (!skip(")")) - InputSections.push_back(next()); + + while (!Error && !skip("}")) { + StringRef Tok = next(); + if (Tok == "*") { + expect("("); + while (!Error && !skip(")")) + Opt.Sections.emplace_back(OutSec, next()); + } else if (Tok == "KEEP") { + expect("("); + expect("*"); + expect("("); + while (!Error && !skip(")")) { + StringRef Sec = next(); + Opt.Sections.emplace_back(OutSec, Sec); + Opt.KeptSections.push_back(Sec); + } + expect(")"); + } else { + setError("unknown command " + Tok); + } + } + + StringRef Tok = peek(); + if (Tok.startswith("=")) { + if (!Tok.startswith("=0x")) { + setError("filler should be a hexadecimal value"); + return; + } + Tok = Tok.substr(3); + Opt.Filler[OutSec] = parseHex(Tok); + next(); + } +} + +void ScriptParser::readSymbolAssignment(StringRef Name) { + expect("="); + std::vector<StringRef> Expr = readSectionsCommandExpr(); + if (Expr.empty()) + error("error in symbol assignment expression"); + else + Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name}); +} + +std::vector<StringRef> ScriptParser::readSectionsCommandExpr() { + std::vector<StringRef> Expr; + while (!Error) { + StringRef Tok = next(); + if (Tok == ";") + break; + Expr.push_back(Tok); } + return Expr; } static bool isUnderSysroot(StringRef Path) { @@ -311,8 +594,13 @@ static bool isUnderSysroot(StringRef Path) { return false; } -// Entry point. The other functions or classes are private to this file. -void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { +// Entry point. +void elf::readLinkerScript(MemoryBufferRef MB) { StringRef Path = MB.getBufferIdentifier(); - LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run(); + ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run(); } + +template class elf::LinkerScript<ELF32LE>; +template class elf::LinkerScript<ELF32BE>; +template class elf::LinkerScript<ELF64LE>; +template class elf::LinkerScript<ELF64BE>; diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h new file mode 100644 index 000000000000..768f78a66468 --- /dev/null +++ b/ELF/LinkerScript.h @@ -0,0 +1,103 @@ +//===- LinkerScript.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_LINKER_SCRIPT_H +#define LLD_ELF_LINKER_SCRIPT_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace lld { +namespace elf { + +// Parses a linker script. Calling this function updates +// Config and ScriptConfig. +void readLinkerScript(MemoryBufferRef MB); + +class ScriptParser; +template <class ELFT> class InputSectionBase; +template <class ELFT> class OutputSectionBase; + +// This class represents each rule in SECTIONS command. +struct SectionRule { + SectionRule(StringRef D, StringRef S) + : Dest(D), SectionPattern(S) {} + + StringRef Dest; + + StringRef SectionPattern; +}; + +// This enum represents what we can observe in SECTIONS tag of script: +// ExprKind is a location counter change, like ". = . + 0x1000" +// SectionKind is a description of output section, like ".data :..." +enum SectionsCommandKind { SectionKind, AssignmentKind }; + +struct SectionsCommand { + SectionsCommandKind Kind; + std::vector<StringRef> Expr; + StringRef Name; +}; + +// ScriptConfiguration holds linker script parse results. +struct ScriptConfiguration { + // SECTIONS commands. + std::vector<SectionRule> Sections; + + // Section fill attribute for each section. + llvm::StringMap<std::vector<uint8_t>> Filler; + + // Used to assign addresses to sections. + std::vector<SectionsCommand> Commands; + + bool DoLayout = false; + + llvm::BumpPtrAllocator Alloc; + + // List of section patterns specified with KEEP commands. They will + // be kept even if they are unused and --gc-sections is specified. + std::vector<StringRef> KeptSections; +}; + +extern ScriptConfiguration *ScriptConfig; + +// This is a runner of the linker script. +template <class ELFT> class LinkerScript { + typedef typename ELFT::uint uintX_t; + +public: + StringRef getOutputSection(InputSectionBase<ELFT> *S); + ArrayRef<uint8_t> getFiller(StringRef Name); + bool isDiscarded(InputSectionBase<ELFT> *S); + bool shouldKeep(InputSectionBase<ELFT> *S); + void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S); + int compareSections(StringRef A, StringRef B); + void addScriptedSymbols(); + +private: + // "ScriptConfig" is a bit too long, so define a short name for it. + ScriptConfiguration &Opt = *ScriptConfig; + + int getSectionIndex(StringRef Name); + + uintX_t Dot; +}; + +// Variable template is a C++14 feature, so we can't template +// a global variable. Use a struct to workaround. +template <class ELFT> struct Script { static LinkerScript<ELFT> *X; }; +template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X; + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index f682f3b8b473..41e30ce599d2 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -21,9 +21,12 @@ //===----------------------------------------------------------------------===// #include "InputSection.h" +#include "LinkerScript.h" #include "OutputSections.h" +#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" +#include "Target.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" @@ -35,30 +38,78 @@ using namespace llvm::ELF; using namespace llvm::object; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; + +// A resolved relocation. The Sec and Offset fields are set if the relocation +// was resolved to an offset within a section. +template <class ELFT> +struct ResolvedReloc { + InputSectionBase<ELFT> *Sec; + typename ELFT::uint Offset; +}; + +template <class ELFT> +static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec, + const typename ELFT::Rel &Rel) { + return Target->getImplicitAddend(Sec.getSectionData().begin(), + Rel.getType(Config->Mips64EL)); +} -// Calls Fn for each section that Sec refers to via relocations. template <class ELFT> -static void forEachSuccessor(InputSection<ELFT> *Sec, - std::function<void(InputSectionBase<ELFT> *)> Fn) { - typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr; +static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec, + const typename ELFT::Rela &Rel) { + return Rel.r_addend; +} + +template <class ELFT, class RelT> +static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec, + RelT &Rel) { + SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel); + auto *D = dyn_cast<DefinedRegular<ELFT>>(&B); + if (!D || !D->Section) + return {nullptr, 0}; + typename ELFT::uint Offset = D->Value; + if (D->isSection()) + Offset += getAddend(Sec, Rel); + return {D->Section->Repl, Offset}; +} - ELFFile<ELFT> &Obj = Sec->getFile()->getObj(); - for (const Elf_Shdr *RelSec : Sec->RelocSections) { - if (RelSec->sh_type == SHT_RELA) { - for (const Elf_Rela &RI : Obj.relas(RelSec)) - if (InputSectionBase<ELFT> *Succ = Sec->getRelocTarget(RI)) - Fn(Succ); - } else { - for (const Elf_Rel &RI : Obj.rels(RelSec)) - if (InputSectionBase<ELFT> *Succ = Sec->getRelocTarget(RI)) - Fn(Succ); - } +template <class ELFT, class Elf_Shdr> +static void run(ELFFile<ELFT> &Obj, InputSectionBase<ELFT> &Sec, + Elf_Shdr *RelSec, std::function<void(ResolvedReloc<ELFT>)> Fn) { + if (RelSec->sh_type == SHT_RELA) { + for (const typename ELFT::Rela &RI : Obj.relas(RelSec)) + Fn(resolveReloc(Sec, RI)); + } else { + for (const typename ELFT::Rel &RI : Obj.rels(RelSec)) + Fn(resolveReloc(Sec, RI)); } } +// Calls Fn for each section that Sec refers to via relocations. +template <class ELFT> +static void forEachSuccessor(InputSection<ELFT> &Sec, + std::function<void(ResolvedReloc<ELFT>)> Fn) { + ELFFile<ELFT> &Obj = Sec.getFile()->getObj(); + for (const typename ELFT::Shdr *RelSec : Sec.RelocSections) + run(Obj, Sec, RelSec, Fn); +} + +template <class ELFT> +static void scanEhFrameSection(EhInputSection<ELFT> &EH, + std::function<void(ResolvedReloc<ELFT>)> Fn) { + if (!EH.RelocSection) + return; + ELFFile<ELFT> &EObj = EH.getFile()->getObj(); + run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) { + if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded) + return; + if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR) + return; + Fn({R.Sec, 0}); + }); +} + // Sections listed below are special because they are used by the loader // just by being in an ELF file. They should not be garbage-collected. template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) { @@ -70,6 +121,12 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) { return true; default: StringRef S = Sec->getSectionName(); + + // We do not want to reclaim sections if they can be referred + // by __start_* and __stop_* symbols. + if (isValidCIdentifier(S)) + return true; + return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || S.startswith(".jcr"); @@ -79,52 +136,66 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) { // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. -template <class ELFT> void elf2::markLive(SymbolTable<ELFT> *Symtab) { +template <class ELFT> void elf::markLive() { SmallVector<InputSection<ELFT> *, 256> Q; - auto Enqueue = [&](InputSectionBase<ELFT> *Sec) { - if (!Sec || Sec->Live) + auto Enqueue = [&](ResolvedReloc<ELFT> R) { + if (!R.Sec) + return; + + // Usually, a whole section is marked as live or dead, but in mergeable + // (splittable) sections, each piece of data has independent liveness bit. + // So we explicitly tell it which offset is in use. + if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec)) + MS->markLiveAt(R.Offset); + + if (R.Sec->Live) return; - Sec->Live = true; - if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(Sec)) + R.Sec->Live = true; + if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec)) Q.push_back(S); }; - auto MarkSymbol = [&](SymbolBody *Sym) { - if (Sym) - if (auto *D = dyn_cast<DefinedRegular<ELFT>>(Sym->repl())) - Enqueue(D->Section); + auto MarkSymbol = [&](const SymbolBody *Sym) { + if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym)) + Enqueue({D->Section, D->Value}); }; // Add GC root symbols. - MarkSymbol(Config->EntrySym); - MarkSymbol(Symtab->find(Config->Init)); - MarkSymbol(Symtab->find(Config->Fini)); + if (Config->EntrySym) + MarkSymbol(Config->EntrySym->body()); + MarkSymbol(Symtab<ELFT>::X->find(Config->Init)); + MarkSymbol(Symtab<ELFT>::X->find(Config->Fini)); for (StringRef S : Config->Undefined) - MarkSymbol(Symtab->find(S)); + MarkSymbol(Symtab<ELFT>::X->find(S)); // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - if (Config->Shared || Config->ExportDynamic) { - for (const std::pair<StringRef, Symbol *> &P : Symtab->getSymbols()) { - SymbolBody *B = P.second->Body; - if (B->getVisibility() == STV_DEFAULT) - MarkSymbol(B); - } - } + for (const Symbol *S : Symtab<ELFT>::X->getSymbols()) + if (S->includeInDynsym()) + MarkSymbol(S->body()); - // Preserve special sections. - for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles()) + // Preserve special sections and those which are specified in linker + // script KEEP command. + for (const std::unique_ptr<ObjectFile<ELFT>> &F : + Symtab<ELFT>::X->getObjectFiles()) for (InputSectionBase<ELFT> *Sec : F->getSections()) - if (Sec && Sec != &InputSection<ELFT>::Discarded && isReserved(Sec)) - Enqueue(Sec); + if (Sec && Sec != &InputSection<ELFT>::Discarded) { + // .eh_frame is always marked as live now, but also it can reference to + // sections that contain personality. We preserve all non-text sections + // referred by .eh_frame here. + if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec)) + scanEhFrameSection<ELFT>(*EH, Enqueue); + if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec)) + Enqueue({Sec, 0}); + } // Mark all reachable sections. while (!Q.empty()) - forEachSuccessor<ELFT>(Q.pop_back_val(), Enqueue); + forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue); } -template void elf2::markLive<ELF32LE>(SymbolTable<ELF32LE> *); -template void elf2::markLive<ELF32BE>(SymbolTable<ELF32BE> *); -template void elf2::markLive<ELF64LE>(SymbolTable<ELF64LE> *); -template void elf2::markLive<ELF64BE>(SymbolTable<ELF64BE> *); +template void elf::markLive<ELF32LE>(); +template void elf::markLive<ELF32BE>(); +template void elf::markLive<ELF64LE>(); +template void elf::markLive<ELF64BE>(); diff --git a/ELF/Options.td b/ELF/Options.td index 1b02c5c8b795..010f37687f03 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -1,165 +1,276 @@ include "llvm/Option/OptParser.td" -def Bsymbolic: Flag<["-"], "Bsymbolic">, - HelpText<"Bind defined symbols locally">; +// For options whose names are multiple letters, either one dash or +// two can precede the option name except those that start with 'o'. +class F<string name>: Flag<["--", "-"], name>; +class J<string name>: Joined<["--", "-"], name>; +class S<string name>: Separate<["--", "-"], name>; +class JS<string name>: JoinedOrSeparate<["--", "-"], name>; -def Bdynamic: Flag<["-"], "Bdynamic">, - HelpText<"Link against shared libraries">; +def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; -def Bstatic: Flag<["-"], "Bstatic">, - HelpText<"Do not link against shared libraries">; +def Bsymbolic_functions: F<"Bsymbolic-functions">, + HelpText<"Bind defined function symbols locally">; -def L : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, - HelpText<"Directory to search for libraries">; +def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; -def O : Joined<["-"], "O">, HelpText<"Optimize">; +def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; -def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, - HelpText<"Allow multiple definitions">; +def build_id: F<"build-id">, HelpText<"Generate build ID note">; + +def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; + +def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, + HelpText<"Add a directory to the library search path">; + +def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; -def allow_shlib_undefined : Flag<["--", "-"], "allow-shlib-undefined">; +def allow_multiple_definition: F<"allow-multiple-definition">, + HelpText<"Allow multiple definitions">; -def as_needed : Flag<["--"], "as-needed">; +def as_needed: F<"as-needed">, + HelpText<"Only set DT_NEEDED for shared libraries if used">; -def disable_new_dtags : Flag<["--"], "disable-new-dtags">, +def disable_new_dtags: F<"disable-new-dtags">, HelpText<"Disable new dynamic tags">; -def discard_all : Flag<["-"], "discard-all">, - HelpText<"Delete all local symbols">; +def discard_all: F<"discard-all">, HelpText<"Delete all local symbols">; -def discard_locals : Flag<["-"], "discard-locals">, +def discard_locals: F<"discard-locals">, HelpText<"Delete temporary local symbols">; -def discard_none : Flag<["-"], "discard-none">, +def discard_none: F<"discard-none">, HelpText<"Keep all symbols in the symbol table">; -def dynamic_linker : Separate<["--", "-"], "dynamic-linker">, +def dynamic_linker: S<"dynamic-linker">, HelpText<"Which dynamic linker to use">; -def enable_new_dtags : Flag<["--"], "enable-new-dtags">, +def dynamic_list: S<"dynamic-list">, + HelpText<"Read a list of dynamic symbols">; + +def eh_frame_hdr: F<"eh-frame-hdr">, + HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">; + +def enable_new_dtags: F<"enable-new-dtags">, HelpText<"Enable new dynamic tags">; -def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">, +def end_lib: F<"end-lib">, + HelpText<"End a grouping of objects that should be treated as if they were together in an archive">; + +def entry: S<"entry">, MetaVarName<"<entry>">, HelpText<"Name of entry point symbol">; -def export_dynamic : Flag<["--", "-"], "export-dynamic">, +def export_dynamic: F<"export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; -def fini : Separate<["-"], "fini">, MetaVarName<"<symbol>">, +def export_dynamic_symbol: S<"export-dynamic-symbol">, + HelpText<"Put a symbol in the dynamic symbol table">; + +def fatal_warnings: F<"fatal-warnings">, + HelpText<"Treat warnings as errors">; + +def fini: S<"fini">, MetaVarName<"<symbol>">, HelpText<"Specify a finalizer function">; -def hash_style : Separate<["--", "-"], "hash-style">, +def hash_style: S<"hash-style">, HelpText<"Specify hash style (sysv, gnu or both)">; -def gc_sections : Flag<["--"], "gc-sections">, +def help: F<"help">, HelpText<"Print option help">; + +def icf: F<"icf=all">, HelpText<"Enable identical code folding">; + +def image_base : J<"image-base=">, HelpText<"Set the base address">; + +def gc_sections: F<"gc-sections">, HelpText<"Enable garbage collection of unused sections">; -def init : Separate<["-"], "init">, MetaVarName<"<symbol>">, +def init: S<"init">, MetaVarName<"<symbol>">, HelpText<"Specify an initializer function">; -def l : JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, +def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, HelpText<"Root name of library to use">; -def m : JoinedOrSeparate<["-"], "m">, - HelpText<"Set target emulation">; +def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, + HelpText<"Optimization level for LTO">; + +def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; + +def no_as_needed: F<"no-as-needed">, + HelpText<"Always DT_NEEDED for shared libraries">; -def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">; +def no_demangle: F<"no-demangle">, + HelpText<"Do not demangle symbol names">; -def no_as_needed : Flag<["--"], "no-as-needed">; +def no_gnu_unique: F<"no-gnu-unique">, + HelpText<"Disable STB_GNU_UNIQUE symbol binding">; -def no_whole_archive : Flag<["--", "-"], "no-whole-archive">, +def no_whole_archive: F<"no-whole-archive">, HelpText<"Restores the default behavior of loading archive members">; -def noinhibit_exec : Flag<["--"], "noinhibit-exec">, +def noinhibit_exec: F<"noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def no_undefined : Flag<["--"], "no-undefined">, +def no_undefined: F<"no-undefined">, HelpText<"Report unresolved symbols even if the linker is creating a shared library">; -def o : Separate<["-"], "o">, MetaVarName<"<path>">, +def no_undefined_version: F<"no-undefined-version">, + HelpText<"Report version scripts that refer undefined symbols">; + +def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; -def print_gc_sections: Flag<["--"], "print-gc-sections">, +def pie: F<"pie">, HelpText<"Create a position independent executable">; + +def print_gc_sections: F<"print-gc-sections">, HelpText<"List removed unused sections">; -def rpath : Separate<["-"], "rpath">, - HelpText<"Add a DT_RUNPATH to the output">; +def reproduce: S<"reproduce">, + HelpText<"Dump linker invocation and input files for debugging">; + +def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; + +def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; + +def script: S<"script">, HelpText<"Read linker script">; + +def shared: F<"shared">, HelpText<"Build a shared object">; + +def soname: J<"soname=">, HelpText<"Set DT_SONAME">; + +def start_lib: F<"start-lib">, + HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; -def relocatable : Flag<["--"], "relocatable">; +def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; -def script : Separate<["--"], "script">, HelpText<"Read linker script">; +def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; -def shared : Flag<["-"], "shared">, - HelpText<"Build a shared object">; +def sysroot: J<"sysroot=">, HelpText<"Set the system root">; -def soname : Joined<["-"], "soname=">, - HelpText<"Set DT_SONAME">; +def threads: F<"threads">, HelpText<"Enable use of threads">; -def strip_all : Flag<["--"], "strip-all">, - HelpText<"Strip all symbols">; +def trace: F<"trace">, HelpText<"Print the names of the input files">; -def sysroot : Joined<["--"], "sysroot=">, - HelpText<"Set the system root">; +def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">; -def undefined : Joined<["--"], "undefined=">, +def undefined: J<"undefined=">, HelpText<"Force undefined symbol during linking">; -def verbose : Flag<["--"], "verbose">; +def unresolved_symbols: J<"unresolved-symbols=">, + HelpText<"Determine how to handle unresolved symbols">; -def whole_archive : Flag<["--", "-"], "whole-archive">, +def rsp_quoting: J<"rsp-quoting=">, + HelpText<"Quoting style for response files. Values supported: windows|posix">; + +def verbose: F<"verbose">, HelpText<"Verbose mode">; + +def version: F<"version">, HelpText<"Display the version number">; + +def version_script: S<"version-script">, + HelpText<"Read a version script">; + +def warn_common: F<"warn-common">, + HelpText<"Warn about duplicate common symbols">; + +def whole_archive: F<"whole-archive">, HelpText<"Force load of all members in a static library">; -def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"<symbol>">, +def wrap: S<"wrap">, MetaVarName<"<symbol>">, HelpText<"Use wrapper functions for symbol">; -def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, +def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; // Aliases -def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias<Bdynamic>; -def alias_Bdynamic_dy: Flag<["-"], "dy">, Alias<Bdynamic>; -def alias_Bstatic_dn: Flag<["-"], "dn">, Alias<Bstatic>; -def alias_Bstatic_non_shared: Flag<["-"], "non_shared">, Alias<Bstatic>; -def alias_Bstatic_static: Flag<["-"], "static">, Alias<Bstatic>; -def alias_L__library_path : Joined<["--"], "library-path=">, Alias<L>; +def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>; +def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>; +def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>; +def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>; +def alias_Bstatic_static: F<"static">, Alias<Bstatic>; +def alias_L__library_path: J<"library-path=">, Alias<L>; def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; -def alias_entry_e : Separate<["-"], "e">, Alias<entry>; +def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>; +def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; +def alias_entry_entry: J<"entry=">, Alias<entry>; def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; -def alias_fini_fini : Joined<["-"], "fini=">, Alias<fini>; -def alias_hash_style_hash_style : Joined<["--", "-"], "hash-style=">, Alias<hash_style>; -def alias_init_init : Joined<["-"], "init=">, Alias<init>; -def alias_l__library : Joined<["--"], "library=">, Alias<l>; -def alias_o_output : Joined<["--"], "output=">, Alias<o>; -def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>; -def alias_relocatable_r : Flag<["-"], "r">, Alias<relocatable>; -def alias_shared_Bshareable : Flag<["-"], "Bshareable">, Alias<shared>; -def alias_soname_h : Separate<["-"], "h">, Alias<soname>; -def alias_soname_soname : Separate<["-"], "soname">, Alias<soname>; -def alias_script_T : Separate<["-"], "T">, Alias<script>; +def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, + Alias<export_dynamic_symbol>; +def alias_fini_fini: J<"fini=">, Alias<fini>; +def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>; +def alias_init_init: J<"init=">, Alias<init>; +def alias_l__library: J<"library=">, Alias<l>; +def alias_o_output: Joined<["--"], "output=">, Alias<o>; +def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>; +def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; +def alias_rpath_R: Joined<["-"], "R">, Alias<rpath>; +def alias_rpath_rpath: J<"rpath=">, Alias<rpath>; +def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>; +def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>; +def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>; +def alias_soname_soname: S<"soname">, Alias<soname>; def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; -def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>; -def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias<wrap>; +def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>; +def alias_trace: Flag<["-"], "t">, Alias<trace>; +def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>; +def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; +def alias_version_V: Flag<["-"], "V">, Alias<version>; +def alias_version_v: Flag<["-"], "v">, Alias<version>; +def alias_wrap_wrap: J<"wrap=">, Alias<wrap>; // Our symbol resolution algorithm handles symbols in archive files differently // than traditional linkers, so we don't need --start-group and --end-group. // These options are recongized for compatibility but ignored. -def end_group : Flag<["--"], "end-group">; +def end_group: F<"end-group">; def end_group_paren: Flag<["-"], ")">; -def start_group : Flag<["--"], "start-group">; +def start_group: F<"start-group">; def start_group_paren: Flag<["-"], "(">; +// Ignore LTO plugin-related options. +// clang -flto passes -plugin and -plugin-opt to the linker. This is required +// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't +// rely on a plugin. Instead of detecting which linker is used on clang side we +// just ignore the option on lld side as it's easier. In fact, the linker could +// be called 'ld' and understanding which linker is used would require parsing of +// --version output. +def plugin: S<"plugin">; +def plugin_eq: J<"plugin=">; +def plugin_opt: S<"plugin-opt">; +def plugin_opt_eq: J<"plugin-opt=">; + // Options listed below are silently ignored for now for compatibility. -def build_id : Flag<["--"], "build-id">; -def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">; -def fatal_warnings : Flag<["--"], "fatal-warnings">; -def no_add_needed : Flag<["--"], "no-add-needed">; -def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">; -def no_warn_mismatch : Flag<["--"], "no-warn-mismatch">; -def version_script : Separate<["--"], "version-script">; -def warn_common : Flag<["--"], "warn-common">; -def warn_shared_textrel : Flag<["--"], "warn-shared-textrel">; -def G : Separate<["-"], "G">; +def allow_shlib_undefined: F<"allow-shlib-undefined">; +def define_common: F<"define-common">; +def demangle: F<"demangle">; +def detect_odr_violations: F<"detect-odr-violations">; +def no_add_needed: F<"no-add-needed">; +def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; +def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">, + Alias<no_add_needed>; +def no_dynamic_linker: F<"no-dynamic-linker">; +def no_fatal_warnings: F<"no-fatal-warnings">; +def no_mmap_output_file: F<"no-mmap-output-file">; +def no_warn_common: F<"no-warn-common">; +def no_warn_mismatch: F<"no-warn-mismatch">; +def rpath_link: S<"rpath-link">; +def rpath_link_eq: J<"rpath-link=">; +def sort_common: F<"sort-common">; +def warn_execstack: F<"warn-execstack">; +def warn_shared_textrel: F<"warn-shared-textrel">; +def G: Separate<["-"], "G">; // Aliases for ignored options -def alias_version_script_version_script : Joined<["--"], "version-script=">, Alias<version_script>; +def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; +def alias_define_common_dc: F<"dc">, Alias<define_common>; +def alias_define_common_dp: F<"dp">, Alias<define_common>; +def alias_version_script_version_script: J<"version-script=">, + Alias<version_script>; + +// LTO-related options. +def lto_jobs: J<"lto-jobs=">, HelpText<"Number of threads to run codegen">; +def lto_aa_pipeline: J<"lto-aa-pipeline=">, + HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; +def lto_newpm_passes: J<"lto-newpm-passes=">, + HelpText<"Passes to run during LTO">; +def disable_verify: F<"disable-verify">; +def mllvm: S<"mllvm">; +def save_temps: F<"save-temps">; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 2aa814524d6b..50b94015f229 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -9,19 +9,26 @@ #include "OutputSections.h" #include "Config.h" +#include "EhFrame.h" +#include "LinkerScript.h" +#include "Strings.h" #include "SymbolTable.h" #include "Target.h" +#include "lld/Core/Parallel.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/SHA1.h" +#include <map> using namespace llvm; +using namespace llvm::dwarf; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; -using namespace lld::elf2; - -bool elf2::HasGotOffRel = false; +using namespace lld::elf; template <class ELFT> OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type, @@ -30,39 +37,39 @@ OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type, memset(&Header, 0, sizeof(Elf_Shdr)); Header.sh_type = Type; Header.sh_flags = Flags; + Header.sh_addralign = 1; +} + +template <class ELFT> +void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *Shdr) { + *Shdr = Header; } template <class ELFT> GotPltSection<ELFT>::GotPltSection() : OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { - this->Header.sh_addralign = sizeof(uintX_t); + this->Header.sh_addralign = Target->GotPltEntrySize; } -template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody *Sym) { - Sym->GotPltIndex = Target->getGotPltHeaderEntriesNum() + Entries.size(); - Entries.push_back(Sym); +template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) { + Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); + Entries.push_back(&Sym); } template <class ELFT> bool GotPltSection<ELFT>::empty() const { return Entries.empty(); } -template <class ELFT> -typename GotPltSection<ELFT>::uintX_t -GotPltSection<ELFT>::getEntryAddr(const SymbolBody &B) const { - return this->getVA() + B.GotPltIndex * sizeof(uintX_t); -} - template <class ELFT> void GotPltSection<ELFT>::finalize() { - this->Header.sh_size = - (Target->getGotPltHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); + this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) * + Target->GotPltEntrySize; } template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) { - Target->writeGotPltHeaderEntries(Buf); - Buf += Target->getGotPltHeaderEntriesNum() * sizeof(uintX_t); + Target->writeGotPltHeader(Buf); + Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; for (const SymbolBody *B : Entries) { - Target->writeGotPltEntry(Buf, Out<ELFT>::Plt->getEntryAddr(*B)); + Target->writeGotPlt(Buf, *B); Buf += sizeof(uintX_t); } } @@ -72,37 +79,135 @@ GotSection<ELFT>::GotSection() : OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { if (Config->EMachine == EM_MIPS) this->Header.sh_flags |= SHF_MIPS_GPREL; - this->Header.sh_addralign = sizeof(uintX_t); + this->Header.sh_addralign = Target->GotEntrySize; +} + +template <class ELFT> +void GotSection<ELFT>::addEntry(SymbolBody &Sym) { + Sym.GotIndex = Entries.size(); + Entries.push_back(&Sym); } -template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) { - Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size(); - Entries.push_back(Sym); +template <class ELFT> +void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend, + RelExpr Expr) { + // For "true" local symbols which can be referenced from the same module + // only compiler creates two instructions for address loading: + // + // lw $8, 0($gp) # R_MIPS_GOT16 + // addi $8, $8, 0 # R_MIPS_LO16 + // + // The first instruction loads high 16 bits of the symbol address while + // the second adds an offset. That allows to reduce number of required + // GOT entries because only one global offset table entry is necessary + // for every 64 KBytes of local data. So for local symbols we need to + // allocate number of GOT entries to hold all required "page" addresses. + // + // All global symbols (hidden and regular) considered by compiler uniformly. + // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation + // to load address of the symbol. So for each such symbol we need to + // allocate dedicated GOT entry to store its address. + // + // If a symbol is preemptible we need help of dynamic linker to get its + // final address. The corresponding GOT entries are allocated in the + // "global" part of GOT. Entries for non preemptible global symbol allocated + // in the "local" part of GOT. + // + // See "Global Offset Table" in Chapter 5: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Expr == R_MIPS_GOT_LOCAL_PAGE) { + // At this point we do not know final symbol value so to reduce number + // of allocated GOT entries do the following trick. Save all output + // sections referenced by GOT relocations. Then later in the `finalize` + // method calculate number of "pages" required to cover all saved output + // section and allocate appropriate number of GOT entries. + auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec; + MipsOutSections.insert(OutSec); + return; + } + if (Sym.isTls()) { + // GOT entries created for MIPS TLS relocations behave like + // almost GOT entries from other ABIs. They go to the end + // of the global offset table. + Sym.GotIndex = Entries.size(); + Entries.push_back(&Sym); + return; + } + auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) { + if (S.isInGot() && !A) + return; + size_t NewIndex = Items.size(); + if (!MipsGotMap.insert({{&S, A}, NewIndex}).second) + return; + Items.emplace_back(&S, A); + if (!A) + S.GotIndex = NewIndex; + }; + if (Sym.isPreemptible()) { + // Ignore addends for preemptible symbols. They got single GOT entry anyway. + AddEntry(Sym, 0, MipsGlobal); + Sym.IsInGlobalMipsGot = true; + } else + AddEntry(Sym, Addend, MipsLocal); } -template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody *Sym) { - if (Sym->hasGlobalDynIndex()) +template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) { + if (Sym.GlobalDynIndex != -1U) return false; - Sym->GlobalDynIndex = Target->getGotHeaderEntriesNum() + Entries.size(); + Sym.GlobalDynIndex = Entries.size(); // Global Dynamic TLS entries take two GOT slots. - Entries.push_back(Sym); Entries.push_back(nullptr); + Entries.push_back(&Sym); return true; } -template <class ELFT> bool GotSection<ELFT>::addCurrentModuleTlsIndex() { - if (LocalTlsIndexOff != uint32_t(-1)) +// Reserves TLS entries for a TLS module ID and a TLS block offset. +// In total it takes two GOT slots. +template <class ELFT> bool GotSection<ELFT>::addTlsIndex() { + if (TlsIndexOff != uint32_t(-1)) return false; + TlsIndexOff = Entries.size() * sizeof(uintX_t); Entries.push_back(nullptr); Entries.push_back(nullptr); - LocalTlsIndexOff = (Entries.size() - 2) * sizeof(uintX_t); return true; } template <class ELFT> typename GotSection<ELFT>::uintX_t -GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const { - return this->getVA() + B.GotIndex * sizeof(uintX_t); +GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) { + // Initialize the entry by the %hi(EntryValue) expression + // but without right-shifting. + EntryValue = (EntryValue + 0x8000) & ~0xffff; + // Take into account MIPS GOT header. + // See comment in the GotSection::writeTo. + size_t NewIndex = MipsLocalGotPos.size() + 2; + auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex)); + assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries); + return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset; +} + +template <class ELFT> +typename GotSection<ELFT>::uintX_t +GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const { + uintX_t Off = MipsPageEntries; + if (B.isTls()) + Off += MipsLocal.size() + MipsGlobal.size() + B.GotIndex; + else if (B.IsInGlobalMipsGot) + Off += MipsLocal.size() + B.GotIndex; + else if (B.isInGot()) + Off += B.GotIndex; + else { + auto It = MipsGotMap.find({&B, Addend}); + assert(It != MipsGotMap.end()); + Off += It->second; + } + return Off * sizeof(uintX_t) - MipsGPOffset; +} + +template <class ELFT> +typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() { + return (MipsPageEntries + MipsLocal.size() + MipsGlobal.size()) * + sizeof(uintX_t); } template <class ELFT> @@ -112,37 +217,85 @@ GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const { } template <class ELFT> +typename GotSection<ELFT>::uintX_t +GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const { + return B.GlobalDynIndex * sizeof(uintX_t); +} + +template <class ELFT> const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const { - return Entries.empty() ? nullptr : Entries.front(); + return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; } template <class ELFT> unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const { - // TODO: Update when the support of GOT entries for local symbols is added. - return Target->getGotHeaderEntriesNum(); + return MipsPageEntries + MipsLocal.size(); } template <class ELFT> void GotSection<ELFT>::finalize() { - this->Header.sh_size = - (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); + size_t EntriesNum = Entries.size(); + if (Config->EMachine == EM_MIPS) { + // Take into account MIPS GOT header. + // See comment in the GotSection::writeTo. + MipsPageEntries += 2; + for (const OutputSectionBase<ELFT> *OutSec : MipsOutSections) { + // Calculate an upper bound of MIPS GOT entries required to store page + // addresses of local symbols. We assume the worst case - each 64kb + // page of the output section has at least one GOT relocation against it. + // Add 0x8000 to the section's size because the page address stored + // in the GOT entry is calculated as (value + 0x8000) & ~0xffff. + MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; + } + EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size(); + } + this->Header.sh_size = EntriesNum * sizeof(uintX_t); +} + +template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) { + // Set the MSB of the second GOT slot. This is not required by any + // MIPS ABI documentation, though. + // + // There is a comment in glibc saying that "The MSB of got[1] of a + // gnu object is set to identify gnu objects," and in GNU gold it + // says "the second entry will be used by some runtime loaders". + // But how this field is being used is unclear. + // + // We are not really willing to mimic other linkers behaviors + // without understanding why they do that, but because all files + // generated by GNU tools have this special GOT value, and because + // we've been doing this for years, it is probably a safe bet to + // keep doing this for now. We really need to revisit this to see + // if we had to do this. + auto *P = reinterpret_cast<typename ELFT::Off *>(Buf); + P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); + // Write 'page address' entries to the local part of the GOT. + for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) { + uint8_t *Entry = Buf + L.second * sizeof(uintX_t); + write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first); + } + Buf += MipsPageEntries * sizeof(uintX_t); + auto AddEntry = [&](const MipsGotEntry &SA) { + uint8_t *Entry = Buf; + Buf += sizeof(uintX_t); + const SymbolBody* Body = SA.first; + uintX_t VA = Body->template getVA<ELFT>(SA.second); + write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA); + }; + std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry); + std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry); } template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { - Target->writeGotHeaderEntries(Buf); - Buf += Target->getGotHeaderEntriesNum() * sizeof(uintX_t); + if (Config->EMachine == EM_MIPS) + writeMipsGot(Buf); for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); if (!B) continue; - // MIPS has special rules to fill up GOT entries. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - // As the first approach, we can just store addresses for all symbols. - if (Config->EMachine != EM_MIPS && canBePreempted(B, false)) + if (B->isPreemptible()) continue; // The dynamic linker will take care of it. - uintX_t VA = getSymVA<ELFT>(*B); + uintX_t VA = B->getVA<ELFT>(); write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA); } } @@ -154,165 +307,81 @@ PltSection<ELFT>::PltSection() } template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) { - size_t Off = 0; - bool LazyReloc = Target->supportsLazyRelocations(); - if (LazyReloc) { - // First write PLT[0] entry which is special. - Target->writePltZeroEntry(Buf, Out<ELFT>::GotPlt->getVA(), this->getVA()); - Off += Target->getPltZeroEntrySize(); - } + // At beginning of PLT, we have code to call the dynamic linker + // to resolve dynsyms at runtime. Write such code. + Target->writePltHeader(Buf); + size_t Off = Target->PltHeaderSize; + for (auto &I : Entries) { - const SymbolBody *E = I.first; + const SymbolBody *B = I.first; unsigned RelOff = I.second; - uint64_t GotVA = - LazyReloc ? Out<ELFT>::GotPlt->getVA() : Out<ELFT>::Got->getVA(); - uint64_t GotE = LazyReloc ? Out<ELFT>::GotPlt->getEntryAddr(*E) - : Out<ELFT>::Got->getEntryAddr(*E); + uint64_t Got = B->getGotPltVA<ELFT>(); uint64_t Plt = this->getVA() + Off; - Target->writePltEntry(Buf + Off, GotVA, GotE, Plt, E->PltIndex, RelOff); - Off += Target->getPltEntrySize(); + Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); + Off += Target->PltEntrySize; } } -template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody *Sym) { - Sym->PltIndex = Entries.size(); - unsigned RelOff = Target->supportsLazyRelocations() - ? Out<ELFT>::RelaPlt->getRelocOffset() - : Out<ELFT>::RelaDyn->getRelocOffset(); - Entries.push_back(std::make_pair(Sym, RelOff)); -} - -template <class ELFT> -typename PltSection<ELFT>::uintX_t -PltSection<ELFT>::getEntryAddr(const SymbolBody &B) const { - return this->getVA() + Target->getPltZeroEntrySize() + - B.PltIndex * Target->getPltEntrySize(); +template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) { + Sym.PltIndex = Entries.size(); + unsigned RelOff = Out<ELFT>::RelaPlt->getRelocOffset(); + Entries.push_back(std::make_pair(&Sym, RelOff)); } template <class ELFT> void PltSection<ELFT>::finalize() { - this->Header.sh_size = Target->getPltZeroEntrySize() + - Entries.size() * Target->getPltEntrySize(); + this->Header.sh_size = + Target->PltHeaderSize + Entries.size() * Target->PltEntrySize; } template <class ELFT> -RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela) - : OutputSectionBase<ELFT>(Name, IsRela ? SHT_RELA : SHT_REL, SHF_ALLOC), - IsRela(IsRela) { - this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; +RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) + : OutputSectionBase<ELFT>(Name, Config->Rela ? SHT_RELA : SHT_REL, + SHF_ALLOC), + Sort(Sort) { + this->Header.sh_entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + this->Header.sh_addralign = sizeof(uintX_t); } -// Applies corresponding symbol and type for dynamic tls relocation. -// Returns true if relocation was handled. template <class ELFT> -bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body, - uint32_t Type, Elf_Rel *P, - Elf_Rel *N) { - if (Target->isTlsLocalDynamicReloc(Type)) { - P->setSymbolAndType(0, Target->getTlsModuleIndexReloc(), Config->Mips64EL); - P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA(); - return true; - } - - if (!Body || !Target->isTlsGlobalDynamicReloc(Type)) - return false; - - if (Target->isTlsOptimized(Type, Body)) { - P->setSymbolAndType(Body->DynamicSymbolTableIndex, - Target->getTlsGotReloc(), Config->Mips64EL); - P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body); - return true; - } +void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) { + Relocs.push_back(Reloc); +} - P->setSymbolAndType(Body->DynamicSymbolTableIndex, - Target->getTlsModuleIndexReloc(), Config->Mips64EL); - P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body); - N->setSymbolAndType(Body->DynamicSymbolTableIndex, - Target->getTlsOffsetReloc(), Config->Mips64EL); - N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t); - return true; +template <class ELFT, class RelTy> +static bool compRelocations(const RelTy &A, const RelTy &B) { + return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL); } template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { + uint8_t *BufBegin = Buf; for (const DynamicReloc<ELFT> &Rel : Relocs) { - auto *P = reinterpret_cast<Elf_Rel *>(Buf); - Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - - // Skip placeholder for global dynamic TLS relocation pair. It was already - // handled by the previous relocation. - if (!Rel.C) - continue; + auto *P = reinterpret_cast<Elf_Rela *>(Buf); + Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - InputSectionBase<ELFT> &C = *Rel.C; - const Elf_Rel &RI = *Rel.RI; - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - const ObjectFile<ELFT> &File = *C.getFile(); - SymbolBody *Body = File.getSymbolBody(SymIndex); - if (Body) - Body = Body->repl(); - - uint32_t Type = RI.getType(Config->Mips64EL); - if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf))) - continue; - bool NeedsCopy = Body && Target->needsCopyRel(Type, *Body); - bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body); - bool CBP = canBePreempted(Body, NeedsGot); - bool LazyReloc = Body && Target->supportsLazyRelocations() && - Target->relocNeedsPlt(Type, *Body); - bool IsDynRelative = Type == Target->getRelativeReloc(); - - unsigned Sym = CBP ? Body->DynamicSymbolTableIndex : 0; - unsigned Reloc; - if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) - Reloc = Target->getIRelativeReloc(); - else if (!CBP || IsDynRelative) - Reloc = Target->getRelativeReloc(); - else if (LazyReloc) - Reloc = Target->getPltReloc(); - else if (NeedsGot) - Reloc = Body->isTls() ? Target->getTlsGotReloc() : Target->getGotReloc(); - else if (NeedsCopy) - Reloc = Target->getCopyReloc(); - else - Reloc = Target->getDynReloc(Type); - P->setSymbolAndType(Sym, Reloc, Config->Mips64EL); - - if (LazyReloc) - P->r_offset = Out<ELFT>::GotPlt->getEntryAddr(*Body); - else if (NeedsGot) - P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body); - else if (NeedsCopy) - P->r_offset = Out<ELFT>::Bss->getVA() + - cast<SharedSymbol<ELFT>>(Body)->OffsetInBss; - else - P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA(); - - uintX_t OrigAddend = 0; - if (IsRela && !NeedsGot) - OrigAddend = static_cast<const Elf_Rela &>(RI).r_addend; + if (Config->Rela) + P->r_addend = Rel.getAddend(); + P->r_offset = Rel.getOffset(); + if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got) + // Dynamic relocation against MIPS GOT section make deal TLS entries + // allocated in the end of the GOT. We need to adjust the offset to take + // in account 'local' and 'global' GOT entries. + P->r_offset += Out<ELFT>::Got->getMipsTlsOffset(); + P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); + } - uintX_t Addend; - if (NeedsCopy) - Addend = 0; - else if (CBP || IsDynRelative) - Addend = OrigAddend; - else if (Body) - Addend = getSymVA<ELFT>(*Body) + OrigAddend; - else if (IsRela) - Addend = - getLocalRelTarget(File, static_cast<const Elf_Rela &>(RI), - getAddend<ELFT>(static_cast<const Elf_Rela &>(RI))); + if (Sort) { + if (Config->Rela) + std::stable_sort((Elf_Rela *)BufBegin, + (Elf_Rela *)BufBegin + Relocs.size(), + compRelocations<ELFT, Elf_Rela>); else - Addend = getLocalRelTarget(File, RI, 0); - - if (IsRela) - static_cast<Elf_Rela *>(P)->r_addend = Addend; + std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), + compRelocations<ELFT, Elf_Rel>); } } template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { - const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - return EntrySize * Relocs.size(); + return this->Header.sh_entsize * Relocs.size(); } template <class ELFT> void RelocationSection<ELFT>::finalize() { @@ -325,17 +394,11 @@ template <class ELFT> InterpSection<ELFT>::InterpSection() : OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) { this->Header.sh_size = Config->DynamicLinker.size() + 1; - this->Header.sh_addralign = 1; -} - -template <class ELFT> -void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) { - Header.sh_name = Out<ELFT>::ShStrTab->addString(Name); - *SHdr = Header; } template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) { - memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size()); + StringRef S = Config->DynamicLinker; + memcpy(Buf, S.data(), S.size()); } template <class ELFT> @@ -360,7 +423,7 @@ static uint32_t hashSysv(StringRef Name) { template <class ELFT> void HashTableSection<ELFT>::finalize() { this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex; - unsigned NumEntries = 2; // nbucket and nchain. + unsigned NumEntries = 2; // nbucket and nchain. NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. @@ -379,9 +442,11 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; - for (SymbolBody *Body : Out<ELFT>::DynSymTab->getSymbols()) { + for (const std::pair<SymbolBody *, unsigned> &P : + Out<ELFT>::DynSymTab->getSymbols()) { + SymbolBody *Body = P.first; StringRef Name = Body->getName(); - unsigned I = Body->DynamicSymbolTableIndex; + unsigned I = Body->DynsymIndex; uint32_t Hash = hashSysv(Name) % NumSymbols; Chains[I] = Buckets[Hash]; Buckets[Hash] = I; @@ -399,7 +464,7 @@ template <class ELFT> GnuHashTableSection<ELFT>::GnuHashTableSection() : OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) { this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4; - this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; + this->Header.sh_addralign = sizeof(uintX_t); } template <class ELFT> @@ -437,7 +502,7 @@ unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) { } template <class ELFT> void GnuHashTableSection<ELFT>::finalize() { - unsigned NumHashed = HashedSymbols.size(); + unsigned NumHashed = Symbols.size(); NBuckets = calcNBuckets(NumHashed); MaskWords = calcMaskWords(NumHashed); // Second hash shift estimation: just predefined values. @@ -452,7 +517,7 @@ template <class ELFT> void GnuHashTableSection<ELFT>::finalize() { template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) { writeHeader(Buf); - if (HashedSymbols.empty()) + if (Symbols.empty()) return; writeBloomFilter(Buf); writeHashTable(Buf); @@ -462,7 +527,7 @@ template <class ELFT> void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) { auto *P = reinterpret_cast<Elf_Word *>(Buf); *P++ = NBuckets; - *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size(); + *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(); *P++ = MaskWords; *P++ = Shift2; Buf = reinterpret_cast<uint8_t *>(P); @@ -473,10 +538,10 @@ void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) { unsigned C = sizeof(Elf_Off) * 8; auto *Masks = reinterpret_cast<Elf_Off *>(Buf); - for (const HashedSymbolData &Item : HashedSymbols) { - size_t Pos = (Item.Hash / C) & (MaskWords - 1); - uintX_t V = (uintX_t(1) << (Item.Hash % C)) | - (uintX_t(1) << ((Item.Hash >> Shift2) % C)); + for (const SymbolData &Sym : Symbols) { + size_t Pos = (Sym.Hash / C) & (MaskWords - 1); + uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | + (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); Masks[Pos] |= V; } Buf += sizeof(Elf_Off) * MaskWords; @@ -489,58 +554,64 @@ void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) { int PrevBucket = -1; int I = 0; - for (const HashedSymbolData &Item : HashedSymbols) { - int Bucket = Item.Hash % NBuckets; + for (const SymbolData &Sym : Symbols) { + int Bucket = Sym.Hash % NBuckets; assert(PrevBucket <= Bucket); if (Bucket != PrevBucket) { - Buckets[Bucket] = Item.Body->DynamicSymbolTableIndex; + Buckets[Bucket] = Sym.Body->DynsymIndex; PrevBucket = Bucket; if (I > 0) Values[I - 1] |= 1; } - Values[I] = Item.Hash & ~1; + Values[I] = Sym.Hash & ~1; ++I; } if (I > 0) Values[I - 1] |= 1; } -static bool includeInGnuHashTable(SymbolBody *B) { - // Assume that includeInDynamicSymtab() is already checked. - return !B->isUndefined(); -} - +// Add symbols to this symbol hash table. Note that this function +// destructively sort a given vector -- which is needed because +// GNU-style hash table places some sorting requirements. template <class ELFT> -void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolBody *> &Symbols) { - std::vector<SymbolBody *> NotHashed; - NotHashed.reserve(Symbols.size()); - HashedSymbols.reserve(Symbols.size()); - for (SymbolBody *B : Symbols) { - if (includeInGnuHashTable(B)) - HashedSymbols.push_back(HashedSymbolData{B, hashGnu(B->getName())}); - else - NotHashed.push_back(B); - } - if (HashedSymbols.empty()) +void GnuHashTableSection<ELFT>::addSymbols( + std::vector<std::pair<SymbolBody *, size_t>> &V) { + // Ideally this will just be 'auto' but GCC 6.1 is not able + // to deduce it correctly. + std::vector<std::pair<SymbolBody *, size_t>>::iterator Mid = + std::stable_partition(V.begin(), V.end(), + [](std::pair<SymbolBody *, size_t> &P) { + return P.first->isUndefined(); + }); + if (Mid == V.end()) return; + for (auto I = Mid, E = V.end(); I != E; ++I) { + SymbolBody *B = I->first; + size_t StrOff = I->second; + Symbols.push_back({B, StrOff, hashGnu(B->getName())}); + } - unsigned NBuckets = calcNBuckets(HashedSymbols.size()); - std::stable_sort(HashedSymbols.begin(), HashedSymbols.end(), - [&](const HashedSymbolData &L, const HashedSymbolData &R) { + unsigned NBuckets = calcNBuckets(Symbols.size()); + std::stable_sort(Symbols.begin(), Symbols.end(), + [&](const SymbolData &L, const SymbolData &R) { return L.Hash % NBuckets < R.Hash % NBuckets; }); - Symbols = std::move(NotHashed); - for (const HashedSymbolData &Item : HashedSymbols) - Symbols.push_back(Item.Body); + V.erase(Mid, V.end()); + for (const SymbolData &Sym : Symbols) + V.push_back({Sym.Body, Sym.STName}); } +// Returns the number of version definition entries. Because the first entry +// is for the version definition itself, it is the number of versioned symbols +// plus one. Note that we don't support multiple versions yet. +static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } + template <class ELFT> -DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab) - : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE), - SymTab(SymTab) { +DynamicSection<ELFT>::DynamicSection() + : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) { Elf_Shdr &Header = this->Header; - Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; + Header.sh_addralign = sizeof(uintX_t); Header.sh_entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS. @@ -557,61 +628,66 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { Elf_Shdr &Header = this->Header; Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex; - unsigned NumEntries = 0; + auto Add = [=](Entry E) { Entries.push_back(E); }; + + // Add strings. We know that these are the last strings to be added to + // DynStrTab and doing this here allows this function to set DT_STRSZ. + if (!Config->RPath.empty()) + Add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, + Out<ELFT>::DynStrTab->addString(Config->RPath)}); + for (const std::unique_ptr<SharedFile<ELFT>> &F : + Symtab<ELFT>::X->getSharedFiles()) + if (F->isNeeded()) + Add({DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())}); + if (!Config->SoName.empty()) + Add({DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)}); + + Out<ELFT>::DynStrTab->finalize(); + if (Out<ELFT>::RelaDyn->hasRelocs()) { - ++NumEntries; // DT_RELA / DT_REL - ++NumEntries; // DT_RELASZ / DT_RELSZ - ++NumEntries; // DT_RELAENT / DT_RELENT + bool IsRela = Config->Rela; + Add({IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn}); + Add({IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()}); + Add({IsRela ? DT_RELAENT : DT_RELENT, + uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); } if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) { - ++NumEntries; // DT_JMPREL - ++NumEntries; // DT_PLTRELSZ - ++NumEntries; // DT_PLTGOT / DT_MIPS_PLTGOT - ++NumEntries; // DT_PLTREL + Add({DT_JMPREL, Out<ELFT>::RelaPlt}); + Add({DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()}); + Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, + Out<ELFT>::GotPlt}); + Add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); } - ++NumEntries; // DT_SYMTAB - ++NumEntries; // DT_SYMENT - ++NumEntries; // DT_STRTAB - ++NumEntries; // DT_STRSZ + Add({DT_SYMTAB, Out<ELFT>::DynSymTab}); + Add({DT_SYMENT, sizeof(Elf_Sym)}); + Add({DT_STRTAB, Out<ELFT>::DynStrTab}); + Add({DT_STRSZ, Out<ELFT>::DynStrTab->getSize()}); if (Out<ELFT>::GnuHashTab) - ++NumEntries; // DT_GNU_HASH + Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab}); if (Out<ELFT>::HashTab) - ++NumEntries; // DT_HASH + Add({DT_HASH, Out<ELFT>::HashTab}); - if (!Config->RPath.empty()) { - ++NumEntries; // DT_RUNPATH / DT_RPATH - Out<ELFT>::DynStrTab->reserve(Config->RPath); + if (PreInitArraySec) { + Add({DT_PREINIT_ARRAY, PreInitArraySec}); + Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()}); } - - if (!Config->SoName.empty()) { - ++NumEntries; // DT_SONAME - Out<ELFT>::DynStrTab->reserve(Config->SoName); + if (InitArraySec) { + Add({DT_INIT_ARRAY, InitArraySec}); + Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()}); } - - if (PreInitArraySec) - NumEntries += 2; - if (InitArraySec) - NumEntries += 2; - if (FiniArraySec) - NumEntries += 2; - - for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) { - if (!F->isNeeded()) - continue; - Out<ELFT>::DynStrTab->reserve(F->getSoName()); - ++NumEntries; + if (FiniArraySec) { + Add({DT_FINI_ARRAY, FiniArraySec}); + Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()}); } - if (Symbol *S = SymTab.getSymbols().lookup(Config->Init)) - InitSym = S->Body; - if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini)) - FiniSym = S->Body; - if (InitSym) - ++NumEntries; // DT_INIT - if (FiniSym) - ++NumEntries; // DT_FINI + if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Init)) + Add({DT_INIT, B}); + if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Fini)) + Add({DT_FINI, B}); + uint32_t DtFlags = 0; + uint32_t DtFlags1 = 0; if (Config->Bsymbolic) DtFlags |= DF_SYMBOLIC; if (Config->ZNodelete) @@ -626,462 +702,490 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { } if (DtFlags) - ++NumEntries; // DT_FLAGS + Add({DT_FLAGS, DtFlags}); if (DtFlags1) - ++NumEntries; // DT_FLAGS_1 + Add({DT_FLAGS_1, DtFlags1}); if (!Config->Entry.empty()) - ++NumEntries; // DT_DEBUG + Add({DT_DEBUG, (uint64_t)0}); + + bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0; + if (HasVerNeed || Out<ELFT>::VerDef) + Add({DT_VERSYM, Out<ELFT>::VerSym}); + if (Out<ELFT>::VerDef) { + Add({DT_VERDEF, Out<ELFT>::VerDef}); + Add({DT_VERDEFNUM, getVerDefNum()}); + } + if (HasVerNeed) { + Add({DT_VERNEED, Out<ELFT>::VerNeed}); + Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()}); + } if (Config->EMachine == EM_MIPS) { - ++NumEntries; // DT_MIPS_RLD_VERSION - ++NumEntries; // DT_MIPS_FLAGS - ++NumEntries; // DT_MIPS_BASE_ADDRESS - ++NumEntries; // DT_MIPS_SYMTABNO - ++NumEntries; // DT_MIPS_LOCAL_GOTNO - ++NumEntries; // DT_MIPS_GOTSYM; - ++NumEntries; // DT_PLTGOT + Add({DT_MIPS_RLD_VERSION, 1}); + Add({DT_MIPS_FLAGS, RHF_NOTPOT}); + Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); + Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()}); + Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()}); + if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry()) + Add({DT_MIPS_GOTSYM, B->DynsymIndex}); + else + Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()}); + Add({DT_PLTGOT, Out<ELFT>::Got}); if (Out<ELFT>::MipsRldMap) - ++NumEntries; // DT_MIPS_RLD_MAP + Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap}); } - ++NumEntries; // DT_NULL - - Header.sh_size = NumEntries * Header.sh_entsize; + // +1 for DT_NULL + Header.sh_size = (Entries.size() + 1) * Header.sh_entsize; } template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast<Elf_Dyn *>(Buf); - auto WritePtr = [&](int32_t Tag, uint64_t Val) { - P->d_tag = Tag; - P->d_un.d_ptr = Val; - ++P; - }; - - auto WriteVal = [&](int32_t Tag, uint32_t Val) { - P->d_tag = Tag; - P->d_un.d_val = Val; + for (const Entry &E : Entries) { + P->d_tag = E.Tag; + switch (E.Kind) { + case Entry::SecAddr: + P->d_un.d_ptr = E.OutSec->getVA(); + break; + case Entry::SymAddr: + P->d_un.d_ptr = E.Sym->template getVA<ELFT>(); + break; + case Entry::PlainInt: + P->d_un.d_val = E.Val; + break; + } ++P; - }; - - if (Out<ELFT>::RelaDyn->hasRelocs()) { - bool IsRela = Out<ELFT>::RelaDyn->isRela(); - WritePtr(IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn->getVA()); - WriteVal(IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()); - WriteVal(IsRela ? DT_RELAENT : DT_RELENT, - IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); } - if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) { - WritePtr(DT_JMPREL, Out<ELFT>::RelaPlt->getVA()); - WriteVal(DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()); - // On MIPS, the address of the .got.plt section is stored in - // the DT_MIPS_PLTGOT entry because the DT_PLTGOT entry points to - // the .got section. See "Dynamic Section" in the following document: - // https://sourceware.org/ml/binutils/2008-07/txt00000.txt - WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT, - Out<ELFT>::GotPlt->getVA()); - WriteVal(DT_PLTREL, Out<ELFT>::RelaPlt->isRela() ? DT_RELA : DT_REL); - } - - WritePtr(DT_SYMTAB, Out<ELFT>::DynSymTab->getVA()); - WritePtr(DT_SYMENT, sizeof(Elf_Sym)); - WritePtr(DT_STRTAB, Out<ELFT>::DynStrTab->getVA()); - WriteVal(DT_STRSZ, Out<ELFT>::DynStrTab->getSize()); - if (Out<ELFT>::GnuHashTab) - WritePtr(DT_GNU_HASH, Out<ELFT>::GnuHashTab->getVA()); - if (Out<ELFT>::HashTab) - WritePtr(DT_HASH, Out<ELFT>::HashTab->getVA()); - - // If --enable-new-dtags is set, lld emits DT_RUNPATH - // instead of DT_RPATH. The two tags are functionally - // equivalent except for the following: - // - DT_RUNPATH is searched after LD_LIBRARY_PATH, while - // DT_RPATH is searched before. - // - DT_RUNPATH is used only to search for direct - // dependencies of the object it's contained in, while - // DT_RPATH is used for indirect dependencies as well. - if (!Config->RPath.empty()) - WriteVal(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - Out<ELFT>::DynStrTab->addString(Config->RPath)); +} - if (!Config->SoName.empty()) - WriteVal(DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)); +template <class ELFT> +EhFrameHeader<ELFT>::EhFrameHeader() + : OutputSectionBase<ELFT>(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC) {} - auto WriteArray = [&](int32_t T1, int32_t T2, - const OutputSectionBase<ELFT> *Sec) { - if (!Sec) - return; - WritePtr(T1, Sec->getVA()); - WriteVal(T2, Sec->getSize()); - }; - WriteArray(DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, PreInitArraySec); - WriteArray(DT_INIT_ARRAY, DT_INIT_ARRAYSZ, InitArraySec); - WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec); +// .eh_frame_hdr contains a binary search table of pointers to FDEs. +// Each entry of the search table consists of two values, +// the starting PC from where FDEs covers, and the FDE's address. +// It is sorted by PC. +template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) { + const endianness E = ELFT::TargetEndianness; - for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) - if (F->isNeeded()) - WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())); + // Sort the FDE list by their PC and uniqueify. Usually there is only + // one FDE for a PC (i.e. function), but if ICF merges two functions + // into one, there can be more than one FDEs pointing to the address. + auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; }; + std::stable_sort(Fdes.begin(), Fdes.end(), Less); + auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; }; + Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end()); - if (InitSym) - WritePtr(DT_INIT, getSymVA<ELFT>(*InitSym)); - if (FiniSym) - WritePtr(DT_FINI, getSymVA<ELFT>(*FiniSym)); - if (DtFlags) - WriteVal(DT_FLAGS, DtFlags); - if (DtFlags1) - WriteVal(DT_FLAGS_1, DtFlags1); - if (!Config->Entry.empty()) - WriteVal(DT_DEBUG, 0); + Buf[0] = 1; + Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; + Buf[2] = DW_EH_PE_udata4; + Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; + write32<E>(Buf + 4, Out<ELFT>::EhFrame->getVA() - this->getVA() - 4); + write32<E>(Buf + 8, Fdes.size()); + Buf += 12; - // See "Dynamic Section" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS) { - WriteVal(DT_MIPS_RLD_VERSION, 1); - WriteVal(DT_MIPS_FLAGS, RHF_NOTPOT); - WritePtr(DT_MIPS_BASE_ADDRESS, Target->getVAStart()); - WriteVal(DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()); - WriteVal(DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()); - if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry()) - WriteVal(DT_MIPS_GOTSYM, B->DynamicSymbolTableIndex); - else - WriteVal(DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()); - WritePtr(DT_PLTGOT, Out<ELFT>::Got->getVA()); - if (Out<ELFT>::MipsRldMap) - WritePtr(DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap->getVA()); + uintX_t VA = this->getVA(); + for (FdeData &Fde : Fdes) { + write32<E>(Buf, Fde.Pc - VA); + write32<E>(Buf + 4, Fde.FdeVA - VA); + Buf += 8; } +} - WriteVal(DT_NULL, 0); +template <class ELFT> void EhFrameHeader<ELFT>::finalize() { + // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. + this->Header.sh_size = 12 + Out<ELFT>::EhFrame->NumFdes * 8; } template <class ELFT> -OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, - uintX_t Flags) - : OutputSectionBase<ELFT>(Name, Type, Flags) {} +void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) { + Fdes.push_back({Pc, FdeVA}); +} + +template <class ELFT> +OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags) + : OutputSectionBase<ELFT>(Name, Type, Flags) { + if (Type == SHT_RELA) + this->Header.sh_entsize = sizeof(Elf_Rela); + else if (Type == SHT_REL) + this->Header.sh_entsize = sizeof(Elf_Rel); +} + +template <class ELFT> void OutputSection<ELFT>::finalize() { + uint32_t Type = this->Header.sh_type; + if (Type != SHT_RELA && Type != SHT_REL) + return; + this->Header.sh_link = Out<ELFT>::SymTab->SectionIndex; + // sh_info for SHT_REL[A] sections should contain the section header index of + // the section to which the relocation applies. + InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection(); + this->Header.sh_info = S->OutSec->SectionIndex; +} template <class ELFT> void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { + assert(C->Live); auto *S = cast<InputSection<ELFT>>(C); Sections.push_back(S); S->OutSec = this; - uint32_t Align = S->getAlign(); - if (Align > this->Header.sh_addralign) - this->Header.sh_addralign = Align; - - uintX_t Off = this->Header.sh_size; - Off = align(Off, Align); - S->OutSecOff = Off; - Off += S->getSize(); - this->Header.sh_size = Off; + this->updateAlignment(S->Alignment); } -template <class ELFT> -typename ELFFile<ELFT>::uintX_t elf2::getSymVA(const SymbolBody &S) { - switch (S.kind()) { - case SymbolBody::DefinedSyntheticKind: { - auto &D = cast<DefinedSynthetic<ELFT>>(S); - return D.Section.getVA() + D.Value; - } - case SymbolBody::DefinedRegularKind: { - const auto &DR = cast<DefinedRegular<ELFT>>(S); - InputSectionBase<ELFT> *SC = DR.Section; - if (!SC) - return DR.Sym.st_value; +// If an input string is in the form of "foo.N" where N is a number, +// return N. Otherwise, returns 65536, which is one greater than the +// lowest priority. +static int getPriority(StringRef S) { + size_t Pos = S.rfind('.'); + if (Pos == StringRef::npos) + return 65536; + int V; + if (S.substr(Pos + 1).getAsInteger(10, V)) + return 65536; + return V; +} - // Symbol offsets for AMDGPU need to be the offset in bytes of the symbol - // from the beginning of the section. - if (Config->EMachine == EM_AMDGPU) - return SC->getOffset(DR.Sym); - if (DR.Sym.getType() == STT_TLS) - return SC->OutSec->getVA() + SC->getOffset(DR.Sym) - - Out<ELFT>::TlsPhdr->p_vaddr; - return SC->OutSec->getVA() + SC->getOffset(DR.Sym); - } - case SymbolBody::DefinedCommonKind: - return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(S).OffsetInBss; - case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol<ELFT>>(S); - if (SS.NeedsCopy) - return Out<ELFT>::Bss->getVA() + SS.OffsetInBss; - return 0; - } - case SymbolBody::UndefinedElfKind: - case SymbolBody::UndefinedKind: - return 0; - case SymbolBody::LazyKind: - assert(S.isUsedInRegularObj() && "Lazy symbol reached writer"); - return 0; +// This function is called after we sort input sections +// and scan relocations to setup sections' offsets. +template <class ELFT> void OutputSection<ELFT>::assignOffsets() { + uintX_t Off = this->Header.sh_size; + for (InputSection<ELFT> *S : Sections) { + Off = alignTo(Off, S->Alignment); + S->OutSecOff = Off; + Off += S->getSize(); } - llvm_unreachable("Invalid symbol kind"); + this->Header.sh_size = Off; } -// Returns a VA which a relocatin RI refers to. Used only for local symbols. -// For non-local symbols, use getSymVA instead. -template <class ELFT, bool IsRela> -typename ELFFile<ELFT>::uintX_t -elf2::getLocalRelTarget(const ObjectFile<ELFT> &File, - const Elf_Rel_Impl<ELFT, IsRela> &RI, - typename ELFFile<ELFT>::uintX_t Addend) { - typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename ELFFile<ELFT>::uintX_t uintX_t; - - // PPC64 has a special relocation representing the TOC base pointer - // that does not have a corresponding symbol. - if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) - return getPPC64TocBase() + Addend; +// Sorts input sections by section name suffixes, so that .foo.N comes +// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. +// We want to keep the original order if the priorities are the same +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +template <class ELFT> void OutputSection<ELFT>::sortInitFini() { + // Sort sections by priority. + typedef std::pair<int, InputSection<ELFT> *> Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - const Elf_Sym *Sym = - File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); + std::vector<Pair> V; + for (InputSection<ELFT> *S : Sections) + V.push_back({getPriority(S->getSectionName()), S}); + std::stable_sort(V.begin(), V.end(), Comp); + Sections.clear(); + for (Pair &P : V) + Sections.push_back(P.second); +} - if (!Sym) - error("Unsupported relocation without symbol"); +// Returns true if S matches /Filename.?\.o$/. +static bool isCrtBeginEnd(StringRef S, StringRef Filename) { + if (!S.endswith(".o")) + return false; + S = S.drop_back(2); + if (S.endswith(Filename)) + return true; + return !S.empty() && S.drop_back().endswith(Filename); +} - InputSectionBase<ELFT> *Section = File.getSection(*Sym); +static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } +static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } - if (Sym->getType() == STT_TLS) - return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) - - Out<ELFT>::TlsPhdr->p_vaddr; +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in crtbegin (crtbegin contains +// some sentinel value in its .ctors and .dtors so that the runtime +// can find the beginning of the sections.) +// +// 2. The section has an optional priority value in the form of ".ctors.N" +// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, +// they are compared as string rather than number. +// +// 3. The section is just ".ctors" or ".dtors". +// +// 4. The section was contained in crtend, which contains an end marker. +// +// In an ideal world, we don't need this function because .init_array and +// .ctors are duplicate features (and .init_array is newer.) However, there +// are too many real-world use cases of .ctors, so we had no choice to +// support that with this rather ad-hoc semantics. +template <class ELFT> +static bool compCtors(const InputSection<ELFT> *A, + const InputSection<ELFT> *B) { + bool BeginA = isCrtbegin(A->getFile()->getName()); + bool BeginB = isCrtbegin(B->getFile()->getName()); + if (BeginA != BeginB) + return BeginA; + bool EndA = isCrtend(A->getFile()->getName()); + bool EndB = isCrtend(B->getFile()->getName()); + if (EndA != EndB) + return EndB; + StringRef X = A->getSectionName(); + StringRef Y = B->getSectionName(); + assert(X.startswith(".ctors") || X.startswith(".dtors")); + assert(Y.startswith(".ctors") || Y.startswith(".dtors")); + X = X.substr(6); + Y = Y.substr(6); + if (X.empty() && Y.empty()) + return false; + return X < Y; +} - // According to the ELF spec reference to a local symbol from outside - // the group are not allowed. Unfortunately .eh_frame breaks that rule - // and must be treated specially. For now we just replace the symbol with - // 0. - if (Section == &InputSection<ELFT>::Discarded || !Section->isLive()) - return Addend; +// Sorts input sections by the special rules for .ctors and .dtors. +// Unfortunately, the rules are different from the one for .{init,fini}_array. +// Read the comment above. +template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() { + std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>); +} - uintX_t VA = Section->OutSec->getVA(); - if (isa<InputSection<ELFT>>(Section)) - return VA + Section->getOffset(*Sym) + Addend; +static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) { + size_t I = 0; + for (; I + A.size() < Size; I += A.size()) + memcpy(Buf + I, A.data(), A.size()); + memcpy(Buf + I, A.data(), Size - I); +} - uintX_t Offset = Sym->st_value; - if (Sym->getType() == STT_SECTION) { - Offset += Addend; - Addend = 0; +template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) { + ArrayRef<uint8_t> Filler = Script<ELFT>::X->getFiller(this->Name); + if (!Filler.empty()) + fill(Buf, this->getSize(), Filler); + if (Config->Threads) { + parallel_for_each(Sections.begin(), Sections.end(), + [=](InputSection<ELFT> *C) { C->writeTo(Buf); }); + } else { + for (InputSection<ELFT> *C : Sections) + C->writeTo(Buf); } - return VA + Section->getOffset(Offset) + Addend; } -// Returns true if a symbol can be replaced at load-time by a symbol -// with the same name defined in other ELF executable or DSO. -bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) { - if (!Body) - return false; // Body is a local symbol. - if (Body->isShared()) - return true; +template <class ELFT> +EhOutputSection<ELFT>::EhOutputSection() + : OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {} - if (Body->isUndefined()) { - if (!Body->isWeak()) - return true; +// Returns the first relocation that points to a region +// between Begin and Begin+Size. +template <class IntTy, class RelTy> +static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef<RelTy> &Rels) { + for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) { + if (I->r_offset < Begin) + continue; - // This is an horrible corner case. Ideally we would like to say that any - // undefined symbol can be preempted so that the dynamic linker has a - // chance of finding it at runtime. - // - // The problem is that the code sequence used to test for weak undef - // functions looks like - // if (func) func() - // If the code is -fPIC the first reference is a load from the got and - // everything works. - // If the code is not -fPIC there is no reasonable way to solve it: - // * A relocation writing to the text segment will fail (it is ro). - // * A copy relocation doesn't work for functions. - // * The trick of using a plt entry as the address would fail here since - // the plt entry would have a non zero address. - // Since we cannot do anything better, we just resolve the symbol to 0 and - // don't produce a dynamic relocation. - // - // As an extra hack, assume that if we are producing a shared library the - // user knows what he or she is doing and can handle a dynamic relocation. - return Config->Shared || NeedsGot; + // Truncate Rels for fast access. That means we expect that the + // relocations are sorted and we are looking up symbols in + // sequential order. It is naturally satisfied for .eh_frame. + Rels = Rels.slice(I - Rels.begin()); + if (I->r_offset < Begin + Size) + return I; + return nullptr; } - if (!Config->Shared) - return false; - return Body->getVisibility() == STV_DEFAULT; -} - -template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) { - for (InputSection<ELFT> *C : Sections) - C->writeTo(Buf); + Rels = ArrayRef<RelTy>(); + return nullptr; } +// Search for an existing CIE record or create a new one. +// CIE records from input object files are uniquified by their contents +// and where their relocations point to. template <class ELFT> -EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type, - uintX_t Flags) - : OutputSectionBase<ELFT>(Name, Type, Flags) {} +template <class RelTy> +CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece, + EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels) { + const endianness E = ELFT::TargetEndianness; + if (read32<E>(Piece.data().data() + 4) != 0) + fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName()); -template <class ELFT> -EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index) - : S(S), Index(Index) {} + SymbolBody *Personality = nullptr; + if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels)) + Personality = &Sec->getFile()->getRelocTargetSym(*Rel); -template <class ELFT> StringRef EHRegion<ELFT>::data() const { - ArrayRef<uint8_t> SecData = S->getSectionData(); - ArrayRef<std::pair<uintX_t, uintX_t>> Offsets = S->Offsets; - size_t Start = Offsets[Index].first; - size_t End = - Index == Offsets.size() - 1 ? SecData.size() : Offsets[Index + 1].first; - return StringRef((const char *)SecData.data() + Start, End - Start); + // Search for an existing CIE by CIE contents/relocation target pair. + CieRecord *Cie = &CieMap[{Piece.data(), Personality}]; + + // If not found, create a new one. + if (Cie->Piece == nullptr) { + Cie->Piece = &Piece; + Cies.push_back(Cie); + } + return Cie; } +// There is one FDE per function. Returns true if a given FDE +// points to a live function. template <class ELFT> -Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index) - : EHRegion<ELFT>(S, Index) {} +template <class RelTy> +bool EhOutputSection<ELFT>::isFdeLive(SectionPiece &Piece, + EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels) { + const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels); + if (!Rel) + fatal("FDE doesn't reference another section"); + SymbolBody &B = Sec->getFile()->getRelocTargetSym(*Rel); + auto *D = dyn_cast<DefinedRegular<ELFT>>(&B); + if (!D || !D->Section) + return false; + InputSectionBase<ELFT> *Target = D->Section->Repl; + return Target && Target->Live; +} +// .eh_frame is a sequence of CIE or FDE records. In general, there +// is one CIE record per input object file which is followed by +// a list of FDEs. This function searches an existing CIE or create a new +// one and associates FDEs to the CIE. template <class ELFT> -template <bool IsRela> -void EHOutputSection<ELFT>::addSectionAux( - EHInputSection<ELFT> *S, - iterator_range<const Elf_Rel_Impl<ELFT, IsRela> *> Rels) { +template <class RelTy> +void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> Rels) { const endianness E = ELFT::TargetEndianness; - S->OutSec = this; - uint32_t Align = S->getAlign(); - if (Align > this->Header.sh_addralign) - this->Header.sh_addralign = Align; - - Sections.push_back(S); - - ArrayRef<uint8_t> SecData = S->getSectionData(); - ArrayRef<uint8_t> D = SecData; - uintX_t Offset = 0; - auto RelI = Rels.begin(); - auto RelE = Rels.end(); - - DenseMap<unsigned, unsigned> OffsetToIndex; - while (!D.empty()) { - unsigned Index = S->Offsets.size(); - S->Offsets.push_back(std::make_pair(Offset, -1)); + DenseMap<size_t, CieRecord *> OffsetToCie; + for (SectionPiece &Piece : Sec->Pieces) { + // The empty record is the end marker. + if (Piece.size() == 4) + return; - uintX_t Length = readEntryLength(D); - StringRef Entry((const char *)D.data(), Length); + size_t Offset = Piece.InputOff; + uint32_t ID = read32<E>(Piece.data().data() + 4); + if (ID == 0) { + OffsetToCie[Offset] = addCie(Piece, Sec, Rels); + continue; + } - while (RelI != RelE && RelI->r_offset < Offset) - ++RelI; - uintX_t NextOffset = Offset + Length; - bool HasReloc = RelI != RelE && RelI->r_offset < NextOffset; + uint32_t CieOffset = Offset + 4 - ID; + CieRecord *Cie = OffsetToCie[CieOffset]; + if (!Cie) + fatal("invalid CIE reference"); - uint32_t ID = read32<E>(D.data() + 4); - if (ID == 0) { - // CIE - Cie<ELFT> C(S, Index); + if (!isFdeLive(Piece, Sec, Rels)) + continue; + Cie->FdePieces.push_back(&Piece); + NumFdes++; + } +} - StringRef Personality; - if (HasReloc) { - uint32_t SymIndex = RelI->getSymbol(Config->Mips64EL); - SymbolBody &Body = *S->getFile()->getSymbolBody(SymIndex)->repl(); - Personality = Body.getName(); - } +template <class ELFT> +void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { + auto *Sec = cast<EhInputSection<ELFT>>(C); + Sec->OutSec = this; + this->updateAlignment(Sec->Alignment); + Sections.push_back(Sec); - std::pair<StringRef, StringRef> CieInfo(Entry, Personality); - auto P = CieMap.insert(std::make_pair(CieInfo, Cies.size())); - if (P.second) { - Cies.push_back(C); - this->Header.sh_size += align(Length, sizeof(uintX_t)); - } - OffsetToIndex[Offset] = P.first->second; - } else { - if (!HasReloc) - error("FDE doesn't reference another section"); - InputSectionBase<ELFT> *Target = S->getRelocTarget(*RelI); - if (Target != &InputSection<ELFT>::Discarded && Target->isLive()) { - uint32_t CieOffset = Offset + 4 - ID; - auto I = OffsetToIndex.find(CieOffset); - if (I == OffsetToIndex.end()) - error("Invalid CIE reference"); - Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index)); - this->Header.sh_size += align(Length, sizeof(uintX_t)); - } - } + // .eh_frame is a sequence of CIE or FDE records. This function + // splits it into pieces so that we can call + // SplitInputSection::getSectionPiece on the section. + Sec->split(); + if (Sec->Pieces.empty()) + return; - Offset = NextOffset; - D = D.slice(Length); + if (const Elf_Shdr *RelSec = Sec->RelocSection) { + ELFFile<ELFT> &Obj = Sec->getFile()->getObj(); + if (RelSec->sh_type == SHT_RELA) + addSectionAux(Sec, Obj.relas(RelSec)); + else + addSectionAux(Sec, Obj.rels(RelSec)); + return; } + addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr)); } template <class ELFT> -typename EHOutputSection<ELFT>::uintX_t -EHOutputSection<ELFT>::readEntryLength(ArrayRef<uint8_t> D) { +static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { + memcpy(Buf, D.data(), D.size()); + + // Fix the size field. -4 since size does not include the size field itself. const endianness E = ELFT::TargetEndianness; + write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4); +} - if (D.size() < 4) - error("Truncated CIE/FDE length"); - uint64_t Len = read32<E>(D.data()); - if (Len < UINT32_MAX) { - if (Len > (UINT32_MAX - 4)) - error("CIE/FIE size is too large"); - if (Len + 4 > D.size()) - error("CIE/FIE ends past the end of the section"); - return Len + 4; - } +template <class ELFT> void EhOutputSection<ELFT>::finalize() { + if (this->Header.sh_size) + return; // Already finalized. + + size_t Off = 0; + for (CieRecord *Cie : Cies) { + Cie->Piece->OutputOff = Off; + Off += alignTo(Cie->Piece->size(), sizeof(uintX_t)); - if (D.size() < 12) - error("Truncated CIE/FDE length"); - Len = read64<E>(D.data() + 4); - if (Len > (UINT64_MAX - 12)) - error("CIE/FIE size is too large"); - if (Len + 12 > D.size()) - error("CIE/FIE ends past the end of the section"); - return Len + 12; + for (SectionPiece *Fde : Cie->FdePieces) { + Fde->OutputOff = Off; + Off += alignTo(Fde->size(), sizeof(uintX_t)); + } + } + this->Header.sh_size = Off; } -template <class ELFT> -void EHOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { - auto *S = cast<EHInputSection<ELFT>>(C); - const Elf_Shdr *RelSec = S->RelocSection; - if (!RelSec) - return addSectionAux( - S, make_range((const Elf_Rela *)nullptr, (const Elf_Rela *)nullptr)); - ELFFile<ELFT> &Obj = S->getFile()->getObj(); - if (RelSec->sh_type == SHT_RELA) - return addSectionAux(S, Obj.relas(RelSec)); - return addSectionAux(S, Obj.rels(RelSec)); +template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) { + const endianness E = ELFT::TargetEndianness; + switch (Size) { + case DW_EH_PE_udata2: + return read16<E>(Buf); + case DW_EH_PE_udata4: + return read32<E>(Buf); + case DW_EH_PE_udata8: + return read64<E>(Buf); + case DW_EH_PE_absptr: + if (ELFT::Is64Bits) + return read64<E>(Buf); + return read32<E>(Buf); + } + fatal("unknown FDE size encoding"); } +// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. +// We need it to create .eh_frame_hdr section. template <class ELFT> -static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data, - uint8_t *Buf) { - typedef typename ELFFile<ELFT>::uintX_t uintX_t; - const endianness E = ELFT::TargetEndianness; - uint64_t Len = align(Data.size(), sizeof(uintX_t)); - write32<E>(Buf, Len - 4); - memcpy(Buf + 4, Data.data() + 4, Data.size() - 4); - return Len; +typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff, + uint8_t Enc) { + // The starting address to which this FDE applies is + // stored at FDE + 8 byte. + size_t Off = FdeOff + 8; + uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7); + if ((Enc & 0x70) == DW_EH_PE_absptr) + return Addr; + if ((Enc & 0x70) == DW_EH_PE_pcrel) + return Addr + this->getVA() + Off; + fatal("unknown FDE size relative encoding"); } -template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) { +template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; - size_t Offset = 0; - for (const Cie<ELFT> &C : Cies) { - size_t CieOffset = Offset; + for (CieRecord *Cie : Cies) { + size_t CieOffset = Cie->Piece->OutputOff; + writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data()); - uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), Buf + Offset); - C.S->Offsets[C.Index].second = Offset; - Offset += CIELen; + for (SectionPiece *Fde : Cie->FdePieces) { + size_t Off = Fde->OutputOff; + writeCieFde<ELFT>(Buf + Off, Fde->data()); - for (const EHRegion<ELFT> &F : C.Fdes) { - uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset); - write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer - F.S->Offsets[F.Index].second = Offset; - Offset += Len; + // FDE's second word should have the offset to an associated CIE. + // Write it. + write32<E>(Buf + Off + 4, Off + 4 - CieOffset); } } - for (EHInputSection<ELFT> *S : Sections) { - const Elf_Shdr *RelSec = S->RelocSection; - if (!RelSec) - continue; - ELFFile<ELFT> &EObj = S->getFile()->getObj(); - if (RelSec->sh_type == SHT_RELA) - S->relocate(Buf, nullptr, EObj.relas(RelSec)); - else - S->relocate(Buf, nullptr, EObj.rels(RelSec)); + for (EhInputSection<ELFT> *S : Sections) + S->relocate(Buf, nullptr); + + // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table + // to get a FDE from an address to which FDE is applied. So here + // we obtain two addresses and pass them to EhFrameHdr object. + if (Out<ELFT>::EhFrameHdr) { + for (CieRecord *Cie : Cies) { + uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data()); + for (SectionPiece *Fde : Cie->FdePieces) { + uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); + uintX_t FdeVA = this->getVA() + Fde->OutputOff; + Out<ELFT>::EhFrameHdr->addFde(Pc, FdeVA); + } + } } } template <class ELFT> MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type, - uintX_t Flags) - : OutputSectionBase<ELFT>(Name, Type, Flags) {} + uintX_t Flags, uintX_t Alignment) + : OutputSectionBase<ELFT>(Name, Type, Flags), + Builder(StringTableBuilder::RAW, Alignment) {} template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) { if (shouldTailMerge()) { @@ -1089,58 +1193,32 @@ template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) { memcpy(Buf, Data.data(), Data.size()); return; } - for (const std::pair<StringRef, size_t> &P : Builder.getMap()) { - StringRef Data = P.first; + for (const std::pair<CachedHash<StringRef>, size_t> &P : Builder.getMap()) { + StringRef Data = P.first.Val; memcpy(Buf + P.second, Data.data(), Data.size()); } } -static size_t findNull(StringRef S, size_t EntSize) { - // Optimize the common case. - if (EntSize == 1) - return S.find(0); - - for (unsigned I = 0, N = S.size(); I != N; I += EntSize) { - const char *B = S.begin() + I; - if (std::all_of(B, B + EntSize, [](char C) { return C == 0; })) - return I; - } - return StringRef::npos; +static StringRef toStringRef(ArrayRef<uint8_t> A) { + return {(const char *)A.data(), A.size()}; } template <class ELFT> void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { - auto *S = cast<MergeInputSection<ELFT>>(C); - S->OutSec = this; - uint32_t Align = S->getAlign(); - if (Align > this->Header.sh_addralign) - this->Header.sh_addralign = Align; + auto *Sec = cast<MergeInputSection<ELFT>>(C); + Sec->OutSec = this; + this->updateAlignment(Sec->Alignment); + this->Header.sh_entsize = Sec->getSectionHdr()->sh_entsize; + Sections.push_back(Sec); - ArrayRef<uint8_t> D = S->getSectionData(); - StringRef Data((const char *)D.data(), D.size()); - uintX_t EntSize = S->getSectionHdr()->sh_entsize; + bool IsString = this->Header.sh_flags & SHF_STRINGS; - if (this->Header.sh_flags & SHF_STRINGS) { - uintX_t Offset = 0; - while (!Data.empty()) { - size_t End = findNull(Data, EntSize); - if (End == StringRef::npos) - error("String is not null terminated"); - StringRef Entry = Data.substr(0, End + EntSize); - uintX_t OutputOffset = Builder.add(Entry); - if (shouldTailMerge()) - OutputOffset = -1; - S->Offsets.push_back(std::make_pair(Offset, OutputOffset)); - uintX_t Size = End + EntSize; - Data = Data.substr(Size); - Offset += Size; - } - } else { - for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) { - StringRef Entry = Data.substr(I, EntSize); - size_t OutputOffset = Builder.add(Entry); - S->Offsets.push_back(std::make_pair(I, OutputOffset)); - } + for (SectionPiece &Piece : Sec->Pieces) { + if (!Piece.Live) + continue; + uintX_t OutputOffset = Builder.add(toStringRef(Piece.data())); + if (!IsString || !shouldTailMerge()) + Piece.OutputOff = OutputOffset; } } @@ -1159,38 +1237,32 @@ template <class ELFT> void MergeOutputSection<ELFT>::finalize() { this->Header.sh_size = Builder.getSize(); } +template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() { + for (MergeInputSection<ELFT> *Sec : Sections) + Sec->finalizePieces(); +} + template <class ELFT> StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic) : OutputSectionBase<ELFT>(Name, SHT_STRTAB, Dynamic ? (uintX_t)SHF_ALLOC : 0), - Dynamic(Dynamic) { - this->Header.sh_addralign = 1; -} - -// String tables are created in two phases. First you call reserve() -// to reserve room in the string table, and then call addString() to actually -// add that string. -// -// Why two phases? We want to know the size of the string table as early as -// possible to fix file layout. So we have separated finalize(), which -// determines the size of the section, from writeTo(), which writes the section -// contents to the output buffer. If we merge reserve() with addString(), -// we need a plumbing work for finalize() and writeTo() so that offsets -// we obtained in the former function can be written in the latter. -// This design eliminated that need. -template <class ELFT> void StringTableSection<ELFT>::reserve(StringRef S) { - Reserved += S.size() + 1; // +1 for NUL -} + Dynamic(Dynamic) {} -// Adds a string to the string table. You must call reserve() with the -// same string before calling addString(). -template <class ELFT> size_t StringTableSection<ELFT>::addString(StringRef S) { - size_t Pos = Used; +// Adds a string to the string table. If HashIt is true we hash and check for +// duplicates. It is optional because the name of global symbols are already +// uniqued and hashing them again has a big cost for a small value: uniquing +// them with some other string that happens to be the same. +template <class ELFT> +unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) { + if (HashIt) { + auto R = StringMap.insert(std::make_pair(S, Size)); + if (!R.second) + return R.first->second; + } + unsigned Ret = Size; + Size += S.size() + 1; Strings.push_back(S); - Used += S.size() + 1; - Reserved -= S.size() + 1; - assert((int64_t)Reserved >= 0); - return Pos; + return Ret; } template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) { @@ -1203,42 +1275,34 @@ template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) { } template <class ELFT> -bool elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File, StringRef SymName, - const typename ELFFile<ELFT>::Elf_Sym &Sym) { - if (Sym.getType() == STT_SECTION) - return false; - - InputSectionBase<ELFT> *Sec = File.getSection(Sym); - // If sym references a section in a discarded group, don't keep it. - if (Sec == &InputSection<ELFT>::Discarded) - return false; - - if (Config->DiscardNone) - return true; - - // In ELF assembly .L symbols are normally discarded by the assembler. - // If the assembler fails to do so, the linker discards them if - // * --discard-locals is used. - // * The symbol is in a SHF_MERGE section, which is normally the reason for - // the assembler keeping the .L symbol. - if (!SymName.startswith(".L") && !SymName.empty()) - return true; +typename ELFT::uint DynamicReloc<ELFT>::getOffset() const { + if (OutputSec) + return OutputSec->getVA() + OffsetInSec; + return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec); +} - if (Config->DiscardLocals) - return false; +template <class ELFT> +typename ELFT::uint DynamicReloc<ELFT>::getAddend() const { + if (UseSymVA) + return Sym->getVA<ELFT>(Addend); + return Addend; +} - return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE); +template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const { + if (Sym && !UseSymVA) + return Sym->DynsymIndex; + return 0; } template <class ELFT> SymbolTableSection<ELFT>::SymbolTableSection( - SymbolTable<ELFT> &Table, StringTableSection<ELFT> &StrTabSec) + StringTableSection<ELFT> &StrTabSec) : OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab", StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0), - Table(Table), StrTabSec(StrTabSec) { + StrTabSec(StrTabSec) { this->Header.sh_entsize = sizeof(Elf_Sym); - this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; + this->Header.sh_addralign = sizeof(uintX_t); } // Orders symbols according to their positions in the GOT, @@ -1246,10 +1310,25 @@ SymbolTableSection<ELFT>::SymbolTableSection( // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf -static bool sortMipsSymbols(SymbolBody *L, SymbolBody *R) { - if (!L->isInGot() || !R->isInGot()) - return R->isInGot(); - return L->GotIndex < R->GotIndex; +static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L, + const std::pair<SymbolBody *, unsigned> &R) { + // Sort entries related to non-local preemptible symbols by GOT indexes. + // All other entries go to the first part of GOT in arbitrary order. + bool LIsInLocalGot = !L.first->IsInGlobalMipsGot; + bool RIsInLocalGot = !R.first->IsInGlobalMipsGot; + if (LIsInLocalGot || RIsInLocalGot) + return !RIsInLocalGot; + return L.first->GotIndex < R.first->GotIndex; +} + +static uint8_t getSymbolBinding(SymbolBody *Body) { + Symbol *S = Body->symbol(); + uint8_t Visibility = S->Visibility; + if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) + return STB_LOCAL; + if (Config->NoGnuUnique && S->Binding == STB_GNU_UNIQUE) + return STB_GLOBAL; + return S->Binding; } template <class ELFT> void SymbolTableSection<ELFT>::finalize() { @@ -1260,11 +1339,19 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() { this->Header.sh_link = StrTabSec.SectionIndex; this->Header.sh_info = NumLocals + 1; + if (Config->Relocatable) { + size_t I = NumLocals; + for (const std::pair<SymbolBody *, size_t> &P : Symbols) + P.first->DynsymIndex = ++I; + return; + } + if (!StrTabSec.isDynamic()) { std::stable_sort(Symbols.begin(), Symbols.end(), - [](SymbolBody *L, SymbolBody *R) { - return getSymbolBinding(L) == STB_LOCAL && - getSymbolBinding(R) != STB_LOCAL; + [](const std::pair<SymbolBody *, unsigned> &L, + const std::pair<SymbolBody *, unsigned> &R) { + return getSymbolBinding(L.first) == STB_LOCAL && + getSymbolBinding(R.first) != STB_LOCAL; }); return; } @@ -1274,22 +1361,13 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() { else if (Config->EMachine == EM_MIPS) std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); size_t I = 0; - for (SymbolBody *B : Symbols) - B->DynamicSymbolTableIndex = ++I; + for (const std::pair<SymbolBody *, size_t> &P : Symbols) + P.first->DynsymIndex = ++I; } template <class ELFT> -void SymbolTableSection<ELFT>::addLocalSymbol(StringRef Name) { - StrTabSec.reserve(Name); - ++NumVisible; - ++NumLocals; -} - -template <class ELFT> -void SymbolTableSection<ELFT>::addSymbol(SymbolBody *Body) { - StrTabSec.reserve(Body->getName()); - Symbols.push_back(Body); - ++NumVisible; +void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) { + Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); } template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { @@ -1307,123 +1385,311 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) { // Iterate over all input object files to copy their local symbols // to the output symbol table pointed by Buf. - for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) { - Elf_Sym_Range Syms = File->getLocalSymbols(); - for (const Elf_Sym &Sym : Syms) { - ErrorOr<StringRef> SymNameOrErr = Sym.getName(File->getStringTable()); - error(SymNameOrErr); - StringRef SymName = *SymNameOrErr; - if (!shouldKeepInSymtab<ELFT>(*File, SymName, Sym)) - continue; - + for (const std::unique_ptr<ObjectFile<ELFT>> &File : + Symtab<ELFT>::X->getObjectFiles()) { + for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P : + File->KeptLocalSyms) { + const DefinedRegular<ELFT> &Body = *P.first; + InputSectionBase<ELFT> *Section = Body.Section; auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); - uintX_t VA = 0; - if (Sym.st_shndx == SHN_ABS) { + + if (!Section) { ESym->st_shndx = SHN_ABS; - VA = Sym.st_value; + ESym->st_value = Body.Value; } else { - InputSectionBase<ELFT> *Section = File->getSection(Sym); - if (!Section->isLive()) - continue; const OutputSectionBase<ELFT> *OutSec = Section->OutSec; ESym->st_shndx = OutSec->SectionIndex; - VA = Section->getOffset(Sym); - // Symbol offsets for AMDGPU need to be the offset in bytes of the - // symbol from the beginning of the section. - if (Config->EMachine != EM_AMDGPU) - VA += OutSec->getVA(); + ESym->st_value = OutSec->getVA() + Section->getOffset(Body); } - ESym->st_name = StrTabSec.addString(SymName); - ESym->st_size = Sym.st_size; - ESym->setBindingAndType(Sym.getBinding(), Sym.getType()); - ESym->st_value = VA; + ESym->st_name = P.second; + ESym->st_size = Body.template getSize<ELFT>(); + ESym->setBindingAndType(STB_LOCAL, Body.Type); Buf += sizeof(*ESym); } } } template <class ELFT> -static const typename llvm::object::ELFFile<ELFT>::Elf_Sym * -getElfSym(SymbolBody &Body) { - if (auto *EBody = dyn_cast<DefinedElf<ELFT>>(&Body)) - return &EBody->Sym; - if (auto *EBody = dyn_cast<UndefinedElf<ELFT>>(&Body)) - return &EBody->Sym; - return nullptr; -} - -template <class ELFT> void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) { // Write the internal symbol table contents to the output symbol table // pointed by Buf. auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); - for (SymbolBody *Body : Symbols) { - const OutputSectionBase<ELFT> *OutSec = nullptr; - - switch (Body->kind()) { - case SymbolBody::DefinedSyntheticKind: - OutSec = &cast<DefinedSynthetic<ELFT>>(Body)->Section; - break; - case SymbolBody::DefinedRegularKind: { - auto *Sym = cast<DefinedRegular<ELFT>>(Body->repl()); - if (InputSectionBase<ELFT> *Sec = Sym->Section) { - if (!Sec->isLive()) - continue; - OutSec = Sec->OutSec; - } - break; - } - case SymbolBody::DefinedCommonKind: - OutSec = Out<ELFT>::Bss; - break; - case SymbolBody::SharedKind: { - if (cast<SharedSymbol<ELFT>>(Body)->NeedsCopy) - OutSec = Out<ELFT>::Bss; - break; - } - case SymbolBody::UndefinedElfKind: - case SymbolBody::UndefinedKind: - case SymbolBody::LazyKind: - break; - } + for (const std::pair<SymbolBody *, size_t> &P : Symbols) { + SymbolBody *Body = P.first; + size_t StrOff = P.second; - StringRef Name = Body->getName(); - ESym->st_name = StrTabSec.addString(Name); - - unsigned char Type = STT_NOTYPE; - uintX_t Size = 0; - if (const Elf_Sym *InputSym = getElfSym<ELFT>(*Body)) { - Type = InputSym->getType(); - Size = InputSym->st_size; - } else if (auto *C = dyn_cast<DefinedCommon>(Body)) { - Type = STT_OBJECT; - Size = C->Size; - } + uint8_t Type = Body->Type; + uintX_t Size = Body->getSize<ELFT>(); ESym->setBindingAndType(getSymbolBinding(Body), Type); ESym->st_size = Size; - ESym->setVisibility(Body->getVisibility()); - ESym->st_value = getSymVA<ELFT>(*Body); + ESym->st_name = StrOff; + ESym->setVisibility(Body->symbol()->Visibility); + ESym->st_value = Body->getVA<ELFT>(); - if (OutSec) + if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body)) ESym->st_shndx = OutSec->SectionIndex; else if (isa<DefinedRegular<ELFT>>(Body)) ESym->st_shndx = SHN_ABS; + // On MIPS we need to mark symbol which has a PLT entry and requires pointer + // equality by STO_MIPS_PLT flag. That is necessary to help dynamic linker + // distinguish such symbols and MIPS lazy-binding stubs. + // https://sourceware.org/ml/binutils/2008-07/txt00000.txt + if (Config->EMachine == EM_MIPS && Body->isInPlt() && + Body->NeedsCopyOrPltAddr) + ESym->st_other |= STO_MIPS_PLT; ++ESym; } } template <class ELFT> -uint8_t SymbolTableSection<ELFT>::getSymbolBinding(SymbolBody *Body) { - uint8_t Visibility = Body->getVisibility(); - if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) - return STB_LOCAL; - if (const Elf_Sym *ESym = getElfSym<ELFT>(*Body)) - return ESym->getBinding(); - if (isa<DefinedSynthetic<ELFT>>(Body)) - return STB_LOCAL; - return Body->isWeak() ? STB_WEAK : STB_GLOBAL; +const OutputSectionBase<ELFT> * +SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { + switch (Sym->kind()) { + case SymbolBody::DefinedSyntheticKind: + return cast<DefinedSynthetic<ELFT>>(Sym)->Section; + case SymbolBody::DefinedRegularKind: { + auto &D = cast<DefinedRegular<ELFT>>(*Sym); + if (D.Section) + return D.Section->OutSec; + break; + } + case SymbolBody::DefinedCommonKind: + return Out<ELFT>::Bss; + case SymbolBody::SharedKind: + if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy()) + return Out<ELFT>::Bss; + break; + case SymbolBody::UndefinedKind: + case SymbolBody::LazyArchiveKind: + case SymbolBody::LazyObjectKind: + break; + case SymbolBody::DefinedBitcodeKind: + llvm_unreachable("should have been replaced"); + } + return nullptr; +} + +template <class ELFT> +VersionDefinitionSection<ELFT>::VersionDefinitionSection() + : OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) { + this->Header.sh_addralign = sizeof(uint32_t); +} + +static StringRef getFileDefName() { + if (!Config->SoName.empty()) + return Config->SoName; + return Config->OutputFile; +} + +template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() { + FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName()); + for (VersionDefinition &V : Config->VersionDefinitions) + V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name); + + this->Header.sh_size = + (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum(); + this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex; + + // sh_info should be set to the number of definitions. This fact is missed in + // documentation, but confirmed by binutils community: + // https://sourceware.org/ml/binutils/2014-11/msg00355.html + this->Header.sh_info = getVerDefNum(); +} + +template <class ELFT> +void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index, + StringRef Name, size_t NameOff) { + auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf); + Verdef->vd_version = 1; + Verdef->vd_cnt = 1; + Verdef->vd_aux = sizeof(Elf_Verdef); + Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); + Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0); + Verdef->vd_ndx = Index; + Verdef->vd_hash = hashSysv(Name); + + auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef)); + Verdaux->vda_name = NameOff; + Verdaux->vda_next = 0; +} + +template <class ELFT> +void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) { + writeOne(Buf, 1, getFileDefName(), FileDefNameOff); + + for (VersionDefinition &V : Config->VersionDefinitions) { + Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); + writeOne(Buf, V.Id, V.Name, V.NameOff); + } + + // Need to terminate the last version definition. + Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf); + Verdef->vd_next = 0; +} + +template <class ELFT> +VersionTableSection<ELFT>::VersionTableSection() + : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) { + this->Header.sh_addralign = sizeof(uint16_t); +} + +template <class ELFT> void VersionTableSection<ELFT>::finalize() { + this->Header.sh_size = + sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1); + this->Header.sh_entsize = sizeof(Elf_Versym); + // At the moment of june 2016 GNU docs does not mention that sh_link field + // should be set, but Sun docs do. Also readelf relies on this field. + this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex; +} + +template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) { + auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1; + for (const std::pair<SymbolBody *, size_t> &P : + Out<ELFT>::DynSymTab->getSymbols()) { + OutVersym->vs_index = P.first->symbol()->VersionId; + ++OutVersym; + } +} + +template <class ELFT> +VersionNeedSection<ELFT>::VersionNeedSection() + : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) { + this->Header.sh_addralign = sizeof(uint32_t); + + // Identifiers in verneed section start at 2 because 0 and 1 are reserved + // for VER_NDX_LOCAL and VER_NDX_GLOBAL. + // First identifiers are reserved by verdef section if it exist. + NextIndex = getVerDefNum() + 1; +} + +template <class ELFT> +void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { + if (!SS->Verdef) { + SS->symbol()->VersionId = VER_NDX_GLOBAL; + return; + } + SharedFile<ELFT> *F = SS->file(); + // If we don't already know that we need an Elf_Verneed for this DSO, prepare + // to create one by adding it to our needed list and creating a dynstr entry + // for the soname. + if (F->VerdefMap.empty()) + Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())}); + typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef]; + // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, + // prepare to create one by allocating a version identifier and creating a + // dynstr entry for the version name. + if (NV.Index == 0) { + NV.StrTab = Out<ELFT>::DynStrTab->addString( + SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name); + NV.Index = NextIndex++; + } + SS->symbol()->VersionId = NV.Index; +} + +template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { + // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. + auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); + auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size()); + + for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) { + // Create an Elf_Verneed for this DSO. + Verneed->vn_version = 1; + Verneed->vn_cnt = P.first->VerdefMap.size(); + Verneed->vn_file = P.second; + Verneed->vn_aux = + reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed); + Verneed->vn_next = sizeof(Elf_Verneed); + ++Verneed; + + // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over + // VerdefMap, which will only contain references to needed version + // definitions. Each Elf_Vernaux is based on the information contained in + // the Elf_Verdef in the source DSO. This loop iterates over a std::map of + // pointers, but is deterministic because the pointers refer to Elf_Verdef + // data structures within a single input file. + for (auto &NV : P.first->VerdefMap) { + Vernaux->vna_hash = NV.first->vd_hash; + Vernaux->vna_flags = 0; + Vernaux->vna_other = NV.second.Index; + Vernaux->vna_name = NV.second.StrTab; + Vernaux->vna_next = sizeof(Elf_Vernaux); + ++Vernaux; + } + + Vernaux[-1].vna_next = 0; + } + Verneed[-1].vn_next = 0; +} + +template <class ELFT> void VersionNeedSection<ELFT>::finalize() { + this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex; + this->Header.sh_info = Needed.size(); + unsigned Size = Needed.size() * sizeof(Elf_Verneed); + for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) + Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); + this->Header.sh_size = Size; +} + +template <class ELFT> +BuildIdSection<ELFT>::BuildIdSection(size_t HashSize) + : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC), + HashSize(HashSize) { + // 16 bytes for the note section header. + this->Header.sh_size = 16 + HashSize; +} + +template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) { + const endianness E = ELFT::TargetEndianness; + write32<E>(Buf, 4); // Name size + write32<E>(Buf + 4, HashSize); // Content size + write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type + memcpy(Buf + 12, "GNU", 4); // Name string + HashBuf = Buf + 16; +} + +template <class ELFT> +void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) { + const endianness E = ELFT::TargetEndianness; + + // 64-bit FNV-1 hash + uint64_t Hash = 0xcbf29ce484222325; + for (ArrayRef<uint8_t> Buf : Bufs) { + for (uint8_t B : Buf) { + Hash *= 0x100000001b3; + Hash ^= B; + } + } + write64<E>(this->HashBuf, Hash); +} + +template <class ELFT> +void BuildIdMd5<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) { + MD5 Hash; + for (ArrayRef<uint8_t> Buf : Bufs) + Hash.update(Buf); + MD5::MD5Result Res; + Hash.final(Res); + memcpy(this->HashBuf, Res, 16); +} + +template <class ELFT> +void BuildIdSha1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) { + SHA1 Hash; + for (ArrayRef<uint8_t> Buf : Bufs) + Hash.update(Buf); + memcpy(this->HashBuf, Hash.final().data(), 20); +} + +template <class ELFT> +BuildIdHexstring<ELFT>::BuildIdHexstring() + : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {} + +template <class ELFT> +void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) { + memcpy(this->HashBuf, Config->BuildIdVector.data(), + Config->BuildIdVector.size()); } template <class ELFT> @@ -1437,7 +1703,7 @@ MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection() template <class ELFT> void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) { auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf); - R->ri_gp_value = getMipsGpAddr<ELFT>(); + R->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset; R->ri_gprmask = GprMask; } @@ -1446,15 +1712,136 @@ void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { // Copy input object file's .reginfo gprmask to output. auto *S = cast<MipsReginfoInputSection<ELFT>>(C); GprMask |= S->Reginfo->ri_gprmask; + S->OutSec = this; +} + +template <class ELFT> +MipsOptionsOutputSection<ELFT>::MipsOptionsOutputSection() + : OutputSectionBase<ELFT>(".MIPS.options", SHT_MIPS_OPTIONS, + SHF_ALLOC | SHF_MIPS_NOSTRIP) { + this->Header.sh_addralign = 8; + this->Header.sh_entsize = 1; + this->Header.sh_size = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); +} + +template <class ELFT> +void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) { + auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf); + Opt->kind = ODK_REGINFO; + Opt->size = this->Header.sh_size; + Opt->section = 0; + Opt->info = 0; + auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt)); + Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset; + Reg->ri_gprmask = GprMask; +} + +template <class ELFT> +void MipsOptionsOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { + auto *S = cast<MipsOptionsInputSection<ELFT>>(C); + if (S->Reginfo) + GprMask |= S->Reginfo->ri_gprmask; + S->OutSec = this; +} + +template <class ELFT> +std::pair<OutputSectionBase<ELFT> *, bool> +OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C, + StringRef OutsecName) { + SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName); + OutputSectionBase<ELFT> *&Sec = Map[Key]; + if (Sec) + return {Sec, false}; + + switch (C->SectionKind) { + case InputSectionBase<ELFT>::Regular: + Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + break; + case InputSectionBase<ELFT>::EHFrame: + return {Out<ELFT>::EhFrame, false}; + case InputSectionBase<ELFT>::Merge: + Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags, + Key.Alignment); + break; + case InputSectionBase<ELFT>::MipsReginfo: + Sec = new MipsReginfoOutputSection<ELFT>(); + break; + case InputSectionBase<ELFT>::MipsOptions: + Sec = new MipsOptionsOutputSection<ELFT>(); + break; + } + return {Sec, true}; +} + +template <class ELFT> +OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name, + uint32_t Type, + uintX_t Flags) { + return Map.lookup({Name, Type, Flags, 0}); +} + +template <class ELFT> +SectionKey<ELFT::Is64Bits> +OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C, + StringRef OutsecName) { + const Elf_Shdr *H = C->getSectionHdr(); + uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; + + // For SHF_MERGE we create different output sections for each alignment. + // This makes each output section simple and keeps a single level mapping from + // input to output. + uintX_t Alignment = 0; + if (isa<MergeInputSection<ELFT>>(C)) + Alignment = std::max(H->sh_addralign, H->sh_entsize); + + uint32_t Type = H->sh_type; + return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment}; +} + +template <bool Is64Bits> +typename lld::elf::SectionKey<Is64Bits> +DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() { + return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0}; +} + +template <bool Is64Bits> +typename lld::elf::SectionKey<Is64Bits> +DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() { + return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0, + 0}; +} + +template <bool Is64Bits> +unsigned +DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) { + return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment); +} + +template <bool Is64Bits> +bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS, + const Key &RHS) { + return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) && + LHS.Type == RHS.Type && LHS.Flags == RHS.Flags && + LHS.Alignment == RHS.Alignment; +} + +namespace llvm { +template struct DenseMapInfo<SectionKey<true>>; +template struct DenseMapInfo<SectionKey<false>>; } namespace lld { -namespace elf2 { +namespace elf { template class OutputSectionBase<ELF32LE>; template class OutputSectionBase<ELF32BE>; template class OutputSectionBase<ELF64LE>; template class OutputSectionBase<ELF64BE>; +template class EhFrameHeader<ELF32LE>; +template class EhFrameHeader<ELF32BE>; +template class EhFrameHeader<ELF64LE>; +template class EhFrameHeader<ELF64BE>; + template class GotPltSection<ELF32LE>; template class GotPltSection<ELF32BE>; template class GotPltSection<ELF64LE>; @@ -1500,16 +1887,21 @@ template class OutputSection<ELF32BE>; template class OutputSection<ELF64LE>; template class OutputSection<ELF64BE>; -template class EHOutputSection<ELF32LE>; -template class EHOutputSection<ELF32BE>; -template class EHOutputSection<ELF64LE>; -template class EHOutputSection<ELF64BE>; +template class EhOutputSection<ELF32LE>; +template class EhOutputSection<ELF32BE>; +template class EhOutputSection<ELF64LE>; +template class EhOutputSection<ELF64BE>; template class MipsReginfoOutputSection<ELF32LE>; template class MipsReginfoOutputSection<ELF32BE>; template class MipsReginfoOutputSection<ELF64LE>; template class MipsReginfoOutputSection<ELF64BE>; +template class MipsOptionsOutputSection<ELF32LE>; +template class MipsOptionsOutputSection<ELF32BE>; +template class MipsOptionsOutputSection<ELF64LE>; +template class MipsOptionsOutputSection<ELF64BE>; + template class MergeOutputSection<ELF32LE>; template class MergeOutputSection<ELF32BE>; template class MergeOutputSection<ELF64LE>; @@ -1525,39 +1917,49 @@ template class SymbolTableSection<ELF32BE>; template class SymbolTableSection<ELF64LE>; template class SymbolTableSection<ELF64BE>; -template ELFFile<ELF32LE>::uintX_t getSymVA<ELF32LE>(const SymbolBody &); -template ELFFile<ELF32BE>::uintX_t getSymVA<ELF32BE>(const SymbolBody &); -template ELFFile<ELF64LE>::uintX_t getSymVA<ELF64LE>(const SymbolBody &); -template ELFFile<ELF64BE>::uintX_t getSymVA<ELF64BE>(const SymbolBody &); +template class VersionTableSection<ELF32LE>; +template class VersionTableSection<ELF32BE>; +template class VersionTableSection<ELF64LE>; +template class VersionTableSection<ELF64BE>; + +template class VersionNeedSection<ELF32LE>; +template class VersionNeedSection<ELF32BE>; +template class VersionNeedSection<ELF64LE>; +template class VersionNeedSection<ELF64BE>; + +template class VersionDefinitionSection<ELF32LE>; +template class VersionDefinitionSection<ELF32BE>; +template class VersionDefinitionSection<ELF64LE>; +template class VersionDefinitionSection<ELF64BE>; + +template class BuildIdSection<ELF32LE>; +template class BuildIdSection<ELF32BE>; +template class BuildIdSection<ELF64LE>; +template class BuildIdSection<ELF64BE>; + +template class BuildIdFnv1<ELF32LE>; +template class BuildIdFnv1<ELF32BE>; +template class BuildIdFnv1<ELF64LE>; +template class BuildIdFnv1<ELF64BE>; + +template class BuildIdMd5<ELF32LE>; +template class BuildIdMd5<ELF32BE>; +template class BuildIdMd5<ELF64LE>; +template class BuildIdMd5<ELF64BE>; + +template class BuildIdSha1<ELF32LE>; +template class BuildIdSha1<ELF32BE>; +template class BuildIdSha1<ELF64LE>; +template class BuildIdSha1<ELF64BE>; -template ELFFile<ELF32LE>::uintX_t -getLocalRelTarget(const ObjectFile<ELF32LE> &, - const ELFFile<ELF32LE>::Elf_Rel &, - ELFFile<ELF32LE>::uintX_t Addend); -template ELFFile<ELF32BE>::uintX_t -getLocalRelTarget(const ObjectFile<ELF32BE> &, - const ELFFile<ELF32BE>::Elf_Rel &, - ELFFile<ELF32BE>::uintX_t Addend); -template ELFFile<ELF64LE>::uintX_t -getLocalRelTarget(const ObjectFile<ELF64LE> &, - const ELFFile<ELF64LE>::Elf_Rel &, - ELFFile<ELF64LE>::uintX_t Addend); -template ELFFile<ELF64BE>::uintX_t -getLocalRelTarget(const ObjectFile<ELF64BE> &, - const ELFFile<ELF64BE>::Elf_Rel &, - ELFFile<ELF64BE>::uintX_t Addend); +template class BuildIdHexstring<ELF32LE>; +template class BuildIdHexstring<ELF32BE>; +template class BuildIdHexstring<ELF64LE>; +template class BuildIdHexstring<ELF64BE>; -template bool shouldKeepInSymtab<ELF32LE>(const ObjectFile<ELF32LE> &, - StringRef, - const ELFFile<ELF32LE>::Elf_Sym &); -template bool shouldKeepInSymtab<ELF32BE>(const ObjectFile<ELF32BE> &, - StringRef, - const ELFFile<ELF32BE>::Elf_Sym &); -template bool shouldKeepInSymtab<ELF64LE>(const ObjectFile<ELF64LE> &, - StringRef, - const ELFFile<ELF64LE>::Elf_Sym &); -template bool shouldKeepInSymtab<ELF64BE>(const ObjectFile<ELF64BE> &, - StringRef, - const ELFFile<ELF64BE>::Elf_Sym &); +template class OutputSectionFactory<ELF32LE>; +template class OutputSectionFactory<ELF32BE>; +template class OutputSectionFactory<ELF64LE>; +template class OutputSectionFactory<ELF64BE>; } } diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index d7109c580cdc..5fdf8de4cb46 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -10,64 +10,35 @@ #ifndef LLD_ELF_OUTPUT_SECTIONS_H #define LLD_ELF_OUTPUT_SECTIONS_H -#include "lld/Core/LLVM.h" +#include "Config.h" +#include "Relocations.h" -#include "llvm/ADT/MapVector.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" - -#include "Config.h" - -#include <type_traits> +#include "llvm/Support/MD5.h" +#include "llvm/Support/SHA1.h" namespace lld { -namespace elf2 { +namespace elf { class SymbolBody; +struct SectionPiece; template <class ELFT> class SymbolTable; template <class ELFT> class SymbolTableSection; template <class ELFT> class StringTableSection; -template <class ELFT> class EHInputSection; +template <class ELFT> class EhInputSection; template <class ELFT> class InputSection; template <class ELFT> class InputSectionBase; template <class ELFT> class MergeInputSection; template <class ELFT> class MipsReginfoInputSection; template <class ELFT> class OutputSection; template <class ELFT> class ObjectFile; +template <class ELFT> class SharedFile; +template <class ELFT> class SharedSymbol; template <class ELFT> class DefinedRegular; -// Flag to force GOT to be in output if we have relocations -// that relies on its address. -extern bool HasGotOffRel; - -template <class ELFT> -static inline typename llvm::object::ELFFile<ELFT>::uintX_t -getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Rel) { - return 0; -} - -template <class ELFT> -static inline typename llvm::object::ELFFile<ELFT>::uintX_t -getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rela &Rel) { - return Rel.r_addend; -} - -template <class ELFT> -typename llvm::object::ELFFile<ELFT>::uintX_t getSymVA(const SymbolBody &S); - -template <class ELFT, bool IsRela> -typename llvm::object::ELFFile<ELFT>::uintX_t -getLocalRelTarget(const ObjectFile<ELFT> &File, - const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel, - typename llvm::object::ELFFile<ELFT>::uintX_t Addend); - -bool canBePreempted(const SymbolBody *Body, bool NeedsGot); - -template <class ELFT> -bool shouldKeepInSymtab( - const ObjectFile<ELFT> &File, StringRef Name, - const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym); - // This represents a section in an output file. // Different sub classes represent different types of sections. Some contain // input sections, others are created by the linker. @@ -75,13 +46,14 @@ bool shouldKeepInSymtab( // non-overlapping file offsets and VAs. template <class ELFT> class OutputSectionBase { public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; - OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags); void setVA(uintX_t VA) { Header.sh_addr = VA; } uintX_t getVA() const { return Header.sh_addr; } void setFileOffset(uintX_t Off) { Header.sh_offset = Off; } + void setSHName(unsigned Val) { Header.sh_name = Val; } void writeHeaderTo(Elf_Shdr *SHdr); StringRef getName() { return Name; } @@ -92,21 +64,24 @@ public: // Returns the size of the section in the output file. uintX_t getSize() const { return Header.sh_size; } void setSize(uintX_t Val) { Header.sh_size = Val; } - uintX_t getFlags() { return Header.sh_flags; } - uintX_t getFileOff() { return Header.sh_offset; } - uintX_t getAlign() { - // The ELF spec states that a value of 0 means the section has no alignment - // constraits. - return std::max<uintX_t>(Header.sh_addralign, 1); - } - uint32_t getType() { return Header.sh_type; } - void updateAlign(uintX_t Align) { - if (Align > Header.sh_addralign) - Header.sh_addralign = Align; + uintX_t getFlags() const { return Header.sh_flags; } + uintX_t getFileOff() const { return Header.sh_offset; } + uintX_t getAlignment() const { return Header.sh_addralign; } + uint32_t getType() const { return Header.sh_type; } + + void updateAlignment(uintX_t Alignment) { + if (Alignment > Header.sh_addralign) + Header.sh_addralign = Alignment; } + // If true, this section will be page aligned on disk. + // Typically the first section of each PT_LOAD segment has this flag. + bool PageAlign = false; + virtual void finalize() {} - virtual void writeTo(uint8_t *Buf) = 0; + virtual void finalizePieces() {} + virtual void assignOffsets() {} + virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; protected: @@ -116,18 +91,21 @@ protected: template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename Base::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: GotSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); - bool addDynTlsEntry(SymbolBody *Sym); - bool addCurrentModuleTlsIndex(); - bool empty() const { return Entries.empty(); } - uintX_t getEntryAddr(const SymbolBody &B) const; + void addEntry(SymbolBody &Sym); + void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); + bool addDynTlsEntry(SymbolBody &Sym); + bool addTlsIndex(); + bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } + uintX_t getMipsLocalPageOffset(uintX_t Addr); + uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getGlobalDynOffset(const SymbolBody &B) const; uintX_t getNumEntries() const { return Entries.size(); } // Returns the symbol which corresponds to the first entry of the global part @@ -140,24 +118,52 @@ public: // the number of reserved entries. This method is MIPS-specific. unsigned getMipsLocalEntriesNum() const; - uint32_t getLocalTlsIndexVA() { return Base::getVA() + LocalTlsIndexOff; } + // Returns offset of TLS part of the MIPS GOT table. This part goes + // after 'local' and 'global' entries. + uintX_t getMipsTlsOffset(); + + uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; } + uint32_t getTlsIndexOff() { return TlsIndexOff; } + + // Flag to force GOT to be in output if we have relocations + // that relies on its address. + bool HasGotOffRel = false; private: std::vector<const SymbolBody *> Entries; - uint32_t LocalTlsIndexOff = -1; + uint32_t TlsIndexOff = -1; + uint32_t MipsPageEntries = 0; + // Output sections referenced by MIPS GOT relocations. + llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections; + llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos; + + // MIPS ABI requires to create unique GOT entry for each Symbol/Addend + // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` + // or `MipsGlobal` vectors. In general it does not have a sence to take in + // account addend for preemptible symbols because the corresponding + // GOT entries should have one-to-one mapping with dynamic symbols table. + // But we use the same container's types for both kind of GOT entries + // to handle them uniformly. + typedef std::pair<const SymbolBody*, uintX_t> MipsGotEntry; + typedef std::vector<MipsGotEntry> MipsGotEntries; + llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap; + MipsGotEntries MipsLocal; + MipsGotEntries MipsGlobal; + + // Write MIPS-specific parts of the GOT. + void writeMipsGot(uint8_t *&Buf); }; template <class ELFT> class GotPltSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: GotPltSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); + void addEntry(SymbolBody &Sym); bool empty() const; - uintX_t getEntryAddr(const SymbolBody &B) const; private: std::vector<const SymbolBody *> Entries; @@ -165,156 +171,248 @@ private: template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename Base::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: PltSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); + void addEntry(SymbolBody &Sym); bool empty() const { return Entries.empty(); } - uintX_t getEntryAddr(const SymbolBody &B) const; private: std::vector<std::pair<const SymbolBody *, unsigned>> Entries; }; -template <class ELFT> struct DynamicReloc { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - InputSectionBase<ELFT> *C; - const Elf_Rel *RI; +template <class ELFT> class DynamicReloc { + typedef typename ELFT::uint uintX_t; + +public: + DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OutputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + uintX_t getOffset() const; + uintX_t getAddend() const; + uint32_t getSymIndex() const; + const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; } + + uint32_t Type; + +private: + SymbolBody *Sym; + const InputSectionBase<ELFT> *InputSec = nullptr; + const OutputSectionBase<ELFT> *OutputSec = nullptr; + uintX_t OffsetInSec; + bool UseSymVA; + uintX_t Addend; }; template <class ELFT> class SymbolTableSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - SymbolTableSection(SymbolTable<ELFT> &Table, - StringTableSection<ELFT> &StrTabSec); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::uint uintX_t; + SymbolTableSection(StringTableSection<ELFT> &StrTabSec); void finalize() override; void writeTo(uint8_t *Buf) override; - void addLocalSymbol(StringRef Name); void addSymbol(SymbolBody *Body); StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; } - unsigned getNumSymbols() const { return NumVisible + 1; } + unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; } + + ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const { + return Symbols; + } - ArrayRef<SymbolBody *> getSymbols() const { return Symbols; } + unsigned NumLocals = 0; + StringTableSection<ELFT> &StrTabSec; private: void writeLocalSymbols(uint8_t *&Buf); void writeGlobalSymbols(uint8_t *Buf); - static uint8_t getSymbolBinding(SymbolBody *Body); + const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym); - SymbolTable<ELFT> &Table; - StringTableSection<ELFT> &StrTabSec; - std::vector<SymbolBody *> Symbols; - unsigned NumVisible = 0; - unsigned NumLocals = 0; + // A vector of symbols and their string table offsets. + std::vector<std::pair<SymbolBody *, size_t>> Symbols; +}; + +// For more information about .gnu.version and .gnu.version_r see: +// https://www.akkadia.org/drepper/symbol-versioning + +// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall +// contain symbol version definitions. The number of entries in this section +// shall be contained in the DT_VERDEFNUM entry of the .dynamic section. +// The section shall contain an array of Elf_Verdef structures, optionally +// followed by an array of Elf_Verdaux structures. +template <class ELFT> +class VersionDefinitionSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + +public: + VersionDefinitionSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + +private: + void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); + + unsigned FileDefNameOff; +}; + +// The .gnu.version section specifies the required version of each symbol in the +// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol +// table entry. An Elf_Versym is just a 16-bit integer that refers to a version +// identifier defined in the either .gnu.version_r or .gnu.version_d section. +// The values 0 and 1 are reserved. All other values are used for versions in +// the own object or in any of the dependencies. +template <class ELFT> +class VersionTableSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Versym Elf_Versym; + +public: + VersionTableSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; +}; + +// The .gnu.version_r section defines the version identifiers used by +// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each +// Elf_Verneed specifies the version requirements for a single DSO, and contains +// a reference to a linked list of Elf_Vernaux data structures which define the +// mapping from version identifiers to version names. +template <class ELFT> +class VersionNeedSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + // A vector of shared files that need Elf_Verneed data structures and the + // string table offsets of their sonames. + std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed; + + // The next available version identifier. + unsigned NextIndex; + +public: + VersionNeedSection(); + void addSymbol(SharedSymbol<ELFT> *SS); + void finalize() override; + void writeTo(uint8_t *Buf) override; + size_t getNeedNum() const { return Needed.size(); } }; template <class ELFT> class RelocationSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::uint uintX_t; public: - RelocationSection(StringRef Name, bool IsRela); - void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); } + RelocationSection(StringRef Name, bool Sort); + void addReloc(const DynamicReloc<ELFT> &Reloc); unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; bool hasRelocs() const { return !Relocs.empty(); } - bool isRela() const { return IsRela; } bool Static = false; private: - bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P, - Elf_Rel *N); - + bool Sort; std::vector<DynamicReloc<ELFT>> Relocs; - const bool IsRela; }; template <class ELFT> class OutputSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::uint uintX_t; + OutputSection(StringRef Name, uint32_t Type, uintX_t Flags); void addSection(InputSectionBase<ELFT> *C) override; + void sortInitFini(); + void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; - -private: + void finalize() override; + void assignOffsets() override; std::vector<InputSection<ELFT> *> Sections; }; template <class ELFT> class MergeOutputSection final : public OutputSectionBase<ELFT> { - typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t; - - bool shouldTailMerge() const; + typedef typename ELFT::uint uintX_t; public: - MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags, + uintX_t Alignment); void addSection(InputSectionBase<ELFT> *S) override; void writeTo(uint8_t *Buf) override; unsigned getOffset(StringRef Val); void finalize() override; + void finalizePieces() override; + bool shouldTailMerge() const; private: - llvm::StringTableBuilder Builder{llvm::StringTableBuilder::RAW}; + llvm::StringTableBuilder Builder; + std::vector<MergeInputSection<ELFT> *> Sections; }; -// FDE or CIE -template <class ELFT> struct EHRegion { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - EHRegion(EHInputSection<ELFT> *S, unsigned Index); - StringRef data() const; - EHInputSection<ELFT> *S; - unsigned Index; -}; - -template <class ELFT> struct Cie : public EHRegion<ELFT> { - Cie(EHInputSection<ELFT> *S, unsigned Index); - std::vector<EHRegion<ELFT>> Fdes; +struct CieRecord { + SectionPiece *Piece = nullptr; + std::vector<SectionPiece *> FdePieces; }; +// Output section for .eh_frame. template <class ELFT> -class EHOutputSection final : public OutputSectionBase<ELFT> { +class EhOutputSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - EHOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + EhOutputSection(); void writeTo(uint8_t *Buf) override; - - template <bool IsRela> - void addSectionAux( - EHInputSection<ELFT> *S, - llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, IsRela> *> - Rels); + void finalize() override; + bool empty() const { return Sections.empty(); } void addSection(InputSectionBase<ELFT> *S) override; + size_t NumFdes = 0; + private: - uintX_t readEntryLength(ArrayRef<uint8_t> D); + template <class RelTy> + void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels); + + template <class RelTy> + CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels); - std::vector<EHInputSection<ELFT> *> Sections; - std::vector<Cie<ELFT>> Cies; + template <class RelTy> + bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels); - // Maps CIE content + personality to a index in Cies. - llvm::DenseMap<std::pair<StringRef, StringRef>, unsigned> CieMap; + uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc); + + std::vector<EhInputSection<ELFT> *> Sections; + std::vector<CieRecord *> Cies; + + // CIE records are uniquified by their contents and personality functions. + llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap; }; template <class ELFT> @@ -327,25 +425,24 @@ public: template <class ELFT> class StringTableSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; StringTableSection(StringRef Name, bool Dynamic); - void reserve(StringRef S); - size_t addString(StringRef S); + unsigned addString(StringRef S, bool HashIt = true); void writeTo(uint8_t *Buf) override; - size_t getSize() const { return Used + Reserved; } + unsigned getSize() const { return Size; } void finalize() override { this->Header.sh_size = getSize(); } bool isDynamic() const { return Dynamic; } private: const bool Dynamic; + llvm::DenseMap<StringRef, unsigned> StringMap; std::vector<StringRef> Strings; - size_t Used = 1; // ELF string tables start with a NUL byte, so 1. - size_t Reserved = 0; + unsigned Size = 1; // ELF string tables start with a NUL byte, so 1. }; template <class ELFT> class HashTableSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; + typedef typename ELFT::Word Elf_Word; public: HashTableSection(); @@ -357,9 +454,9 @@ public: // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections template <class ELFT> class GnuHashTableSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Off Elf_Off; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Off Elf_Off; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::uint uintX_t; public: GnuHashTableSection(); @@ -368,7 +465,7 @@ public: // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. - void addSymbols(std::vector<SymbolBody *> &Symbols); + void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols); private: static unsigned calcNBuckets(unsigned NumHashed); @@ -378,12 +475,13 @@ private: void writeBloomFilter(uint8_t *&Buf); void writeHashTable(uint8_t *Buf); - struct HashedSymbolData { + struct SymbolData { SymbolBody *Body; + size_t STName; uint32_t Hash; }; - std::vector<HashedSymbolData> HashedSymbols; + std::vector<SymbolData> Symbols; unsigned MaskWords; unsigned NBuckets; @@ -393,27 +491,45 @@ private: template <class ELFT> class DynamicSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Dyn Elf_Dyn; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename ELFT::Dyn Elf_Dyn; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; + + // The .dynamic section contains information for the dynamic linker. + // The section consists of fixed size entries, which consist of + // type and value fields. Value are one of plain integers, symbol + // addresses, or section addresses. This struct represents the entry. + struct Entry { + int32_t Tag; + union { + OutputSectionBase<ELFT> *OutSec; + uint64_t Val; + const SymbolBody *Sym; + }; + enum KindT { SecAddr, SymAddr, PlainInt } Kind; + Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec) + : Tag(Tag), OutSec(OutSec), Kind(SecAddr) {} + Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {} + Entry(int32_t Tag, const SymbolBody *Sym) + : Tag(Tag), Sym(Sym), Kind(SymAddr) {} + }; + + // finalize() fills this vector with the section contents. finalize() + // cannot directly create final section contents because when the + // function is called, symbol or section addresses are not fixed yet. + std::vector<Entry> Entries; public: - DynamicSection(SymbolTable<ELFT> &SymTab); + explicit DynamicSection(); void finalize() override; void writeTo(uint8_t *Buf) override; OutputSectionBase<ELFT> *PreInitArraySec = nullptr; OutputSectionBase<ELFT> *InitArraySec = nullptr; OutputSectionBase<ELFT> *FiniArraySec = nullptr; - -private: - SymbolTable<ELFT> &SymTab; - const SymbolBody *InitSym = nullptr; - const SymbolBody *FiniSym = nullptr; - uint32_t DtFlags = 0; - uint32_t DtFlags1 = 0; }; template <class ELFT> @@ -429,17 +545,94 @@ private: uint32_t GprMask = 0; }; -inline uint64_t align(uint64_t Value, uint64_t Align) { - return llvm::RoundUpToAlignment(Value, Align); -} +template <class ELFT> +class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> { + typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; + typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; + +public: + MipsOptionsOutputSection(); + void writeTo(uint8_t *Buf) override; + void addSection(InputSectionBase<ELFT> *S) override; + +private: + uint32_t GprMask = 0; +}; + +// --eh-frame-hdr option tells linker to construct a header for all the +// .eh_frame sections. This header is placed to a section named .eh_frame_hdr +// and also to a PT_GNU_EH_FRAME segment. +// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by +// calling dl_iterate_phdr. +// This section contains a lookup table for quick binary search of FDEs. +// Detailed info about internals can be found in Ian Lance Taylor's blog: +// http://www.airs.com/blog/archives/460 (".eh_frame") +// http://www.airs.com/blog/archives/462 (".eh_frame_hdr") +template <class ELFT> +class EhFrameHeader final : public OutputSectionBase<ELFT> { + typedef typename ELFT::uint uintX_t; + +public: + EhFrameHeader(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + void addFde(uint32_t Pc, uint32_t FdeVA); + +private: + struct FdeData { + uint32_t Pc; + uint32_t FdeVA; + }; + + std::vector<FdeData> Fdes; +}; + +template <class ELFT> class BuildIdSection : public OutputSectionBase<ELFT> { +public: + void writeTo(uint8_t *Buf) override; + virtual void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) = 0; + +protected: + BuildIdSection(size_t HashSize); + size_t HashSize; + uint8_t *HashBuf = nullptr; +}; + +template <class ELFT> class BuildIdFnv1 final : public BuildIdSection<ELFT> { +public: + BuildIdFnv1() : BuildIdSection<ELFT>(8) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> class BuildIdMd5 final : public BuildIdSection<ELFT> { +public: + BuildIdMd5() : BuildIdSection<ELFT>(16) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> class BuildIdSha1 final : public BuildIdSection<ELFT> { +public: + BuildIdSha1() : BuildIdSection<ELFT>(20) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> +class BuildIdHexstring final : public BuildIdSection<ELFT> { +public: + BuildIdHexstring(); + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; // All output sections that are hadnled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. template <class ELFT> struct Out { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Phdr Elf_Phdr; + static BuildIdSection<ELFT> *BuildId; static DynamicSection<ELFT> *Dynamic; + static EhFrameHeader<ELFT> *EhFrameHdr; + static EhOutputSection<ELFT> *EhFrame; static GnuHashTableSection<ELFT> *GnuHashTab; static GotPltSection<ELFT> *GotPlt; static GotSection<ELFT> *Got; @@ -457,10 +650,47 @@ template <class ELFT> struct Out { static StringTableSection<ELFT> *StrTab; static SymbolTableSection<ELFT> *DynSymTab; static SymbolTableSection<ELFT> *SymTab; + static VersionDefinitionSection<ELFT> *VerDef; + static VersionTableSection<ELFT> *VerSym; + static VersionNeedSection<ELFT> *VerNeed; static Elf_Phdr *TlsPhdr; + static OutputSectionBase<ELFT> *ElfHeader; + static OutputSectionBase<ELFT> *ProgramHeaders; +}; + +template <bool Is64Bits> struct SectionKey { + typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t; + StringRef Name; + uint32_t Type; + uintX_t Flags; + uintX_t Alignment; +}; + +// This class knows how to create an output section for a given +// input section. Output section type is determined by various +// factors, including input section's sh_flags, sh_type and +// linker scripts. +template <class ELFT> class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename elf::SectionKey<ELFT::Is64Bits> Key; + +public: + std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C, + StringRef OutsecName); + + OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags); + +private: + Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName); + + llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map; }; +template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId; template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic; +template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr; +template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame; template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab; template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt; template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got; @@ -478,9 +708,25 @@ template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab; template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab; -template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr; +template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef; +template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym; +template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed; +template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr; +template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader; +template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders; -} // namespace elf2 +} // namespace elf } // namespace lld -#endif // LLD_ELF_OUTPUT_SECTIONS_H +namespace llvm { +template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> { + typedef typename lld::elf::SectionKey<Is64Bits> Key; + + static Key getEmptyKey(); + static Key getTombstoneKey(); + static unsigned getHashValue(const Key &Val); + static bool isEqual(const Key &LHS, const Key &RHS); +}; +} + +#endif diff --git a/ELF/README.md b/ELF/README.md index 49b8167bbfe0..f1bfc9c15263 100644 --- a/ELF/README.md +++ b/ELF/README.md @@ -1,21 +1 @@ -The New ELF Linker -================== -This directory contains a port of the new PE/COFF linker for ELF. - -Overall Design --------------- -See COFF/README.md for details on the design. Note that unlike COFF, we do not -distinguish chunks from input sections; they are merged together. - -Capabilities ------------- -This linker can link LLVM and Clang on Linux/x86-64 or FreeBSD/x86-64 -"Hello world" can be linked on Linux/PPC64 and on Linux/AArch64 or -FreeBSD/AArch64. - -Performance ------------ -Achieving good performance is one of our goals. It's too early to reach a -conclusion, but we are optimistic about that as it currently seems to be faster -than GNU gold. It will be interesting to compare when we are close to feature -parity. +See docs/NewLLD.rst diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp new file mode 100644 index 000000000000..c09cf6b2b1ef --- /dev/null +++ b/ELF/Relocations.cpp @@ -0,0 +1,704 @@ +//===- Relocations.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains platform-independent functions to process relocations. +// I'll describe the overview of this file here. +// +// Simple relocations are easy to handle for the linker. For example, +// for R_X86_64_PC64 relocs, the linker just has to fix up locations +// with the relative offsets to the target symbols. It would just be +// reading records from relocation sections and applying them to output. +// +// But not all relocations are that easy to handle. For example, for +// R_386_GOTOFF relocs, the linker has to create new GOT entries for +// symbols if they don't exist, and fix up locations with GOT entry +// offsets from the beginning of GOT section. So there is more than +// fixing addresses in relocation processing. +// +// ELF defines a large number of complex relocations. +// +// The functions in this file analyze relocations and do whatever needs +// to be done. It includes, but not limited to, the following. +// +// - create GOT/PLT entries +// - create new relocations in .dynsym to let the dynamic linker resolve +// them at runtime (since ELF supports dynamic linking, not all +// relocations can be resolved at link-time) +// - create COPY relocs and reserve space in .bss +// - replace expensive relocs (in terms of runtime cost) with cheap ones +// - error out infeasible combinations such as PIC and non-relative relocs +// +// Note that the functions in this file don't actually apply relocations +// because it doesn't know about the output file nor the output file buffer. +// It instead stores Relocation objects to InputSection's Relocations +// vector to let it apply later in InputSection::writeTo. +// +//===----------------------------------------------------------------------===// + +#include "Relocations.h" +#include "Config.h" +#include "OutputSections.h" +#include "SymbolTable.h" +#include "Target.h" +#include "Thunks.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; +using namespace llvm::support::endian; + +namespace lld { +namespace elf { + +static bool refersToGotEntry(RelExpr Expr) { + return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE || + Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD || + Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC || + Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC || + Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE; +} + +static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { + // In case of MIPS GP-relative relocations always resolve to a definition + // in a regular input file, ignoring the one-definition rule. So we, + // for example, should not attempt to create a dynamic relocation even + // if the target symbol is preemptible. There are two two MIPS GP-relative + // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 + // can be against a preemptible symbol. + // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all + // relocation types occupy eight bit. In case of N64 ABI we extract first + // relocation from 3-in-1 packet because only the first relocation can + // be against a real symbol. + if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16) + return false; + return Body.isPreemptible(); +} + +// This function is similar to the `handleTlsRelocation`. MIPS does not support +// any relaxations for TLS relocations so by factoring out MIPS handling into +// the separate function we can simplify the code and does not pollute +// `handleTlsRelocation` by MIPS `ifs` statements. +template <class ELFT> +static unsigned +handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, + InputSectionBase<ELFT> &C, typename ELFT::uint Offset, + typename ELFT::uint Addend, RelExpr Expr) { + if (Expr == R_MIPS_TLSLD) { + if (Out<ELFT>::Got->addTlsIndex()) + Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got, + Out<ELFT>::Got->getTlsIndexOff(), false, + nullptr, 0}); + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); + return 1; + } + if (Target->isTlsGlobalDynamicRel(Type)) { + if (Out<ELFT>::Got->addDynTlsEntry(Body)) { + typedef typename ELFT::uint uintX_t; + uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); + Out<ELFT>::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0}); + Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, + Off + (uintX_t)sizeof(uintX_t), false, + &Body, 0}); + } + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); + return 1; + } + return 0; +} + +// Returns the number of relocations processed. +template <class ELFT> +static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, + InputSectionBase<ELFT> &C, + typename ELFT::uint Offset, + typename ELFT::uint Addend, RelExpr Expr) { + if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC)) + return 0; + + if (!Body.isTls()) + return 0; + + typedef typename ELFT::uint uintX_t; + + if (Config->EMachine == EM_MIPS) + return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr); + + if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) && + Config->Shared) { + if (Out<ELFT>::Got->addDynTlsEntry(Body)) { + uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); + Out<ELFT>::RelaDyn->addReloc( + {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0}); + } + if (Expr != R_HINT) + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); + return 1; + } + + if (Expr == R_TLSLD_PC || Expr == R_TLSLD) { + // Local-Dynamic relocs can be relaxed to Local-Exec. + if (!Config->Shared) { + C.Relocations.push_back( + {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body}); + return 2; + } + if (Out<ELFT>::Got->addTlsIndex()) + Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got, + Out<ELFT>::Got->getTlsIndexOff(), false, + nullptr, 0}); + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); + return 1; + } + + // Local-Dynamic relocs can be relaxed to Local-Exec. + if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) { + C.Relocations.push_back( + {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body}); + return 1; + } + + if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT || + Target->isTlsGlobalDynamicRel(Type)) { + if (Config->Shared) { + if (Out<ELFT>::Got->addDynTlsEntry(Body)) { + uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); + Out<ELFT>::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0}); + + // If the symbol is preemptible we need the dynamic linker to write + // the offset too. + if (isPreemptible(Body, Type)) + Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, + Off + (uintX_t)sizeof(uintX_t), false, + &Body, 0}); + } + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); + return 1; + } + + // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec + // depending on the symbol being locally defined or not. + if (isPreemptible(Body, Type)) { + C.Relocations.push_back( + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, + &C, Offset, Addend, &Body}); + if (!Body.isInGot()) { + Out<ELFT>::Got->addEntry(Body); + Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got, + Body.getGotOffset<ELFT>(), false, &Body, + 0}); + } + return Target->TlsGdRelaxSkip; + } + C.Relocations.push_back( + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, &C, + Offset, Addend, &Body}); + return Target->TlsGdRelaxSkip; + } + + // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally + // defined. + if (Target->isTlsInitialExecRel(Type) && !Config->Shared && + !isPreemptible(Body, Type)) { + C.Relocations.push_back( + {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body}); + return 1; + } + return 0; +} + +template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) { + return read32<E>(Loc) & 0xffff; +} + +template <class RelTy> +static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) { + switch (Rel->getType(Config->Mips64EL)) { + case R_MIPS_HI16: + return R_MIPS_LO16; + case R_MIPS_GOT16: + return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE; + case R_MIPS_PCHI16: + return R_MIPS_PCLO16; + case R_MICROMIPS_HI16: + return R_MICROMIPS_LO16; + default: + return R_MIPS_NONE; + } +} + +template <class ELFT, class RelTy> +static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc, + SymbolBody &Sym, const RelTy *Rel, + const RelTy *End) { + uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL); + uint32_t Type = getMipsPairType(Rel, Sym); + + // Some MIPS relocations use addend calculated from addend of the relocation + // itself and addend of paired relocation. ABI requires to compute such + // combined addend in case of REL relocation record format only. + // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (RelTy::IsRela || Type == R_MIPS_NONE) + return 0; + + for (const RelTy *RI = Rel; RI != End; ++RI) { + if (RI->getType(Config->Mips64EL) != Type) + continue; + if (RI->getSymbol(Config->Mips64EL) != SymIndex) + continue; + const endianness E = ELFT::TargetEndianness; + return ((read32<E>(BufLoc) & 0xffff) << 16) + + readSignedLo16<E>(Buf + RI->r_offset); + } + warning("can't find matching " + getRelName(Type) + " relocation for " + + getRelName(Rel->getType(Config->Mips64EL))); + return 0; +} + +// True if non-preemptable symbol always has the same value regardless of where +// the DSO is loaded. +template <class ELFT> static bool isAbsolute(const SymbolBody &Body) { + if (Body.isUndefined()) + return !Body.isLocal() && Body.symbol()->isWeak(); + if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body)) + return DR->Section == nullptr; // Absolute symbol. + return false; +} + +static bool needsPlt(RelExpr Expr) { + return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT || + Expr == R_PLT_PAGE_PC || Expr == R_THUNK_PLT_PC; +} + +// True if this expression is of the form Sym - X, where X is a position in the +// file (PC, or GOT for example). +static bool isRelExpr(RelExpr Expr) { + return Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC || + Expr == R_RELAX_GOT_PC || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC; +} + +template <class ELFT> +static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, + const SymbolBody &Body) { + // These expressions always compute a constant + if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || + E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD || + E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || + E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || + E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC) + return true; + + // These never do, except if the entire file is position dependent or if + // only the low bits are used. + if (E == R_GOT || E == R_PLT || E == R_TLSDESC) + return Target->usesOnlyLowPageBits(Type) || !Config->Pic; + + if (isPreemptible(Body, Type)) + return false; + + if (!Config->Pic) + return true; + + bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls(); + bool RelE = isRelExpr(E); + if (AbsVal && !RelE) + return true; + if (!AbsVal && RelE) + return true; + + // Relative relocation to an absolute value. This is normally unrepresentable, + // but if the relocation refers to a weak undefined symbol, we allow it to + // resolve to the image base. This is a little strange, but it allows us to + // link function calls to such symbols. Normally such a call will be guarded + // with a comparison, which will load a zero from the GOT. + if (AbsVal && RelE) { + if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) + return true; + error("relocation " + getRelName(Type) + + " cannot refer to absolute symbol " + Body.getName()); + return true; + } + + return Target->usesOnlyLowPageBits(Type); +} + +static RelExpr toPlt(RelExpr Expr) { + if (Expr == R_PPC_OPD) + return R_PPC_PLT_OPD; + if (Expr == R_PC) + return R_PLT_PC; + if (Expr == R_PAGE_PC) + return R_PLT_PAGE_PC; + if (Expr == R_ABS) + return R_PLT; + return Expr; +} + +static RelExpr fromPlt(RelExpr Expr) { + // We decided not to use a plt. Optimize a reference to the plt to a + // reference to the symbol itself. + if (Expr == R_PLT_PC) + return R_PC; + if (Expr == R_PPC_PLT_OPD) + return R_PPC_OPD; + if (Expr == R_PLT) + return R_ABS; + return Expr; +} + +template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) { + typedef typename ELFT::uint uintX_t; + + uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign; + uintX_t SymValue = SS->Sym.st_value; + int TrailingZeros = + std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue)); + return 1 << TrailingZeros; +} + +// Reserve space in .bss for copy relocation. +template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Sym Elf_Sym; + + // Copy relocation against zero-sized symbol doesn't make sense. + uintX_t SymSize = SS->template getSize<ELFT>(); + if (SymSize == 0) + fatal("cannot create a copy relocation for " + SS->getName()); + + uintX_t Alignment = getAlignment(SS); + uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment); + Out<ELFT>::Bss->setSize(Off + SymSize); + Out<ELFT>::Bss->updateAlignment(Alignment); + uintX_t Shndx = SS->Sym.st_shndx; + uintX_t Value = SS->Sym.st_value; + // Look through the DSO's dynamic symbol table for aliases and create a + // dynamic symbol for each one. This causes the copy relocation to correctly + // interpose any aliases. + for (const Elf_Sym &S : SS->file()->getElfSymbols(true)) { + if (S.st_shndx != Shndx || S.st_value != Value) + continue; + auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>( + Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable())))); + if (!Alias) + continue; + Alias->OffsetInBss = Off; + Alias->NeedsCopyOrPltAddr = true; + Alias->symbol()->IsUsedInRegularObj = true; + } + Out<ELFT>::RelaDyn->addReloc( + {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0}); +} + +template <class ELFT> +static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body, + bool IsWrite, RelExpr Expr, uint32_t Type, + const uint8_t *Data) { + bool Preemptible = isPreemptible(Body, Type); + if (Body.isGnuIFunc()) { + Expr = toPlt(Expr); + } else if (!Preemptible) { + if (needsPlt(Expr)) + Expr = fromPlt(Expr); + if (Expr == R_GOT_PC) + Expr = Target->adjustRelaxExpr(Type, Data, Expr); + } + Expr = Target->getThunkExpr(Expr, Type, File, Body); + + if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body)) + return Expr; + + // This relocation would require the dynamic linker to write a value to read + // only memory. We can hack around it if we are producing an executable and + // the refered symbol can be preemepted to refer to the executable. + if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { + error("can't create dynamic relocation " + getRelName(Type) + + " against readonly segment"); + return Expr; + } + if (Body.getVisibility() != STV_DEFAULT) { + error("cannot preempt symbol"); + return Expr; + } + if (Body.isObject()) { + // Produce a copy relocation. + auto *B = cast<SharedSymbol<ELFT>>(&Body); + if (!B->needsCopy()) + addCopyRelSymbol(B); + return Expr; + } + if (Body.isFunc()) { + // This handles a non PIC program call to function in a shared library. In + // an ideal world, we could just report an error saying the relocation can + // overflow at runtime. In the real world with glibc, crt1.o has a + // R_X86_64_PC32 pointing to libc.so. + // + // The general idea on how to handle such cases is to create a PLT entry and + // use that as the function value. + // + // For the static linking part, we just return a plt expr and everything + // else will use the the PLT entry as the address. + // + // The remaining problem is making sure pointer equality still works. We + // need the help of the dynamic linker for that. We let it know that we have + // a direct reference to a so symbol by creating an undefined symbol with a + // non zero st_value. Seeing that, the dynamic linker resolves the symbol to + // the value of the symbol we created. This is true even for got entries, so + // pointer equality is maintained. To avoid an infinite loop, the only entry + // that points to the real function is a dedicated got entry used by the + // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, + // R_386_JMP_SLOT, etc). + Body.NeedsCopyOrPltAddr = true; + return toPlt(Expr); + } + error("symbol is missing type"); + + return Expr; +} + +template <class ELFT, class RelTy> +static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File, + const uint8_t *SectionData, + const RelTy *End, const RelTy &RI, + RelExpr Expr, SymbolBody &Body) { + typedef typename ELFT::uint uintX_t; + + uint32_t Type = RI.getType(Config->Mips64EL); + uintX_t Addend = getAddend<ELFT>(RI); + const uint8_t *BufLoc = SectionData + RI.r_offset; + if (!RelTy::IsRela) + Addend += Target->getImplicitAddend(BufLoc, Type); + if (Config->EMachine == EM_MIPS) { + Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End); + if (Type == R_MIPS_LO16 && Expr == R_PC) + // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp + // symbol. In that case we should use the following formula for + // calculation "AHL + GP - P + 4". Let's add 4 right here. + // For details see p. 4-19 at + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Addend += 4; + if (Expr == R_GOTREL) { + Addend -= MipsGPOffset; + if (Body.isLocal()) + Addend += File.getMipsGp0(); + } + } + if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) + Addend += getPPC64TocBase(); + return Addend; +} + +// The reason we have to do this early scan is as follows +// * To mmap the output file, we need to know the size +// * For that, we need to know how many dynamic relocs we will have. +// It might be possible to avoid this by outputting the file with write: +// * Write the allocated output sections, computing addresses. +// * Apply relocations, recording which ones require a dynamic reloc. +// * Write the dynamic relocations. +// * Write the rest of the file. +// This would have some drawbacks. For example, we would only know if .rela.dyn +// is needed after applying relocations. If it is, it will go after rw and rx +// sections. Given that it is ro, we will need an extra PT_LOAD. This +// complicates things for the dynamic linker and means we would have to reserve +// space for the extra PT_LOAD even if we end up not using it. +template <class ELFT, class RelTy> +static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) { + typedef typename ELFT::uint uintX_t; + + bool IsWrite = C.getSectionHdr()->sh_flags & SHF_WRITE; + + auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) { + Out<ELFT>::RelaDyn->addReloc(Reloc); + }; + + const elf::ObjectFile<ELFT> &File = *C.getFile(); + ArrayRef<uint8_t> SectionData = C.getSectionData(); + const uint8_t *Buf = SectionData.begin(); + for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) { + const RelTy &RI = *I; + SymbolBody &Body = File.getRelocTargetSym(RI); + uint32_t Type = RI.getType(Config->Mips64EL); + + RelExpr Expr = Target->getRelExpr(Type, Body); + bool Preemptible = isPreemptible(Body, Type); + Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf + RI.r_offset); + if (HasError) + continue; + + // Skip a relocation that points to a dead piece + // in a mergeable section. + if (C.getOffset(RI.r_offset) == (uintX_t)-1) + continue; + + // This relocation does not require got entry, but it is relative to got and + // needs it to be created. Here we request for that. + if (Expr == R_GOTONLY_PC || Expr == R_GOTREL || Expr == R_PPC_TOC) + Out<ELFT>::Got->HasGotOffRel = true; + + uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body); + + if (unsigned Processed = handleTlsRelocation<ELFT>( + Type, Body, C, RI.r_offset, Addend, Expr)) { + I += (Processed - 1); + continue; + } + + // Ignore "hint" relocation because it is for optional code optimization. + if (Expr == R_HINT) + continue; + + if (needsPlt(Expr) || Expr == R_THUNK_ABS || Expr == R_THUNK_PC || + Expr == R_THUNK_PLT_PC || refersToGotEntry(Expr) || + !isPreemptible(Body, Type)) { + // If the relocation points to something in the file, we can process it. + bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body); + + // If the output being produced is position independent, the final value + // is still not known. In that case we still need some help from the + // dynamic linker. We can however do better than just copying the incoming + // relocation. We can process some of it and and just ask the dynamic + // linker to add the load address. + if (!Constant) + AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend}); + + // If the produced value is a constant, we just remember to write it + // when outputting this section. We also have to do it if the format + // uses Elf_Rel, since in that case the written value is the addend. + if (Constant || !RelTy::IsRela) + C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body}); + } else { + // We don't know anything about the finaly symbol. Just ask the dynamic + // linker to handle the relocation for us. + AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend}); + // MIPS ABI turns using of GOT and dynamic relocations inside out. + // While regular ABI uses dynamic relocations to fill up GOT entries + // MIPS ABI requires dynamic linker to fills up GOT entries using + // specially sorted dynamic symbol table. This affects even dynamic + // relocations against symbols which do not require GOT entries + // creation explicitly, i.e. do not have any GOT-relocations. So if + // a preemptible symbol has a dynamic relocation we anyway have + // to create a GOT entry for it. + // If a non-preemptible symbol has a dynamic relocation against it, + // dynamic linker takes it st_value, adds offset and writes down + // result of the dynamic relocation. In case of preemptible symbol + // dynamic linker performs symbol resolution, writes the symbol value + // to the GOT entry and reads the GOT entry when it needs to perform + // a dynamic relocation. + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 + if (Config->EMachine == EM_MIPS) + Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr); + continue; + } + + // Some targets might require creation of thunks for relocations. + // Now we support only MIPS which requires LA25 thunk to call PIC + // code from non-PIC one, and ARM which requires interworking. + if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) { + auto *Sec = cast<InputSection<ELFT>>(&C); + addThunk<ELFT>(Type, Body, *Sec); + } + + // At this point we are done with the relocated position. Some relocations + // also require us to create a got or plt entry. + + // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol. + if (needsPlt(Expr)) { + if (Body.isInPlt()) + continue; + Out<ELFT>::Plt->addEntry(Body); + + uint32_t Rel; + if (Body.isGnuIFunc() && !Preemptible) + Rel = Target->IRelativeRel; + else + Rel = Target->PltRel; + + Out<ELFT>::GotPlt->addEntry(Body); + Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt, + Body.getGotPltOffset<ELFT>(), !Preemptible, + &Body, 0}); + continue; + } + + if (refersToGotEntry(Expr)) { + if (Config->EMachine == EM_MIPS) { + // MIPS ABI has special rules to process GOT entries + // and doesn't require relocation entries for them. + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr); + if (Body.isTls()) + AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), + !Preemptible, &Body, 0}); + continue; + } + + if (Body.isInGot()) + continue; + + Out<ELFT>::Got->addEntry(Body); + if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) { + uint32_t DynType; + if (Body.isTls()) + DynType = Target->TlsGotRel; + else if (Preemptible) + DynType = Target->GotRel; + else + DynType = Target->RelativeRel; + AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), + !Preemptible, &Body, 0}); + } + continue; + } + } +} + +template <class ELFT> void scanRelocations(InputSection<ELFT> &C) { + typedef typename ELFT::Shdr Elf_Shdr; + + // Scan all relocations. Each relocation goes through a series + // of tests to determine if it needs special treatment, such as + // creating GOT, PLT, copy relocations, etc. + // Note that relocations for non-alloc sections are directly + // processed by InputSection::relocateNonAlloc. + if (C.getSectionHdr()->sh_flags & SHF_ALLOC) + for (const Elf_Shdr *RelSec : C.RelocSections) + scanRelocations(C, *RelSec); +} + +template <class ELFT> +void scanRelocations(InputSectionBase<ELFT> &S, + const typename ELFT::Shdr &RelSec) { + ELFFile<ELFT> &EObj = S.getFile()->getObj(); + if (RelSec.sh_type == SHT_RELA) + scanRelocs(S, EObj.relas(&RelSec)); + else + scanRelocs(S, EObj.rels(&RelSec)); +} + +template void scanRelocations<ELF32LE>(InputSection<ELF32LE> &); +template void scanRelocations<ELF32BE>(InputSection<ELF32BE> &); +template void scanRelocations<ELF64LE>(InputSection<ELF64LE> &); +template void scanRelocations<ELF64BE>(InputSection<ELF64BE> &); + +template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &, + const ELF32LE::Shdr &); +template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &, + const ELF32BE::Shdr &); +template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &, + const ELF64LE::Shdr &); +template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &, + const ELF64BE::Shdr &); +} +} diff --git a/ELF/Relocations.h b/ELF/Relocations.h new file mode 100644 index 000000000000..4c1c74efb0da --- /dev/null +++ b/ELF/Relocations.h @@ -0,0 +1,93 @@ +//===- Relocations.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_RELOCATIONS_H +#define LLD_ELF_RELOCATIONS_H + +#include "lld/Core/LLVM.h" + +namespace lld { +namespace elf { +class SymbolBody; +template <class ELFT> class InputSection; +template <class ELFT> class InputSectionBase; + +enum RelExpr { + R_ABS, + R_GOT, + R_GOTONLY_PC, + R_GOTREL, + R_GOT_FROM_END, + R_GOT_OFF, + R_GOT_PAGE_PC, + R_GOT_PC, + R_HINT, + R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOT_OFF, + R_MIPS_TLSGD, + R_MIPS_TLSLD, + R_NEG_TLS, + R_PAGE_PC, + R_PC, + R_PLT, + R_PLT_PC, + R_PLT_PAGE_PC, + R_PPC_OPD, + R_PPC_PLT_OPD, + R_PPC_TOC, + R_RELAX_GOT_PC, + R_RELAX_GOT_PC_NOPIC, + R_RELAX_TLS_GD_TO_IE, + R_RELAX_TLS_GD_TO_IE_END, + R_RELAX_TLS_GD_TO_IE_ABS, + R_RELAX_TLS_GD_TO_IE_PAGE_PC, + R_RELAX_TLS_GD_TO_LE, + R_RELAX_TLS_GD_TO_LE_NEG, + R_RELAX_TLS_IE_TO_LE, + R_RELAX_TLS_LD_TO_LE, + R_SIZE, + R_THUNK_ABS, + R_THUNK_PC, + R_THUNK_PLT_PC, + R_TLS, + R_TLSDESC, + R_TLSDESC_PAGE, + R_TLSGD, + R_TLSGD_PC, + R_TLSLD, + R_TLSLD_PC +}; + +template <class ELFT> struct Relocation { + RelExpr Expr; + uint32_t Type; + InputSectionBase<ELFT> *InputSec; + uint64_t Offset; + uint64_t Addend; + SymbolBody *Sym; +}; + +template <class ELFT> void scanRelocations(InputSection<ELFT> &); + +template <class ELFT> +void scanRelocations(InputSectionBase<ELFT> &, const typename ELFT::Shdr &); + +template <class ELFT> +static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) { + return 0; +} + +template <class ELFT> +static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) { + return Rel.r_addend; +} +} +} + +#endif diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp new file mode 100644 index 000000000000..559ec1be0e39 --- /dev/null +++ b/ELF/ScriptParser.cpp @@ -0,0 +1,163 @@ +//===- ScriptParser.cpp ---------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the base parser class for linker script and dynamic +// list. +// +//===----------------------------------------------------------------------===// + +#include "ScriptParser.h" +#include "Error.h" +#include "llvm/ADT/Twine.h" + +using namespace llvm; +using namespace lld; +using namespace lld::elf; + +// Returns the line that the character S[Pos] is in. +static StringRef getLine(StringRef S, size_t Pos) { + size_t Begin = S.rfind('\n', Pos); + size_t End = S.find('\n', Pos); + Begin = (Begin == StringRef::npos) ? 0 : Begin + 1; + if (End == StringRef::npos) + End = S.size(); + // rtrim for DOS-style newlines. + return S.substr(Begin, End - Begin).rtrim(); +} + +void ScriptParserBase::printErrorPos() { + StringRef Tok = Tokens[Pos == 0 ? 0 : Pos - 1]; + StringRef Line = getLine(Input, Tok.data() - Input.data()); + size_t Col = Tok.data() - Line.data(); + error(Line); + error(std::string(Col, ' ') + "^"); +} + +// We don't want to record cascading errors. Keep only the first one. +void ScriptParserBase::setError(const Twine &Msg) { + if (Error) + return; + if (Input.empty() || Tokens.empty()) { + error(Msg); + } else { + error("line " + Twine(getPos()) + ": " + Msg); + printErrorPos(); + } + Error = true; +} + +// Split S into linker script tokens. +std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) { + std::vector<StringRef> Ret; + for (;;) { + S = skipSpace(S); + if (S.empty()) + return Ret; + + // Quoted token + if (S.startswith("\"")) { + size_t E = S.find("\"", 1); + if (E == StringRef::npos) { + error("unclosed quote"); + return {}; + } + Ret.push_back(S.substr(1, E - 1)); + S = S.substr(E + 1); + continue; + } + + // Unquoted token + size_t Pos = S.find_first_not_of( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789_.$/\\~=+[]*?-:!<>"); + // A character that cannot start a word (which is usually a + // punctuation) forms a single character token. + if (Pos == 0) + Pos = 1; + Ret.push_back(S.substr(0, Pos)); + S = S.substr(Pos); + } +} + +// Skip leading whitespace characters or comments. +StringRef ScriptParserBase::skipSpace(StringRef S) { + for (;;) { + if (S.startswith("/*")) { + size_t E = S.find("*/", 2); + if (E == StringRef::npos) { + error("unclosed comment in a linker script"); + return ""; + } + S = S.substr(E + 2); + continue; + } + if (S.startswith("#")) { + size_t E = S.find('\n', 1); + if (E == StringRef::npos) + E = S.size() - 1; + S = S.substr(E + 1); + continue; + } + size_t Size = S.size(); + S = S.ltrim(); + if (S.size() == Size) + return S; + } +} + +// An erroneous token is handled as if it were the last token before EOF. +bool ScriptParserBase::atEOF() { return Error || Tokens.size() == Pos; } + +StringRef ScriptParserBase::next() { + if (Error) + return ""; + if (atEOF()) { + setError("unexpected EOF"); + return ""; + } + return Tokens[Pos++]; +} + +StringRef ScriptParserBase::peek() { + StringRef Tok = next(); + if (Error) + return ""; + --Pos; + return Tok; +} + +bool ScriptParserBase::skip(StringRef Tok) { + if (Error) + return false; + if (atEOF()) { + setError("unexpected EOF"); + return false; + } + if (Tokens[Pos] != Tok) + return false; + ++Pos; + return true; +} + +void ScriptParserBase::expect(StringRef Expect) { + if (Error) + return; + StringRef Tok = next(); + if (Tok != Expect) + setError(Expect + " expected, but got " + Tok); +} + +// Returns the current line number. +size_t ScriptParserBase::getPos() { + if (Pos == 0) + return 1; + const char *Begin = Input.data(); + const char *Tok = Tokens[Pos - 1].data(); + return StringRef(Begin, Tok - Begin).count('\n') + 1; +} diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h new file mode 100644 index 000000000000..20735f78da81 --- /dev/null +++ b/ELF/ScriptParser.h @@ -0,0 +1,49 @@ +//===- ScriptParser.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_SCRIPT_PARSER_H +#define LLD_ELF_SCRIPT_PARSER_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include <utility> +#include <vector> + +namespace lld { +namespace elf { + +class ScriptParserBase { +public: + explicit ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {} + explicit ScriptParserBase(std::vector<StringRef> Tokens) + : Input(""), Tokens(std::move(Tokens)) {} + +protected: + void setError(const Twine &Msg); + static std::vector<StringRef> tokenize(StringRef S); + static StringRef skipSpace(StringRef S); + bool atEOF(); + StringRef next(); + StringRef peek(); + bool skip(StringRef Tok); + void expect(StringRef Expect); + + size_t getPos(); + void printErrorPos(); + + StringRef Input; + std::vector<StringRef> Tokens; + size_t Pos = 0; + bool Error = false; +}; + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp new file mode 100644 index 000000000000..0c21e8819d6c --- /dev/null +++ b/ELF/Strings.cpp @@ -0,0 +1,98 @@ +//===- Strings.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Strings.h" +#include "Error.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" +#include <algorithm> + +#ifdef HAVE_CXXABI_H +#include <cxxabi.h> +#endif + +using namespace llvm; +using namespace lld; +using namespace lld::elf; + +// Returns true if S matches T. S can contain glob meta-characters. +// The asterisk ('*') matches zero or more characters, and the question +// mark ('?') matches one character. +bool elf::globMatch(StringRef S, StringRef T) { + for (;;) { + if (S.empty()) + return T.empty(); + if (S[0] == '*') { + S = S.substr(1); + if (S.empty()) + // Fast path. If a pattern is '*', it matches anything. + return true; + for (size_t I = 0, E = T.size(); I < E; ++I) + if (globMatch(S, T.substr(I))) + return true; + return false; + } + if (T.empty() || (S[0] != T[0] && S[0] != '?')) + return false; + S = S.substr(1); + T = T.substr(1); + } +} + +// Converts a hex string (e.g. "deadbeef") to a vector. +std::vector<uint8_t> elf::parseHex(StringRef S) { + std::vector<uint8_t> Hex; + while (!S.empty()) { + StringRef B = S.substr(0, 2); + S = S.substr(2); + uint8_t H; + if (B.getAsInteger(16, H)) { + error("not a hexadecimal value: " + B); + return {}; + } + Hex.push_back(H); + } + return Hex; +} + +static bool isAlpha(char C) { + return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; +} + +static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); } + +// Returns true if S is valid as a C language identifier. +bool elf::isValidCIdentifier(StringRef S) { + return !S.empty() && isAlpha(S[0]) && + std::all_of(S.begin() + 1, S.end(), isAlnum); +} + +// Returns the demangled C++ symbol name for Name. +std::string elf::demangle(StringRef Name) { +#if !defined(HAVE_CXXABI_H) + return Name; +#else + // __cxa_demangle can be used to demangle strings other than symbol + // names which do not necessarily start with "_Z". Name can be + // either a C or C++ symbol. Don't call __cxa_demangle if the name + // does not look like a C++ symbol name to avoid getting unexpected + // result for a C symbol that happens to match a mangled type name. + if (!Name.startswith("_Z")) + return Name; + + char *Buf = + abi::__cxa_demangle(Name.str().c_str(), nullptr, nullptr, nullptr); + if (!Buf) + return Name; + std::string S(Buf); + free(Buf); + return S; +#endif +} diff --git a/ELF/Strings.h b/ELF/Strings.h new file mode 100644 index 000000000000..4948e9dbd56b --- /dev/null +++ b/ELF/Strings.h @@ -0,0 +1,29 @@ +//===- Strings.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_STRINGS_H +#define LLD_COFF_STRINGS_H + +#include "lld/Core/LLVM.h" +#include <vector> + +namespace lld { +namespace elf { +bool globMatch(StringRef S, StringRef T); +std::vector<uint8_t> parseHex(StringRef S); +bool isValidCIdentifier(StringRef S); + +// Returns a demangled C++ symbol name. If Name is not a mangled +// name or the system does not provide __cxa_demangle function, +// it returns an unmodified string. +std::string demangle(StringRef Name); +} +} + +#endif diff --git a/ELF/SymbolListFile.cpp b/ELF/SymbolListFile.cpp new file mode 100644 index 000000000000..9e088025c1b7 --- /dev/null +++ b/ELF/SymbolListFile.cpp @@ -0,0 +1,168 @@ +//===- SymbolListFile.cpp -------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the parser/evaluator of the linker script. +// It does not construct an AST but consume linker script directives directly. +// Results are written to Driver or Config object. +// +//===----------------------------------------------------------------------===// + +#include "SymbolListFile.h" +#include "Config.h" +#include "ScriptParser.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +// Parse the --dynamic-list argument. A dynamic list is in the form +// +// { symbol1; symbol2; [...]; symbolN }; +// +// Multiple groups can be defined in the same file, and they are merged +// into a single group. + +class DynamicListParser final : public ScriptParserBase { +public: + DynamicListParser(StringRef S) : ScriptParserBase(S) {} + void run(); +}; + +void DynamicListParser::run() { + while (!atEOF()) { + expect("{"); + while (!Error) { + Config->DynamicList.push_back(next()); + expect(";"); + if (skip("}")) + break; + } + expect(";"); + } +} + +void elf::parseDynamicList(MemoryBufferRef MB) { + DynamicListParser(MB.getBuffer()).run(); +} + +// Parse the --version-script argument. We currently only accept the following +// version script syntax: +// +// { [ global: symbol1; symbol2; [...]; symbolN; ] local: *; }; +// +// No wildcards are supported, other than for the local entry. Symbol versioning +// is also not supported. + +class VersionScriptParser final : public ScriptParserBase { +public: + VersionScriptParser(StringRef S) : ScriptParserBase(S) {} + + void run(); + +private: + void parseExtern(std::vector<SymbolVersion> *Globals); + void parseVersion(StringRef VerStr); + void parseGlobal(StringRef VerStr); + void parseLocal(); +}; + +size_t elf::defineSymbolVersion(StringRef VerStr) { + // Identifiers start at 2 because 0 and 1 are reserved + // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants. + size_t VersionId = Config->VersionDefinitions.size() + 2; + Config->VersionDefinitions.push_back({VerStr, VersionId}); + return VersionId; +} + +void VersionScriptParser::parseVersion(StringRef VerStr) { + defineSymbolVersion(VerStr); + + if (skip("global:") || peek() != "local:") + parseGlobal(VerStr); + if (skip("local:")) + parseLocal(); + expect("}"); + + // Each version may have a parent version. For example, "Ver2" defined as + // "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This + // version hierarchy is, probably against your instinct, purely for human; the + // runtime doesn't care about them at all. In LLD, we simply skip the token. + if (!VerStr.empty() && peek() != ";") + next(); + expect(";"); +} + +void VersionScriptParser::parseLocal() { + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + expect("*"); + expect(";"); +} + +void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) { + expect("C++"); + expect("{"); + + for (;;) { + if (peek() == "}" || Error) + break; + Globals->push_back({next(), true}); + expect(";"); + } + + expect("}"); + expect(";"); +} + +void VersionScriptParser::parseGlobal(StringRef VerStr) { + std::vector<SymbolVersion> *Globals; + if (VerStr.empty()) + Globals = &Config->VersionScriptGlobals; + else + Globals = &Config->VersionDefinitions.back().Globals; + + for (;;) { + if (skip("extern")) + parseExtern(Globals); + + StringRef Cur = peek(); + if (Cur == "}" || Cur == "local:" || Error) + return; + next(); + Globals->push_back({Cur, false}); + expect(";"); + } +} + +void VersionScriptParser::run() { + StringRef Msg = "anonymous version definition is used in " + "combination with other version definitions"; + if (skip("{")) { + parseVersion(""); + if (!atEOF()) + setError(Msg); + return; + } + + while (!atEOF() && !Error) { + StringRef VerStr = next(); + if (VerStr == "{") { + setError(Msg); + return; + } + expect("{"); + parseVersion(VerStr); + } +} + +void elf::parseVersionScript(MemoryBufferRef MB) { + VersionScriptParser(MB.getBuffer()).run(); +} diff --git a/ELF/SymbolListFile.h b/ELF/SymbolListFile.h new file mode 100644 index 000000000000..cf3c4c639ea4 --- /dev/null +++ b/ELF/SymbolListFile.h @@ -0,0 +1,27 @@ +//===- SymbolListFile.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_SYMBOL_LIST_FILE_H +#define LLD_ELF_SYMBOL_LIST_FILE_H + +#include "lld/Core/LLVM.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace lld { +namespace elf { + +size_t defineSymbolVersion(StringRef Version); + +void parseDynamicList(MemoryBufferRef MB); +void parseVersionScript(MemoryBufferRef MB); + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 65f5dff9d7a3..78c1298df427 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -17,7 +17,11 @@ #include "SymbolTable.h" #include "Config.h" #include "Error.h" +#include "LinkerScript.h" +#include "Strings.h" +#include "SymbolListFile.h" #include "Symbols.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/StringSaver.h" using namespace llvm; @@ -25,40 +29,48 @@ using namespace llvm::object; using namespace llvm::ELF; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. -template <class ELFT> -static void checkCompatibility(InputFile *FileP) { - auto *F = dyn_cast<ELFFileBase<ELFT>>(FileP); - if (!F) - return; - if (F->getELFKind() == Config->EKind && F->getEMachine() == Config->EMachine) - return; +template <class ELFT> static bool isCompatible(InputFile *F) { + if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F)) + return true; + if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) + return true; StringRef A = F->getName(); StringRef B = Config->Emulation; if (B.empty()) B = Config->FirstElf->getName(); error(A + " is incompatible with " + B); + return false; } // Add symbols in File to the symbol table. template <class ELFT> void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) { InputFile *FileP = File.get(); - checkCompatibility<ELFT>(FileP); + if (!isCompatible<ELFT>(FileP)) + return; // .a file if (auto *F = dyn_cast<ArchiveFile>(FileP)) { ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release())); - F->parse(); - for (Lazy &Sym : F->getLazySymbols()) - addLazy(&Sym); + F->parse<ELFT>(); return; } + // Lazy object file + if (auto *F = dyn_cast<LazyObjectFile>(FileP)) { + LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release())); + F->parse<ELFT>(); + return; + } + + if (Config->Trace) + outs() << getFilename(FileP) << "\n"; + // .so file if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) { // DSOs are uniquified not by filename but by soname. @@ -68,189 +80,443 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) { SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release())); F->parseRest(); - for (SharedSymbol<ELFT> &B : F->getSharedSymbols()) - resolve(&B); return; } - // .o file + // LLVM bitcode file + if (auto *F = dyn_cast<BitcodeFile>(FileP)) { + BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release())); + F->parse<ELFT>(ComdatGroups); + return; + } + + // Regular object file auto *F = cast<ObjectFile<ELFT>>(FileP); ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release())); F->parse(ComdatGroups); - for (SymbolBody *B : F->getSymbols()) - resolve(B); } -// Add an undefined symbol. -template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) { - auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false); - resolve(Sym); - return Sym; -} +// This function is where all the optimizations of link-time +// optimization happens. When LTO is in use, some input files are +// not in native object file format but in the LLVM bitcode format. +// This function compiles bitcode files into a few big native files +// using LLVM functions and replaces bitcode symbols with the results. +// Because all bitcode files that consist of a program are passed +// to the compiler at once, it can do whole-program optimization. +template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() { + if (BitcodeFiles.empty()) + return; -// Add an undefined symbol. Unlike addUndefined, that symbol -// doesn't have to be resolved, thus "opt" (optional). -template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) { - auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true); - resolve(Sym); - return Sym; -} + // Compile bitcode files. + Lto.reset(new BitcodeCompiler); + for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles) + Lto->add(*F); + std::vector<std::unique_ptr<InputFile>> IFs = Lto->compile(); -template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addAbsolute(StringRef Name, Elf_Sym &ESym) { - // Pass nullptr because absolute symbols have no corresponding input sections. - auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr); - resolve(Sym); - return Sym; + // Replace bitcode symbols. + for (auto &IF : IFs) { + ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release()); + + DenseSet<StringRef> DummyGroups; + Obj->parse(DummyGroups); + ObjectFiles.emplace_back(Obj); + } } template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addSynthetic(StringRef Name, - OutputSectionBase<ELFT> &Section, - uintX_t Value) { - auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Value, Section); - resolve(Sym); - return Sym; +DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name, + uint8_t Visibility) { + return cast<DefinedRegular<ELFT>>( + addRegular(Name, STB_GLOBAL, Visibility)->body()); } // Add Name as an "ignored" symbol. An ignored symbol is a regular -// linker-synthesized defined symbol, but it is not recorded to the output -// file's symbol table. Such symbols are useful for some linker-defined symbols. +// linker-synthesized defined symbol, but is only defined if needed. template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) { - return addAbsolute(Name, ElfSym<ELFT>::IgnoredWeak); +DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name, + uint8_t Visibility) { + if (!find(Name)) + return nullptr; + return addAbsolute(Name, Visibility); } -// The 'strong' variant of the addIgnored. Adds symbol which has a global -// binding and cannot be substituted. -template <class ELFT> -SymbolBody *SymbolTable<ELFT>::addIgnoredStrong(StringRef Name) { - return addAbsolute(Name, ElfSym<ELFT>::Ignored); +// Set a flag for --trace-symbol so that we can print out a log message +// if a new symbol with the same name is inserted into the symbol table. +template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) { + Symtab.insert({Name, {-1, true}}); } // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) { - if (Symtab.count(Name) == 0) + SymbolBody *B = find(Name); + if (!B) return; StringSaver Saver(Alloc); - Symbol *Sym = addUndefined(Name)->getSymbol(); - Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol(); - Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol(); - Real->Body = Sym->Body; - Sym->Body = Wrap->Body; + Symbol *Sym = B->symbol(); + Symbol *Real = addUndefined(Saver.save("__real_" + Name)); + Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); + // We rename symbols by replacing the old symbol's SymbolBody with the new + // symbol's SymbolBody. This causes all SymbolBody pointers referring to the + // old symbol to instead refer to the new symbol. + memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body)); + memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); +} + +static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { + if (VA == STV_DEFAULT) + return VB; + if (VB == STV_DEFAULT) + return VA; + return std::min(VA, VB); } -// Returns a file from which symbol B was created. -// If B does not belong to any file, returns a nullptr. +// Find an existing symbol or create and insert a new one. template <class ELFT> -ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) { - for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) { - ArrayRef<SymbolBody *> Syms = F->getSymbols(); - if (std::find(Syms.begin(), Syms.end(), B) != Syms.end()) - return F.get(); +std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) { + auto P = Symtab.insert({Name, {(int)SymVector.size(), false}}); + SymIndex &V = P.first->second; + bool IsNew = P.second; + + if (V.Idx == -1) { + IsNew = true; + V = {(int)SymVector.size(), true}; + } + + Symbol *Sym; + if (IsNew) { + Sym = new (Alloc) Symbol; + Sym->Binding = STB_WEAK; + Sym->Visibility = STV_DEFAULT; + Sym->IsUsedInRegularObj = false; + Sym->ExportDynamic = false; + Sym->VersionId = Config->DefaultSymbolVersion; + Sym->Traced = V.Traced; + SymVector.push_back(Sym); + } else { + Sym = SymVector[V.Idx]; } - return nullptr; + return {Sym, IsNew}; +} + +// Find an existing symbol or create and insert a new one, then apply the given +// attributes. +template <class ELFT> +std::pair<Symbol *, bool> +SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility, + bool CanOmitFromDynSym, bool IsUsedInRegularObj, + InputFile *File) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + // Merge in the new symbol's visibility. + S->Visibility = getMinVisibility(S->Visibility, Visibility); + if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) + S->ExportDynamic = true; + if (IsUsedInRegularObj) + S->IsUsedInRegularObj = true; + if (!WasInserted && S->body()->Type != SymbolBody::UnknownType && + ((Type == STT_TLS) != S->body()->isTls())) + error("TLS attribute mismatch for symbol: " + + conflictMsg(S->body(), File)); + + return {S, WasInserted}; } // Construct a string in the form of "Sym in File1 and File2". // Used to construct an error message. -template <class ELFT> -std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) { - ELFFileBase<ELFT> *OldFile = findFile(Old); - ELFFileBase<ELFT> *NewFile = findFile(New); +template <typename ELFT> +std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Existing, + InputFile *NewFile) { + std::string Sym = Existing->getName(); + if (Config->Demangle) + Sym = demangle(Sym); + return Sym + " in " + getFilename(Existing->File) + " and " + + getFilename(NewFile); +} - StringRef Sym = Old->getName(); - StringRef F1 = OldFile ? OldFile->getName() : "(internal)"; - StringRef F2 = NewFile ? NewFile->getName() : "(internal)"; - return (Sym + " in " + F1 + " and " + F2).str(); +template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) { + return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, + /*CanOmitFromDynSym*/ false, /*File*/ nullptr); } -// This function resolves conflicts if there's an existing symbol with -// the same name. Decisions are made based on symbol type. -template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) { - Symbol *Sym = insert(New); - if (Sym->Body == New) - return; +template <class ELFT> +Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, + InputFile *File) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(Name, Type, StOther & 3, CanOmitFromDynSym, + /*IsUsedInRegularObj*/ !File || !isa<BitcodeFile>(File), File); + if (WasInserted) { + S->Binding = Binding; + replaceBody<Undefined>(S, Name, StOther, Type, File); + return S; + } + if (Binding != STB_WEAK) { + if (S->body()->isShared() || S->body()->isLazy()) + S->Binding = Binding; + if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body())) + SS->file()->IsUsed = true; + } + if (auto *L = dyn_cast<Lazy>(S->body())) { + // An undefined weak will not fetch archive members, but we have to remember + // its type. See also comment in addLazyArchive. + if (S->isWeak()) + L->Type = Type; + else if (auto F = L->fetch()) + addFile(std::move(F)); + } + return S; +} - SymbolBody *Existing = Sym->Body; +// We have a new defined symbol with the specified binding. Return 1 if the new +// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are +// strong defined symbols. +static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { + if (WasInserted) + return 1; + SymbolBody *Body = S->body(); + if (Body->isLazy() || Body->isUndefined() || Body->isShared()) + return 1; + if (Binding == STB_WEAK) + return -1; + if (S->isWeak()) + return 1; + return 0; +} - if (Lazy *L = dyn_cast<Lazy>(Existing)) { - if (auto *Undef = dyn_cast<Undefined>(New)) { - addMemberFile(Undef, L); - return; +// We have a new non-common defined symbol with the specified binding. Return 1 +// if the new symbol should win, -1 if the new symbol should lose, or 0 if there +// is a conflict. If the new symbol wins, also update the binding. +static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding) { + if (int Cmp = compareDefined(S, WasInserted, Binding)) { + if (Cmp > 0) + S->Binding = Binding; + return Cmp; + } + if (isa<DefinedCommon>(S->body())) { + // Non-common symbols take precedence over common symbols. + if (Config->WarnCommon) + warning("common " + S->body()->getName() + " is overridden"); + return 1; + } + return 0; +} + +template <class ELFT> +Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size, + uint64_t Alignment, uint8_t Binding, + uint8_t StOther, uint8_t Type, + InputFile *File) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false, + /*IsUsedInRegularObj*/ true, File); + int Cmp = compareDefined(S, WasInserted, Binding); + if (Cmp > 0) { + S->Binding = Binding; + replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File); + } else if (Cmp == 0) { + auto *C = dyn_cast<DefinedCommon>(S->body()); + if (!C) { + // Non-common symbols take precedence over common symbols. + if (Config->WarnCommon) + warning("common " + S->body()->getName() + " is overridden"); + return S; } - // Found a definition for something also in an archive. - // Ignore the archive definition. - Sym->Body = New; - return; + + if (Config->WarnCommon) + warning("multiple common of " + S->body()->getName()); + + C->Size = std::max(C->Size, Size); + C->Alignment = std::max(C->Alignment, Alignment); } + return S; +} - if (New->isTls() != Existing->isTls()) - error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New)); +template <class ELFT> +void SymbolTable<ELFT>::reportDuplicate(SymbolBody *Existing, + InputFile *NewFile) { + std::string Msg = "duplicate symbol: " + conflictMsg(Existing, NewFile); + if (Config->AllowMultipleDefinition) + warning(Msg); + else + error(Msg); +} - // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, - // equivalent (conflicting), or more preferable, respectively. - int Comp = Existing->compare<ELFT>(New); - if (Comp == 0) { - std::string S = "duplicate symbol: " + conflictMsg(Existing, New); - if (!Config->AllowMultipleDefinition) - error(S); - warning(S); - return; +template <typename ELFT> +Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym, + InputSectionBase<ELFT> *Section) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(Name, Sym.getType(), Sym.getVisibility(), + /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, + Section ? Section->getFile() : nullptr); + int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding()); + if (Cmp > 0) + replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section); + else if (Cmp == 0) + reportDuplicate(S->body(), Section->getFile()); + return S; +} + +template <typename ELFT> +Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding, + uint8_t StOther) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false, + /*IsUsedInRegularObj*/ true, nullptr); + int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); + if (Cmp > 0) + replaceBody<DefinedRegular<ELFT>>(S, Name, StOther); + else if (Cmp == 0) + reportDuplicate(S->body(), nullptr); + return S; +} + +template <typename ELFT> +Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N, + OutputSectionBase<ELFT> *Section, + uintX_t Value) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(N, STT_NOTYPE, STV_HIDDEN, /*CanOmitFromDynSym*/ false, + /*IsUsedInRegularObj*/ true, nullptr); + int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL); + if (Cmp > 0) + replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section); + else if (Cmp == 0) + reportDuplicate(S->body(), nullptr); + return S; +} + +template <typename ELFT> +void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name, + const Elf_Sym &Sym, + const typename ELFT::Verdef *Verdef) { + // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT + // as the visibility, which will leave the visibility in the symbol table + // unchanged. + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = + insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, + /*IsUsedInRegularObj*/ false, F); + // Make sure we preempt DSO symbols with default visibility. + if (Sym.getVisibility() == STV_DEFAULT) + S->ExportDynamic = true; + if (WasInserted || isa<Undefined>(S->body())) { + replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef); + if (!S->isWeak()) + F->IsUsed = true; } - if (Comp < 0) - Sym->Body = New; } -// Find an existing symbol or create and insert a new one. -template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) { - StringRef Name = New->getName(); - Symbol *&Sym = Symtab[Name]; - if (!Sym) - Sym = new (Alloc) Symbol{New}; - New->setBackref(Sym); - return Sym; +template <class ELFT> +Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, BitcodeFile *F) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym, + /*IsUsedInRegularObj*/ false, F); + int Cmp = + compareDefinedNonCommon(S, WasInserted, IsWeak ? STB_WEAK : STB_GLOBAL); + if (Cmp > 0) + replaceBody<DefinedBitcode>(S, Name, StOther, Type, F); + else if (Cmp == 0) + reportDuplicate(S->body(), F); + return S; } template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) { auto It = Symtab.find(Name); if (It == Symtab.end()) return nullptr; - return It->second->Body; + SymIndex V = It->second; + if (V.Idx == -1) + return nullptr; + return SymVector[V.Idx]->body(); +} + +// Returns a list of defined symbols that match with a given glob pattern. +template <class ELFT> +std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) { + std::vector<SymbolBody *> Res; + for (Symbol *Sym : SymVector) { + SymbolBody *B = Sym->body(); + if (!B->isUndefined() && globMatch(Pattern, B->getName())) + Res.push_back(B); + } + return Res; } -template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) { - Symbol *Sym = insert(L); - if (Sym->Body == L) +template <class ELFT> +void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, + const object::Archive::Symbol Sym) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Sym.getName()); + if (WasInserted) { + replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType); return; - if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) { - Sym->Body = L; - addMemberFile(Undef, L); } + if (!S->body()->isUndefined()) + return; + + // Weak undefined symbols should not fetch members from archives. If we were + // to keep old symbol we would not know that an archive member was available + // if a strong undefined symbol shows up afterwards in the link. If a strong + // undefined symbol never shows up, this lazy symbol will get to the end of + // the link and must be treated as the weak undefined one. We already marked + // this symbol as used when we added it to the symbol table, but we also need + // to preserve its type. FIXME: Move the Type field to Symbol. + if (S->isWeak()) { + replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type); + return; + } + MemoryBufferRef MBRef = F->getMember(&Sym); + if (!MBRef.getBuffer().empty()) + addFile(createObjectFile(MBRef, F->getName())); } template <class ELFT> -void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) { - // Weak undefined symbols should not fetch members from archives. - // If we were to keep old symbol we would not know that an archive member was - // available if a strong undefined symbol shows up afterwards in the link. - // If a strong undefined symbol never shows up, this lazy symbol will - // get to the end of the link and must be treated as the weak undefined one. - // We set UsedInRegularObj in a similar way to what is done with shared - // symbols and mark it as weak to reduce how many special cases are needed. - if (Undef->isWeak()) { - L->setUsedInRegularObj(); - L->setWeak(); +void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { + replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType); return; } + if (!S->body()->isUndefined()) + return; + + // See comment for addLazyArchive above. + if (S->isWeak()) { + replaceBody<LazyObject>(S, Name, Obj, S->body()->Type); + } else { + MemoryBufferRef MBRef = Obj.getBuffer(); + if (!MBRef.getBuffer().empty()) + addFile(createObjectFile(MBRef)); + } +} - // Fetch a member file that has the definition for L. - // getMember returns nullptr if the member was already read from the library. - if (std::unique_ptr<InputFile> File = L->getMember()) - addFile(std::move(File)); +// Process undefined (-u) flags by loading lazy symbols named by those flags. +template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() { + for (StringRef S : Config->Undefined) + if (auto *L = dyn_cast_or_null<Lazy>(find(S))) + if (std::unique_ptr<InputFile> File = L->fetch()) + addFile(std::move(File)); } // This function takes care of the case in which shared libraries depend on @@ -265,10 +531,183 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() { for (StringRef U : File->getUndefinedSymbols()) if (SymbolBody *Sym = find(U)) if (Sym->isDefined()) - Sym->setUsedInDynamicReloc(); + Sym->symbol()->ExportDynamic = true; +} + +// This function process the dynamic list option by marking all the symbols +// to be exported in the dynamic table. +template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() { + for (StringRef S : Config->DynamicList) + if (SymbolBody *B = find(S)) + B->symbol()->ExportDynamic = true; +} + +static bool hasWildcard(StringRef S) { + return S.find_first_of("?*") != StringRef::npos; +} + +static void setVersionId(SymbolBody *Body, StringRef VersionName, + StringRef Name, uint16_t Version) { + if (!Body || Body->isUndefined()) { + if (Config->NoUndefinedVersion) + error("version script assignment of " + VersionName + " to symbol " + + Name + " failed: symbol not defined"); + return; + } + + Symbol *Sym = Body->symbol(); + if (Sym->VersionId != Config->DefaultSymbolVersion) + warning("duplicate symbol " + Name + " in version script"); + Sym->VersionId = Version; +} + +template <class ELFT> +std::map<std::string, SymbolBody *> SymbolTable<ELFT>::getDemangledSyms() { + std::map<std::string, SymbolBody *> Result; + for (Symbol *Sym : SymVector) { + SymbolBody *B = Sym->body(); + Result[demangle(B->getName())] = B; + } + return Result; +} + +static bool hasExternCpp() { + for (VersionDefinition &V : Config->VersionDefinitions) + for (SymbolVersion Sym : V.Globals) + if (Sym.IsExternCpp) + return true; + return false; +} + +// This function processes the --version-script option by marking all global +// symbols with the VersionScriptGlobal flag, which acts as a filter on the +// dynamic symbol table. +template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { + // If version script does not contain versions declarations, + // we just should mark global symbols. + if (!Config->VersionScriptGlobals.empty()) { + for (SymbolVersion &Sym : Config->VersionScriptGlobals) + if (SymbolBody *B = find(Sym.Name)) + B->symbol()->VersionId = VER_NDX_GLOBAL; + return; + } + + if (Config->VersionDefinitions.empty()) + return; + + // If we have symbols version declarations, we should + // assign version references for each symbol. + // Current rules are: + // * If there is an exact match for the mangled name or we have extern C++ + // exact match, then we use it. + // * Otherwise, we look through the wildcard patterns. We look through the + // version tags in reverse order. We use the first match we find (the last + // matching version tag in the file). + // Handle exact matches and build a map of demangled externs for + // quick search during next step. + std::map<std::string, SymbolBody *> Demangled; + if (hasExternCpp()) + Demangled = getDemangledSyms(); + + for (VersionDefinition &V : Config->VersionDefinitions) { + for (SymbolVersion Sym : V.Globals) { + if (hasWildcard(Sym.Name)) + continue; + SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name); + setVersionId(B, V.Name, Sym.Name, V.Id); + } + } + + // Handle wildcards. + for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) { + VersionDefinition &V = Config->VersionDefinitions[I]; + for (SymbolVersion &Sym : V.Globals) + if (hasWildcard(Sym.Name)) + for (SymbolBody *B : findAll(Sym.Name)) + if (B->symbol()->VersionId == Config->DefaultSymbolVersion) + B->symbol()->VersionId = V.Id; + } +} + +// Returns the size of the longest version name. +static int getMaxVersionLen() { + size_t Len = 0; + for (VersionDefinition &V : Config->VersionDefinitions) + Len = std::max(Len, V.Name.size()); + return Len; +} + +// Parses a symbol name in the form of <name>@<version> or <name>@@<version>. +static std::pair<StringRef, uint16_t> +getSymbolVersion(SymbolBody *B, int MaxVersionLen) { + StringRef S = B->getName(); + + // MaxVersionLen was passed so that we don't need to scan + // all characters in a symbol name. It is effective because + // versions are usually short and symbol names can be very long. + size_t Pos = S.find('@', std::max(0, int(S.size()) - MaxVersionLen - 2)); + if (Pos == 0 || Pos == StringRef::npos) + return {"", 0}; + + StringRef Name = S.substr(0, Pos); + StringRef Verstr = S.substr(Pos + 1); + if (Verstr.empty()) + return {"", 0}; + + // '@@' in a symbol name means the default version. + // It is usually the most recent one. + bool IsDefault = (Verstr[0] == '@'); + if (IsDefault) + Verstr = Verstr.substr(1); + + for (VersionDefinition &V : Config->VersionDefinitions) { + if (V.Name == Verstr) + return {Name, IsDefault ? V.Id : (V.Id | VERSYM_HIDDEN)}; + } + + // It is an error if the specified version was not defined. + error("symbol " + S + " has undefined version " + Verstr); + return {"", 0}; +} + +// Versions are usually assigned to symbols using version scripts, +// but there's another way to assign versions to symbols. +// If a symbol name contains '@', the string after it is not +// actually a part of the symbol name but specifies a version. +// This function takes care of it. +template <class ELFT> void SymbolTable<ELFT>::scanSymbolVersions() { + if (Config->VersionDefinitions.empty()) + return; + + int MaxVersionLen = getMaxVersionLen(); + + // Unfortunately there's no way other than iterating over all + // symbols to look for '@' characters in symbol names. + // So this is inherently slow. A good news is that we do this + // only when versions have been defined. + for (Symbol *Sym : SymVector) { + // Symbol versions for exported symbols are by nature + // only for defined global symbols. + SymbolBody *B = Sym->body(); + if (!B->isDefined()) + continue; + uint8_t Visibility = B->getVisibility(); + if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) + continue; + + // Look for '@' in the symbol name. + StringRef Name; + uint16_t Version; + std::tie(Name, Version) = getSymbolVersion(B, MaxVersionLen); + if (Name.empty()) + continue; + + B->setName(Name); + Sym->VersionId = Version; + } } -template class elf2::SymbolTable<ELF32LE>; -template class elf2::SymbolTable<ELF32BE>; -template class elf2::SymbolTable<ELF64LE>; -template class elf2::SymbolTable<ELF64BE>; +template class elf::SymbolTable<ELF32LE>; +template class elf::SymbolTable<ELF32BE>; +template class elf::SymbolTable<ELF64LE>; +template class elf::SymbolTable<ELF64BE>; diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 16ed821bf01a..40415b645a44 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -11,14 +11,16 @@ #define LLD_ELF_SYMBOL_TABLE_H #include "InputFiles.h" -#include "llvm/ADT/MapVector.h" +#include "LTO.h" +#include "llvm/ADT/DenseMap.h" namespace lld { -namespace elf2 { +namespace elf { class Lazy; template <class ELFT> class OutputSectionBase; struct Symbol; -class Undefined; + +typedef llvm::CachedHash<StringRef> SymName; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive @@ -29,17 +31,18 @@ class Undefined; // conflicts. For example, obviously, a defined symbol is better than // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition -// to replace the lazy symbol. The logic is implemented in resolve(). +// to replace the lazy symbol. The logic is implemented in the +// add*() functions, which are called by input files as they are parsed. There +// is one add* function per symbol type. template <class ELFT> class SymbolTable { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; public: void addFile(std::unique_ptr<InputFile> File); + void addCombinedLtoObject(); - const llvm::MapVector<StringRef, Symbol *> &getSymbols() const { - return Symtab; - } + llvm::ArrayRef<Symbol *> getSymbols() const { return SymVector; } const std::vector<std::unique_ptr<ObjectFile<ELFT>>> &getObjectFiles() const { return ObjectFiles; @@ -49,34 +52,69 @@ public: return SharedFiles; } - SymbolBody *addUndefined(StringRef Name); - SymbolBody *addUndefinedOpt(StringRef Name); - SymbolBody *addAbsolute(StringRef Name, Elf_Sym &ESym); - SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section, - uintX_t Value); - SymbolBody *addIgnored(StringRef Name); - SymbolBody *addIgnoredStrong(StringRef Name); + DefinedRegular<ELFT> *addAbsolute(StringRef Name, + uint8_t Visibility = llvm::ELF::STV_HIDDEN); + DefinedRegular<ELFT> *addIgnored(StringRef Name, + uint8_t Visibility = llvm::ELF::STV_HIDDEN); + + Symbol *addUndefined(StringRef Name); + Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, + uint8_t Type, bool CanOmitFromDynSym, InputFile *File); + + Symbol *addRegular(StringRef Name, const Elf_Sym &Sym, + InputSectionBase<ELFT> *Section); + Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther); + Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> *Section, + uintX_t Value); + void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, + const typename ELFT::Verdef *Verdef); + void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); + void addLazyObject(StringRef Name, LazyObjectFile &Obj); + Symbol *addBitcode(StringRef Name, bool IsWeak, uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, BitcodeFile *File); + + Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment, + uint8_t Binding, uint8_t StOther, uint8_t Type, + InputFile *File); + + void scanUndefinedFlags(); void scanShlibUndefined(); + void scanDynamicList(); + void scanVersionScript(); + void scanSymbolVersions(); + SymbolBody *find(StringRef Name); + + void trace(StringRef Name); void wrap(StringRef Name); - ELFFileBase<ELFT> *findFile(SymbolBody *B); private: - Symbol *insert(SymbolBody *New); - void addLazy(Lazy *New); - void addMemberFile(Undefined *Undef, Lazy *L); - void resolve(SymbolBody *Body); - std::string conflictMsg(SymbolBody *Old, SymbolBody *New); + std::vector<SymbolBody *> findAll(StringRef Pattern); + std::pair<Symbol *, bool> insert(StringRef Name); + std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type, + uint8_t Visibility, bool CanOmitFromDynSym, + bool IsUsedInRegularObj, InputFile *File); + + std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile); + void reportDuplicate(SymbolBody *Existing, InputFile *NewFile); + + std::map<std::string, SymbolBody *> getDemangledSyms(); + + struct SymIndex { + int Idx : 31; + unsigned Traced : 1; + }; // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. // The default hashing of StringRef produces different results on 32 and 64 - // bit systems so we use a MapVector. That is arbitrary, deterministic but - // a bit inefficient. + // bit systems so we use a map to a vector. That is arbitrary, deterministic + // but a bit inefficient. // FIXME: Experiment with passing in a custom hashing or sorting the symbols // once symbol resolution is finished. - llvm::MapVector<StringRef, Symbol *> Symtab; + llvm::DenseMap<SymName, SymIndex> Symtab; + std::vector<Symbol *> SymVector; llvm::BumpPtrAllocator Alloc; // Comdat groups define "link once" sections. If two comdat groups have the @@ -87,13 +125,20 @@ private: // The symbol table owns all file objects. std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles; std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles; + std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles; std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles; + std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles; // Set of .so files to not link the same shared object file more than once. llvm::DenseSet<StringRef> SoNames; + + std::unique_ptr<BitcodeCompiler> Lto; }; -} // namespace elf2 +template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; }; +template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X; + +} // namespace elf } // namespace lld #endif diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 3c864cbe2b67..d6a605d11183 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -8,9 +8,11 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "InputSection.h" #include "Error.h" #include "InputFiles.h" +#include "InputSection.h" +#include "OutputSections.h" +#include "Target.h" #include "llvm/ADT/STLExtras.h" @@ -19,131 +21,316 @@ using namespace llvm::object; using namespace llvm::ELF; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; + +template <class ELFT> +static typename ELFT::uint getSymVA(const SymbolBody &Body, + typename ELFT::uint &Addend) { + typedef typename ELFT::uint uintX_t; + + switch (Body.kind()) { + case SymbolBody::DefinedSyntheticKind: { + auto &D = cast<DefinedSynthetic<ELFT>>(Body); + const OutputSectionBase<ELFT> *Sec = D.Section; + if (!Sec) + return D.Value; + if (D.Value == DefinedSynthetic<ELFT>::SectionEnd) + return Sec->getVA() + Sec->getSize(); + return Sec->getVA() + D.Value; + } + case SymbolBody::DefinedRegularKind: { + auto &D = cast<DefinedRegular<ELFT>>(Body); + InputSectionBase<ELFT> *SC = D.Section; + + // According to the ELF spec reference to a local symbol from outside + // the group are not allowed. Unfortunately .eh_frame breaks that rule + // and must be treated specially. For now we just replace the symbol with + // 0. + if (SC == &InputSection<ELFT>::Discarded) + return 0; -static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { - if (VA == STV_DEFAULT) - return VB; - if (VB == STV_DEFAULT) + // This is an absolute symbol. + if (!SC) + return D.Value; + + uintX_t Offset = D.Value; + if (D.isSection()) { + Offset += Addend; + Addend = 0; + } + uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset); + if (D.isTls()) + return VA - Out<ELFT>::TlsPhdr->p_vaddr; return VA; - return std::min(VA, VB); + } + case SymbolBody::DefinedCommonKind: + return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss; + case SymbolBody::SharedKind: { + auto &SS = cast<SharedSymbol<ELFT>>(Body); + if (!SS.NeedsCopyOrPltAddr) + return 0; + if (SS.isFunc()) + return Body.getPltVA<ELFT>(); + return Out<ELFT>::Bss->getVA() + SS.OffsetInBss; + } + case SymbolBody::UndefinedKind: + return 0; + case SymbolBody::LazyArchiveKind: + case SymbolBody::LazyObjectKind: + assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); + return 0; + case SymbolBody::DefinedBitcodeKind: + llvm_unreachable("should have been replaced"); + } + llvm_unreachable("invalid symbol kind"); } -// Returns 1, 0 or -1 if this symbol should take precedence -// over the Other, tie or lose, respectively. -template <class ELFT> int SymbolBody::compare(SymbolBody *Other) { - typedef typename ELFFile<ELFT>::uintX_t uintX_t; - assert(!isLazy() && !Other->isLazy()); - std::pair<bool, bool> L(isDefined(), !isWeak()); - std::pair<bool, bool> R(Other->isDefined(), !Other->isWeak()); +SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, + uint8_t Type) + : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), + IsInGlobalMipsGot(false), Type(Type), StOther(StOther), + NameOffset(NameOffset) {} + +SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type) + : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), + IsInGlobalMipsGot(false), Type(Type), StOther(StOther), + Name({Name.data(), Name.size()}) {} - // Normalize - if (L > R) - return -Other->compare<ELFT>(this); +StringRef SymbolBody::getName() const { + assert(!isLocal()); + return StringRef(Name.S, Name.Len); +} - Visibility = Other->Visibility = - getMinVisibility(Visibility, Other->Visibility); +void SymbolBody::setName(StringRef S) { + Name.S = S.data(); + Name.Len = S.size(); +} - if (IsUsedInRegularObj || Other->IsUsedInRegularObj) - IsUsedInRegularObj = Other->IsUsedInRegularObj = true; +// Returns true if a symbol can be replaced at load-time by a symbol +// with the same name defined in other ELF executable or DSO. +bool SymbolBody::isPreemptible() const { + if (isLocal()) + return false; - if (L != R) - return -1; - if (!L.first || !L.second) - return 1; + // Shared symbols resolve to the definition in the DSO. The exceptions are + // symbols with copy relocations (which resolve to .bss) or preempt plt + // entries (which resolve to that plt entry). if (isShared()) - return -1; - if (Other->isShared()) - return 1; - if (isCommon()) { - if (!Other->isCommon()) - return -1; - auto *ThisC = cast<DefinedCommon>(this); - auto *OtherC = cast<DefinedCommon>(Other); - uintX_t Align = std::max(ThisC->MaxAlignment, OtherC->MaxAlignment); - if (ThisC->Size >= OtherC->Size) { - ThisC->MaxAlignment = Align; - return 1; - } - OtherC->MaxAlignment = Align; - return -1; - } - if (Other->isCommon()) - return 1; + return !NeedsCopyOrPltAddr; + + // That's all that can be preempted in a non-DSO. + if (!Config->Shared) + return false; + + // Only symbols that appear in dynsym can be preempted. + if (!symbol()->includeInDynsym()) + return false; + + // Only default visibility symbols can be preempted. + if (symbol()->Visibility != STV_DEFAULT) + return false; + + // -Bsymbolic means that definitions are not preempted. + if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) + return !isDefined(); + return true; +} + +template <class ELFT> bool SymbolBody::hasThunk() const { + if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) + return DR->ThunkData != nullptr; + if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) + return S->ThunkData != nullptr; + return false; +} + +template <class ELFT> +typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const { + typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend); + return OutVA + Addend; +} + +template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const { + return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>(); +} + +template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const { + return GotIndex * Target->GotEntrySize; +} + +template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const { + return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>(); +} + +template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const { + return GotPltIndex * Target->GotPltEntrySize; +} + +template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const { + return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize + + PltIndex * Target->PltEntrySize; +} + +template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const { + if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) + return DR->ThunkData->getVA(); + if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) + return S->ThunkData->getVA(); + fatal("getThunkVA() not supported for Symbol class\n"); +} + +template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { + if (const auto *C = dyn_cast<DefinedCommon>(this)) + return C->Size; + if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) + return DR->Size; + if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) + return S->Sym.st_size; return 0; } -Defined::Defined(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, - bool IsTls) - : SymbolBody(K, Name, IsWeak, Visibility, IsTls) {} +Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type) + : SymbolBody(K, Name, StOther, Type) {} -Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak, - uint8_t Visibility, bool IsTls) - : SymbolBody(K, N, IsWeak, Visibility, IsTls), CanKeepUndefined(false) {} +Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type) + : SymbolBody(K, NameOffset, StOther, Type) {} -Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility, - bool CanKeepUndefined) - : Undefined(SymbolBody::UndefinedKind, N, IsWeak, Visibility, - /*IsTls*/ false) { - this->CanKeepUndefined = CanKeepUndefined; +DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, + BitcodeFile *F) + : Defined(DefinedBitcodeKind, Name, StOther, Type) { + this->File = F; } -template <typename ELFT> -UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym) - : Undefined(SymbolBody::UndefinedElfKind, N, - Sym.getBinding() == llvm::ELF::STB_WEAK, Sym.getVisibility(), - Sym.getType() == llvm::ELF::STT_TLS), - Sym(Sym) {} +bool DefinedBitcode::classof(const SymbolBody *S) { + return S->kind() == DefinedBitcodeKind; +} + +Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type, + InputFile *File) + : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) { + this->File = File; +} + +Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, + InputFile *File) + : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) { + this->File = File; +} template <typename ELFT> DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value, - OutputSectionBase<ELFT> &Section) - : Defined(SymbolBody::DefinedSyntheticKind, N, false, STV_DEFAULT, false), + OutputSectionBase<ELFT> *Section) + : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */), Value(Value), Section(Section) {} DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, - bool IsWeak, uint8_t Visibility) - : Defined(SymbolBody::DefinedCommonKind, N, IsWeak, Visibility, false) { - MaxAlignment = Alignment; - this->Size = Size; + uint8_t StOther, uint8_t Type, InputFile *File) + : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type), + Alignment(Alignment), Size(Size) { + this->File = File; +} + +std::unique_ptr<InputFile> Lazy::fetch() { + if (auto *S = dyn_cast<LazyArchive>(this)) + return S->fetch(); + return cast<LazyObject>(this)->fetch(); } -std::unique_ptr<InputFile> Lazy::getMember() { - MemoryBufferRef MBRef = File->getMember(&Sym); +LazyArchive::LazyArchive(ArchiveFile &File, + const llvm::object::Archive::Symbol S, uint8_t Type) + : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) { + this->File = &File; +} + +LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) + : Lazy(LazyObjectKind, Name, Type) { + this->File = &File; +} + +std::unique_ptr<InputFile> LazyArchive::fetch() { + MemoryBufferRef MBRef = file()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr<InputFile>(nullptr); + return createObjectFile(MBRef, file()->getName()); +} + +std::unique_ptr<InputFile> LazyObject::fetch() { + MemoryBufferRef MBRef = file()->getBuffer(); + if (MBRef.getBuffer().empty()) + return std::unique_ptr<InputFile>(nullptr); return createObjectFile(MBRef); } -template <class ELFT> static void doInitSymbols() { - ElfSym<ELFT>::End.setBinding(STB_GLOBAL); - ElfSym<ELFT>::IgnoredWeak.setBinding(STB_WEAK); - ElfSym<ELFT>::IgnoredWeak.setVisibility(STV_HIDDEN); - ElfSym<ELFT>::Ignored.setBinding(STB_GLOBAL); - ElfSym<ELFT>::Ignored.setVisibility(STV_HIDDEN); +bool Symbol::includeInDynsym() const { + if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) + return false; + return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() || + (body()->isUndefined() && Config->Shared); } -void elf2::initSymbols() { - doInitSymbols<ELF32LE>(); - doInitSymbols<ELF32BE>(); - doInitSymbols<ELF64LE>(); - doInitSymbols<ELF64BE>(); +// Print out a log message for --trace-symbol. +void elf::printTraceSymbol(Symbol *Sym) { + SymbolBody *B = Sym->body(); + outs() << getFilename(B->File); + + if (B->isUndefined()) + outs() << ": reference to "; + else if (B->isCommon()) + outs() << ": common definition of "; + else + outs() << ": definition of "; + outs() << B->getName() << "\n"; } -template int SymbolBody::compare<ELF32LE>(SymbolBody *Other); -template int SymbolBody::compare<ELF32BE>(SymbolBody *Other); -template int SymbolBody::compare<ELF64LE>(SymbolBody *Other); -template int SymbolBody::compare<ELF64BE>(SymbolBody *Other); +template bool SymbolBody::hasThunk<ELF32LE>() const; +template bool SymbolBody::hasThunk<ELF32BE>() const; +template bool SymbolBody::hasThunk<ELF64LE>() const; +template bool SymbolBody::hasThunk<ELF64BE>() const; + +template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const; +template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const; +template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const; +template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const; + +template uint32_t SymbolBody::template getGotVA<ELF32LE>() const; +template uint32_t SymbolBody::template getGotVA<ELF32BE>() const; +template uint64_t SymbolBody::template getGotVA<ELF64LE>() const; +template uint64_t SymbolBody::template getGotVA<ELF64BE>() const; + +template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const; +template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const; +template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const; +template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const; + +template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const; +template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const; +template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const; +template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const; + +template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const; +template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const; +template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const; +template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const; + +template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const; +template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const; +template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const; +template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const; + +template uint32_t SymbolBody::template getPltVA<ELF32LE>() const; +template uint32_t SymbolBody::template getPltVA<ELF32BE>() const; +template uint64_t SymbolBody::template getPltVA<ELF64LE>() const; +template uint64_t SymbolBody::template getPltVA<ELF64BE>() const; -template class elf2::UndefinedElf<ELF32LE>; -template class elf2::UndefinedElf<ELF32BE>; -template class elf2::UndefinedElf<ELF64LE>; -template class elf2::UndefinedElf<ELF64BE>; +template uint32_t SymbolBody::template getSize<ELF32LE>() const; +template uint32_t SymbolBody::template getSize<ELF32BE>() const; +template uint64_t SymbolBody::template getSize<ELF64LE>() const; +template uint64_t SymbolBody::template getSize<ELF64BE>() const; -template class elf2::DefinedSynthetic<ELF32LE>; -template class elf2::DefinedSynthetic<ELF32BE>; -template class elf2::DefinedSynthetic<ELF64LE>; -template class elf2::DefinedSynthetic<ELF64BE>; +template class elf::DefinedSynthetic<ELF32LE>; +template class elf::DefinedSynthetic<ELF32BE>; +template class elf::DefinedSynthetic<ELF64LE>; +template class elf::DefinedSynthetic<ELF64BE>; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 6f65ea1a72e4..aa9a87d3b4f7 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -10,14 +10,6 @@ // All symbols are handled as SymbolBodies regardless of their types. // This file defines various types of SymbolBodies. // -// File-scope symbols in ELF objects are the only exception of SymbolBody -// instantiation. We will never create SymbolBodies for them for performance -// reason. They are often represented as nullptrs. This is fine for symbol -// resolution because the symbol table naturally cares only about -// externally-visible symbols. For relocations, you have to deal with both -// local and non-local functions, and we have two different functions -// where we need them. -// //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYMBOLS_H @@ -28,28 +20,22 @@ #include "lld/Core/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/AlignOf.h" namespace lld { -namespace elf2 { +namespace elf { class ArchiveFile; +class BitcodeFile; class InputFile; +class LazyObjectFile; class SymbolBody; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; template <class ELFT> class OutputSectionBase; template <class ELFT> class SharedFile; -// Initializes global objects defined in this file. -// Called at the beginning of main(). -void initSymbols(); - -// A real symbol object, SymbolBody, is usually accessed indirectly -// through a Symbol. There's always one Symbol for each symbol name. -// The resolver updates SymbolBody pointers as it resolves symbols. -struct Symbol { - SymbolBody *Body; -}; +struct Symbol; // The base class for real symbol classes. class SymbolBody { @@ -58,115 +44,134 @@ public: DefinedFirst, DefinedRegularKind = DefinedFirst, SharedKind, - DefinedElfLast = SharedKind, DefinedCommonKind, + DefinedBitcodeKind, DefinedSyntheticKind, DefinedLast = DefinedSyntheticKind, - UndefinedElfKind, UndefinedKind, - LazyKind + LazyArchiveKind, + LazyObjectKind, }; - Kind kind() const { return static_cast<Kind>(SymbolKind); } + SymbolBody(Kind K) : SymbolKind(K) {} - bool isWeak() const { return IsWeak; } - bool isUndefined() const { - return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind; + Symbol *symbol(); + const Symbol *symbol() const { + return const_cast<SymbolBody *>(this)->symbol(); } + + Kind kind() const { return static_cast<Kind>(SymbolKind); } + + bool isUndefined() const { return SymbolKind == UndefinedKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } bool isCommon() const { return SymbolKind == DefinedCommonKind; } - bool isLazy() const { return SymbolKind == LazyKind; } + bool isLazy() const { + return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; + } bool isShared() const { return SymbolKind == SharedKind; } - bool isUsedInRegularObj() const { return IsUsedInRegularObj; } - bool isUsedInDynamicReloc() const { return IsUsedInDynamicReloc; } - void setUsedInDynamicReloc() { IsUsedInDynamicReloc = true; } - bool isTls() const { return IsTls; } + bool isLocal() const { return IsLocal; } + bool isPreemptible() const; - // Returns the symbol name. - StringRef getName() const { return Name; } + StringRef getName() const; + void setName(StringRef S); - uint8_t getVisibility() const { return Visibility; } + uint32_t getNameOffset() const { + assert(isLocal()); + return NameOffset; + } - unsigned DynamicSymbolTableIndex = 0; - uint32_t GlobalDynIndex = -1; + uint8_t getVisibility() const { return StOther & 0x3; } + + unsigned DynsymIndex = 0; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; - bool hasGlobalDynIndex() { return GlobalDynIndex != uint32_t(-1); } + uint32_t GlobalDynIndex = -1; bool isInGot() const { return GotIndex != -1U; } - bool isInGotPlt() const { return GotPltIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } + template <class ELFT> bool hasThunk() const; + + template <class ELFT> + typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; - // A SymbolBody has a backreference to a Symbol. Originally they are - // doubly-linked. A backreference will never change. But the pointer - // in the Symbol may be mutated by the resolver. If you have a - // pointer P to a SymbolBody and are not sure whether the resolver - // has chosen the object among other objects having the same name, - // you can access P->Backref->Body to get the resolver's result. - void setBackref(Symbol *P) { Backref = P; } - SymbolBody *repl() { return Backref ? Backref->Body : this; } - Symbol *getSymbol() { return Backref; } + template <class ELFT> typename ELFT::uint getGotOffset() const; + template <class ELFT> typename ELFT::uint getGotVA() const; + template <class ELFT> typename ELFT::uint getGotPltOffset() const; + template <class ELFT> typename ELFT::uint getGotPltVA() const; + template <class ELFT> typename ELFT::uint getPltVA() const; + template <class ELFT> typename ELFT::uint getThunkVA() const; + template <class ELFT> typename ELFT::uint getSize() const; - // Decides which symbol should "win" in the symbol table, this or - // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if - // they are duplicate (conflicting) symbols. - template <class ELFT> int compare(SymbolBody *Other); + // The file from which this symbol was created. + InputFile *File = nullptr; protected: - SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, - bool IsTls) - : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility), IsTls(IsTls), - Name(Name) { - IsUsedInRegularObj = K != SharedKind && K != LazyKind; - IsUsedInDynamicReloc = 0; - } + SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type); + + SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); const unsigned SymbolKind : 8; - unsigned IsWeak : 1; - unsigned Visibility : 2; - // True if the symbol was used for linking and thus need to be - // added to the output file's symbol table. It is usually true, - // but if it is a shared symbol that were not referenced by anyone, - // it can be false. - unsigned IsUsedInRegularObj : 1; +public: + // True if the linker has to generate a copy relocation for this shared + // symbol or if the symbol should point to its plt entry. + unsigned NeedsCopyOrPltAddr : 1; + + // True if this is a local symbol. + unsigned IsLocal : 1; + + // True if this symbol has an entry in the global part of MIPS GOT. + unsigned IsInGlobalMipsGot : 1; + + // The following fields have the same meaning as the ELF symbol attributes. + uint8_t Type; // symbol type + uint8_t StOther; // st_other field value + + // The Type field may also have this value. It means that we have not yet seen + // a non-Lazy symbol with this name, so we don't know what its type is. The + // Type field is normally set to this value for Lazy symbols unless we saw a + // weak undefined symbol first, in which case we need to remember the original + // symbol's type in order to check for TLS mismatches. + enum { UnknownType = 255 }; - // If true, the symbol is added to .dynsym symbol table. - unsigned IsUsedInDynamicReloc : 1; + bool isSection() const { return Type == llvm::ELF::STT_SECTION; } + bool isTls() const { return Type == llvm::ELF::STT_TLS; } + bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } + bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } + bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } + bool isFile() const { return Type == llvm::ELF::STT_FILE; } - unsigned IsTls : 1; - StringRef Name; - Symbol *Backref = nullptr; +protected: + struct Str { + const char *S; + size_t Len; + }; + union { + Str Name; + uint32_t NameOffset; + }; }; // The base class for any defined symbols. class Defined : public SymbolBody { public: - Defined(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, bool IsTls); + Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type); + Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; -// Any defined symbol from an ELF file. -template <class ELFT> class DefinedElf : public Defined { -protected: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - +// The defined symbol in LLVM bitcode files. +class DefinedBitcode : public Defined { public: - DefinedElf(Kind K, StringRef N, const Elf_Sym &Sym) - : Defined(K, N, Sym.getBinding() == llvm::ELF::STB_WEAK, - Sym.getVisibility(), Sym.getType() == llvm::ELF::STT_TLS), - Sym(Sym) {} - - const Elf_Sym &Sym; - static bool classof(const SymbolBody *S) { - return S->kind() <= DefinedElfLast; - } + DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, BitcodeFile *F); + static bool classof(const SymbolBody *S); + BitcodeFile *file() { return (BitcodeFile *)this->File; } }; class DefinedCommon : public Defined { public: - DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak, - uint8_t Visibility); + DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther, + uint8_t Type, InputFile *File); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedCommonKind; @@ -177,95 +182,137 @@ public: uint64_t OffsetInBss; // The maximum alignment we have seen for this symbol. - uint64_t MaxAlignment; + uint64_t Alignment; uint64_t Size; }; // Regular defined symbols read from object file symbol tables. -template <class ELFT> class DefinedRegular : public DefinedElf<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; +template <class ELFT> class DefinedRegular : public Defined { + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; public: - DefinedRegular(StringRef N, const Elf_Sym &Sym, + DefinedRegular(StringRef Name, const Elf_Sym &Sym, InputSectionBase<ELFT> *Section) - : DefinedElf<ELFT>(SymbolBody::DefinedRegularKind, N, Sym), - Section(Section) {} + : Defined(SymbolBody::DefinedRegularKind, Name, Sym.st_other, + Sym.getType()), + Value(Sym.st_value), Size(Sym.st_size), + Section(Section ? Section->Repl : NullInputSection) { + if (Section) + this->File = Section->getFile(); + } + + DefinedRegular(const Elf_Sym &Sym, InputSectionBase<ELFT> *Section) + : Defined(SymbolBody::DefinedRegularKind, Sym.st_name, Sym.st_other, + Sym.getType()), + Value(Sym.st_value), Size(Sym.st_size), + Section(Section ? Section->Repl : NullInputSection) { + assert(isLocal()); + if (Section) + this->File = Section->getFile(); + } + + DefinedRegular(StringRef Name, uint8_t StOther) + : Defined(SymbolBody::DefinedRegularKind, Name, StOther, + llvm::ELF::STT_NOTYPE), + Value(0), Size(0), Section(NullInputSection) {} static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedRegularKind; } - // If this is null, the symbol is absolute. - InputSectionBase<ELFT> *Section; + uintX_t Value; + uintX_t Size; + + // The input section this symbol belongs to. Notice that this is + // a reference to a pointer. We are using two levels of indirections + // because of ICF. If ICF decides two sections need to be merged, it + // manipulates this Section pointers so that they point to the same + // section. This is a bit tricky, so be careful to not be confused. + // If this is null, the symbol is an absolute symbol. + InputSectionBase<ELFT> *&Section; + + // If non-null the symbol has a Thunk that may be used as an alternative + // destination for callers of this Symbol. + Thunk<ELFT> *ThunkData = nullptr; + +private: + static InputSectionBase<ELFT> *NullInputSection; }; +template <class ELFT> +InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection; + // DefinedSynthetic is a class to represent linker-generated ELF symbols. // The difference from the regular symbol is that DefinedSynthetic symbols // don't belong to any input files or sections. Thus, its constructor // takes an output section to calculate output VA, etc. +// If Section is null, this symbol is relative to the image base. template <class ELFT> class DefinedSynthetic : public Defined { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; DefinedSynthetic(StringRef N, uintX_t Value, - OutputSectionBase<ELFT> &Section); + OutputSectionBase<ELFT> *Section); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; } + // Special value designates that the symbol 'points' + // to the end of the section. + static const uintX_t SectionEnd = uintX_t(-1); + uintX_t Value; - const OutputSectionBase<ELFT> &Section; + const OutputSectionBase<ELFT> *Section; }; -// Undefined symbol. class Undefined : public SymbolBody { - typedef SymbolBody::Kind Kind; - bool CanKeepUndefined; - -protected: - Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, bool IsTls); - public: - Undefined(StringRef N, bool IsWeak, uint8_t Visibility, - bool CanKeepUndefined); - - static bool classof(const SymbolBody *S) { return S->isUndefined(); } - - bool canKeepUndefined() const { return CanKeepUndefined; } -}; - -template <class ELFT> class UndefinedElf : public Undefined { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - -public: - UndefinedElf(StringRef N, const Elf_Sym &Sym); - const Elf_Sym &Sym; + Undefined(StringRef Name, uint8_t StOther, uint8_t Type, InputFile *F); + Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, InputFile *F); static bool classof(const SymbolBody *S) { - return S->kind() == SymbolBody::UndefinedElfKind; + return S->kind() == UndefinedKind; } + + InputFile *file() { return this->File; } }; -template <class ELFT> class SharedSymbol : public DefinedElf<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; +template <class ELFT> class SharedSymbol : public Defined { + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::uint uintX_t; public: static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::SharedKind; } - SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym) - : DefinedElf<ELFT>(SymbolBody::SharedKind, Name, Sym), File(F) {} + SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, + const Elf_Verdef *Verdef) + : Defined(SymbolBody::SharedKind, Name, Sym.st_other, Sym.getType()), + Sym(Sym), Verdef(Verdef) { + // IFuncs defined in DSOs are treated as functions by the static linker. + if (isGnuIFunc()) + Type = llvm::ELF::STT_FUNC; + this->File = F; + } + + SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; } - SharedFile<ELFT> *File; + const Elf_Sym &Sym; - // True if the linker has to generate a copy relocation for this shared - // symbol. OffsetInBss is significant only when NeedsCopy is true. - bool NeedsCopy = false; + // This field is a pointer to the symbol's version definition. + const Elf_Verdef *Verdef; + + // OffsetInBss is significant only when needsCopy() is true. uintX_t OffsetInBss = 0; + + // If non-null the symbol has a Thunk that may be used as an alternative + // destination for callers of this Symbol. + Thunk<ELFT> *ThunkData = nullptr; + bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); } }; // This class represents a symbol defined in an archive file. It is @@ -275,58 +322,153 @@ public: // the same name, it will ask the Lazy to load a file. class Lazy : public SymbolBody { public: - Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S) - : SymbolBody(LazyKind, S.getName(), false, llvm::ELF::STV_DEFAULT, false), - File(F), Sym(S) {} - - static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } + static bool classof(const SymbolBody *S) { return S->isLazy(); } // Returns an object file for this symbol, or a nullptr if the file // was already returned. - std::unique_ptr<InputFile> getMember(); + std::unique_ptr<InputFile> fetch(); + +protected: + Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type) + : SymbolBody(K, Name, llvm::ELF::STV_DEFAULT, Type) {} +}; - void setWeak() { IsWeak = true; } - void setUsedInRegularObj() { IsUsedInRegularObj = true; } +// LazyArchive symbols represents symbols in archive files. +class LazyArchive : public Lazy { +public: + LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, + uint8_t Type); + + static bool classof(const SymbolBody *S) { + return S->kind() == LazyArchiveKind; + } + + ArchiveFile *file() { return (ArchiveFile *)this->File; } + std::unique_ptr<InputFile> fetch(); private: - ArchiveFile *File; const llvm::object::Archive::Symbol Sym; }; +// LazyObject symbols represents symbols in object files between +// --start-lib and --end-lib options. +class LazyObject : public Lazy { +public: + LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type); + + static bool classof(const SymbolBody *S) { + return S->kind() == LazyObjectKind; + } + + LazyObjectFile *file() { return (LazyObjectFile *)this->File; } + std::unique_ptr<InputFile> fetch(); +}; + // Some linker-generated symbols need to be created as -// DefinedRegular symbols, so they need Elf_Sym symbols. -// Here we allocate such Elf_Sym symbols statically. +// DefinedRegular symbols. template <class ELFT> struct ElfSym { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + // The content for _etext and etext symbols. + static DefinedRegular<ELFT> *Etext; + static DefinedRegular<ELFT> *Etext2; - // Used to represent an undefined symbol which we don't want - // to add to the output file's symbol table. The `IgnoredWeak` - // has weak binding and can be substituted. The `Ignore` has - // global binding and gets priority over symbols from shared libs. - static Elf_Sym IgnoredWeak; - static Elf_Sym Ignored; + // The content for _edata and edata symbols. + static DefinedRegular<ELFT> *Edata; + static DefinedRegular<ELFT> *Edata2; // The content for _end and end symbols. - static Elf_Sym End; + static DefinedRegular<ELFT> *End; + static DefinedRegular<ELFT> *End2; + + // The content for _gp_disp symbol for MIPS target. + static SymbolBody *MipsGpDisp; +}; + +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext; +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2; +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata; +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2; +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End; +template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2; +template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp; + +// A real symbol object, SymbolBody, is usually stored within a Symbol. There's +// always one Symbol for each symbol name. The resolver updates the SymbolBody +// stored in the Body field of this object as it resolves symbols. Symbol also +// holds computed properties of symbol names. +struct Symbol { + // Symbol binding. This is on the Symbol to track changes during resolution. + // In particular: + // An undefined weak is still weak when it resolves to a shared library. + // An undefined weak will not fetch archive members, but we have to remember + // it is weak. + uint8_t Binding; + + // Version definition index. + uint16_t VersionId; - // The content for _gp symbol for MIPS target. - static Elf_Sym MipsGp; + // Symbol visibility. This is the computed minimum visibility of all + // observed non-DSO symbols. + unsigned Visibility : 2; + + // True if the symbol was used for linking and thus need to be added to the + // output file's symbol table. This is true for all symbols except for + // unreferenced DSO symbols and bitcode symbols that are unreferenced except + // by other bitcode objects. + unsigned IsUsedInRegularObj : 1; + + // If this flag is true and the symbol has protected or default visibility, it + // will appear in .dynsym. This flag is set by interposable DSO symbols in + // executables, by most symbols in DSOs and executables built with + // --export-dynamic, and by dynamic lists. + unsigned ExportDynamic : 1; + + // True if this symbol is specified by --trace-symbol option. + unsigned Traced : 1; + + bool includeInDynsym() const; + bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } - // __rel_iplt_start/__rel_iplt_end for signaling - // where R_[*]_IRELATIVE relocations do live. - static Elf_Sym RelaIpltStart; - static Elf_Sym RelaIpltEnd; + // This field is used to store the Symbol's SymbolBody. This instantiation of + // AlignedCharArrayUnion gives us a struct with a char array field that is + // large and aligned enough to store any derived class of SymbolBody. We + // assume that the size and alignment of ELF64LE symbols is sufficient for any + // ELFT, and we verify this with the static_asserts in replaceBody. + llvm::AlignedCharArrayUnion< + DefinedBitcode, DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, + DefinedSynthetic<llvm::object::ELF64LE>, Undefined, + SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject> + Body; + + SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); } + const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); } }; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoredWeak; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::Ignored; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::End; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::MipsGp; -template <class ELFT> -typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::RelaIpltStart; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::RelaIpltEnd; +void printTraceSymbol(Symbol *Sym); + +template <typename T, typename... ArgT> +void replaceBody(Symbol *S, ArgT &&... Arg) { + static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); + static_assert(llvm::AlignOf<T>::Alignment <= + llvm::AlignOf<decltype(S->Body)>::Alignment, + "Body not aligned enough"); + assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr && + "Not a SymbolBody"); + + new (S->Body.buffer) T(std::forward<ArgT>(Arg)...); + + // Print out a log message if --trace-symbol was specified. + // This is for debugging. + if (S->Traced) + printTraceSymbol(S); +} + +inline Symbol *SymbolBody::symbol() { + assert(!isLocal()); + return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) - + offsetof(Symbol, Body)); +} -} // namespace elf2 +} // namespace elf } // namespace lld #endif diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 6d42dbe86e54..466d1b47ce12 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -11,14 +11,25 @@ // GOT or PLT entries, etc., are handled in this file. // // Refer the ELF spec for the single letter varaibles, S, A or P, used -// in this file. SA is S+A. +// in this file. +// +// Some functions defined in this file has "relaxTls" as part of their names. +// They do peephole optimization for TLS variables by rewriting instructions. +// They are not part of the ABI but optional optimization, so you can skip +// them if you are not interested in how TLS variables are optimized. +// See the following paper for the details. +// +// Ulrich Drepper, ELF Handling For Thread-Local Storage +// http://www.akkadia.org/drepper/tls.pdf // //===----------------------------------------------------------------------===// #include "Target.h" #include "Error.h" +#include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" +#include "Thunks.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/ELF.h" @@ -31,215 +42,169 @@ using namespace llvm::support::endian; using namespace llvm::ELF; namespace lld { -namespace elf2 { +namespace elf { -std::unique_ptr<TargetInfo> Target; +TargetInfo *Target; -template <endianness E> static void add32(void *P, int32_t V) { - write32<E>(P, read32<E>(P) + V); -} - -static void add32le(uint8_t *P, int32_t V) { add32<support::little>(P, V); } static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } +StringRef getRelName(uint32_t Type) { + return getELFRelocationTypeName(Config->EMachine, Type); +} + template <unsigned N> static void checkInt(int64_t V, uint32_t Type) { - if (isInt<N>(V)) - return; - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("Relocation " + S + " out of range"); + if (!isInt<N>(V)) + error("relocation " + getRelName(Type) + " out of range"); } template <unsigned N> static void checkUInt(uint64_t V, uint32_t Type) { - if (isUInt<N>(V)) - return; - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("Relocation " + S + " out of range"); + if (!isUInt<N>(V)) + error("relocation " + getRelName(Type) + " out of range"); } template <unsigned N> static void checkIntUInt(uint64_t V, uint32_t Type) { - if (isInt<N>(V) || isUInt<N>(V)) - return; - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("Relocation " + S + " out of range"); + if (!isInt<N>(V) && !isUInt<N>(V)) + error("relocation " + getRelName(Type) + " out of range"); } template <unsigned N> static void checkAlignment(uint64_t V, uint32_t Type) { - if ((V & (N - 1)) == 0) - return; - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("Improper alignment for relocation " + S); + if ((V & (N - 1)) != 0) + error("improper alignment for relocation " + getRelName(Type)); } -template <class ELFT> bool isGnuIFunc(const SymbolBody &S) { - if (auto *SS = dyn_cast<DefinedElf<ELFT>>(&S)) - return SS->Sym.getType() == STT_GNU_IFUNC; - return false; +static void errorDynRel(uint32_t Type) { + error("relocation " + getRelName(Type) + + " cannot be used against shared object; recompile with -fPIC."); } -template bool isGnuIFunc<ELF32LE>(const SymbolBody &S); -template bool isGnuIFunc<ELF32BE>(const SymbolBody &S); -template bool isGnuIFunc<ELF64LE>(const SymbolBody &S); -template bool isGnuIFunc<ELF64BE>(const SymbolBody &S); - namespace { class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); - void writeGotPltHeaderEntries(uint8_t *Buf) const override; - unsigned getDynReloc(unsigned Type) const override; - unsigned getTlsGotReloc(unsigned Type) const override; - bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsDynRelative(unsigned Type) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; - bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; - unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, - const SymbolBody &S) const override; - bool isGotRelative(uint32_t Type) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + uint32_t getDynRel(uint32_t Type) const override; + bool isTlsLocalDynamicRel(uint32_t Type) const override; + bool isTlsGlobalDynamicRel(uint32_t Type) const override; + bool isTlsInitialExecRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; -private: - void relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsIeToLe(unsigned Type, uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const; + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; -class X86_64TargetInfo final : public TargetInfo { +template <class ELFT> class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); - bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; - void writeGotPltHeaderEntries(uint8_t *Buf) const override; - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; - bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; - bool isSizeReloc(uint32_t Type) const override; - unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, - const SymbolBody &S) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + uint32_t getDynRel(uint32_t Type) const override; + bool isTlsLocalDynamicRel(uint32_t Type) const override; + bool isTlsGlobalDynamicRel(uint32_t Type) const override; + bool isTlsInitialExecRel(uint32_t Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxGot(uint8_t *Loc, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; private: - void relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; - void relocateTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const; + void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, + uint8_t ModRm) const; }; class PPCTargetInfo final : public TargetInfo { public: PPCTargetInfo(); - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); - unsigned getDynReloc(unsigned Type) const override; - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - unsigned getTlsGotReloc(unsigned Type = -1) const override; - bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; - bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + uint32_t getDynRel(uint32_t Type) const override; + bool isTlsInitialExecRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + bool usesOnlyLowPageBits(uint32_t Type) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AMDGPUTargetInfo final : public TargetInfo { public: AMDGPUTargetInfo(); - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; +}; + +class ARMTargetInfo final : public TargetInfo { +public: + ARMTargetInfo(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + uint32_t getDynRel(uint32_t Type) const override; + uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, + const InputFile &File, + const SymbolBody &S) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; template <class ELFT> class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); - void writeGotHeaderEntries(uint8_t *Buf) const override; - void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; - void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; - void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const override; - bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; - bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const override; - bool isRelRelative(uint32_t Type) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; + uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + uint32_t getDynRel(uint32_t Type) const override; + bool isTlsLocalDynamicRel(uint32_t Type) const override; + bool isTlsGlobalDynamicRel(uint32_t Type) const override; + void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, + const InputFile &File, + const SymbolBody &S) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + bool usesOnlyLowPageBits(uint32_t Type) const override; }; } // anonymous namespace @@ -251,80 +216,153 @@ TargetInfo *createTarget() { return new AArch64TargetInfo(); case EM_AMDGPU: return new AMDGPUTargetInfo(); + case EM_ARM: + return new ARMTargetInfo(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: return new MipsTargetInfo<ELF32LE>(); case ELF32BEKind: return new MipsTargetInfo<ELF32BE>(); + case ELF64LEKind: + return new MipsTargetInfo<ELF64LE>(); + case ELF64BEKind: + return new MipsTargetInfo<ELF64BE>(); default: - error("Unsupported MIPS target"); + fatal("unsupported MIPS target"); } case EM_PPC: return new PPCTargetInfo(); case EM_PPC64: return new PPC64TargetInfo(); case EM_X86_64: - return new X86_64TargetInfo(); + if (Config->EKind == ELF32LEKind) + return new X86_64TargetInfo<ELF32LE>(); + return new X86_64TargetInfo<ELF64LE>(); } - error("Unknown target machine"); + fatal("unknown target machine"); } TargetInfo::~TargetInfo() {} -bool TargetInfo::isTlsOptimized(unsigned Type, const SymbolBody *S) const { - return false; +uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, + uint32_t Type) const { + return 0; } -uint64_t TargetInfo::getVAStart() const { return Config->Shared ? 0 : VAStart; } +bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; } -bool TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { +RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType, + const InputFile &File, + const SymbolBody &S) const { + return Expr; +} + +bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; } + +bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; } + +bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; } -bool TargetInfo::isGotRelative(uint32_t Type) const { return false; } +RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const { + return Expr; +} -bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } +void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { + llvm_unreachable("Should not have claimed to be relaxable"); +} -bool TargetInfo::isSizeReloc(uint32_t Type) const { return false; } +void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + llvm_unreachable("Should not have claimed to be relaxable"); +} -unsigned TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, uint64_t SA, - const SymbolBody &S) const { - return 0; +void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + llvm_unreachable("Should not have claimed to be relaxable"); } -void TargetInfo::writeGotHeaderEntries(uint8_t *Buf) const {} +void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + llvm_unreachable("Should not have claimed to be relaxable"); +} -void TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const {} +void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + llvm_unreachable("Should not have claimed to be relaxable"); +} X86TargetInfo::X86TargetInfo() { - CopyReloc = R_386_COPY; - PCRelReloc = R_386_PC32; - GotReloc = R_386_GLOB_DAT; - PltReloc = R_386_JUMP_SLOT; - IRelativeReloc = R_386_IRELATIVE; - RelativeReloc = R_386_RELATIVE; - TlsGotReloc = R_386_TLS_TPOFF; - TlsGlobalDynamicReloc = R_386_TLS_GD; - TlsLocalDynamicReloc = R_386_TLS_LDM; - TlsModuleIndexReloc = R_386_TLS_DTPMOD32; - TlsOffsetReloc = R_386_TLS_DTPOFF32; - LazyRelocations = true; + CopyRel = R_386_COPY; + GotRel = R_386_GLOB_DAT; + PltRel = R_386_JUMP_SLOT; + IRelativeRel = R_386_IRELATIVE; + RelativeRel = R_386_RELATIVE; + TlsGotRel = R_386_TLS_TPOFF; + TlsModuleIndexRel = R_386_TLS_DTPMOD32; + TlsOffsetRel = R_386_TLS_DTPOFF32; + GotEntrySize = 4; + GotPltEntrySize = 4; PltEntrySize = 16; - PltZeroEntrySize = 16; + PltHeaderSize = 16; + TlsGdRelaxSkip = 2; +} + +RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_386_TLS_GD: + return R_TLSGD; + case R_386_TLS_LDM: + return R_TLSLD; + case R_386_PLT32: + return R_PLT_PC; + case R_386_PC32: + return R_PC; + case R_386_GOTPC: + return R_GOTONLY_PC; + case R_386_TLS_IE: + return R_GOT; + case R_386_GOT32: + case R_386_GOT32X: + case R_386_TLS_GOTIE: + return R_GOT_FROM_END; + case R_386_GOTOFF: + return R_GOTREL; + case R_386_TLS_LE: + return R_TLS; + case R_386_TLS_LE_32: + return R_NEG_TLS; + } } -void X86TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const { +RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const { + switch (Expr) { + default: + return Expr; + case R_RELAX_TLS_GD_TO_IE: + return R_RELAX_TLS_GD_TO_IE_END; + case R_RELAX_TLS_GD_TO_LE: + return R_RELAX_TLS_GD_TO_LE_NEG; + } +} + +void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, Out<ELF32LE>::Dynamic->getVA()); } -void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { - // Skip 6 bytes of "pushl (GOT+4)" - write32le(Buf, Plt + 6); +void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { + // Entries in .got.plt initially points back to the corresponding + // PLT entries with a fixed offset to skip the first instruction. + write32le(Buf, S.getPltVA<ELF32LE>() + 6); } -unsigned X86TargetInfo::getDynReloc(unsigned Type) const { +uint32_t X86TargetInfo::getDynRel(uint32_t Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) @@ -332,30 +370,26 @@ unsigned X86TargetInfo::getDynReloc(unsigned Type) const { return Type; } -unsigned X86TargetInfo::getTlsGotReloc(unsigned Type) const { - if (Type == R_386_TLS_IE) - return Type; - return TlsGotReloc; +bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { + return Type == R_386_TLS_GD; } -bool X86TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const { - if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 || - Type == R_386_TLS_GOTIE) - return Config->Shared; - if (Type == R_386_TLS_IE) - return canBePreempted(&S, true); - return Type == R_386_TLS_GD; +bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { + return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM; } -void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { +bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const { + return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE; +} + +void X86TargetInfo::writePltHeader(uint8_t *Buf) const { // Executable files and shared object files have // separate procedure linkage tables. - if (Config->Shared) { + if (Config->Pic) { const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) - 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) - 0x90, 0x90, 0x90, 0x90 // nop;nop;nop;nop + 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) + 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop }; memcpy(Buf, V, sizeof(V)); return; @@ -363,283 +397,229 @@ void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4) - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8) - 0x90, 0x90, 0x90, 0x90 // nop;nop;nop;nop + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8) + 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop }; memcpy(Buf, PltData, sizeof(PltData)); - write32le(Buf + 2, GotEntryAddr + 4); // GOT+4 - write32le(Buf + 8, GotEntryAddr + 8); // GOT+8 + uint32_t Got = Out<ELF32LE>::GotPlt->getVA(); + write32le(Buf + 2, Got + 4); + write32le(Buf + 8, Got + 8); } -void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const { +void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx) 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC }; memcpy(Buf, Inst, sizeof(Inst)); + // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT - Buf[1] = Config->Shared ? 0xa3 : 0x25; - write32le(Buf + 2, Config->Shared ? (GotEntryAddr - GotAddr) : GotEntryAddr); + Buf[1] = Config->Pic ? 0xa3 : 0x25; + uint32_t Got = Out<ELF32LE>::GotPlt->getVA(); + write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr); write32le(Buf + 7, RelOff); - write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); -} - -bool X86TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { - if (Type == R_386_32 || Type == R_386_16 || Type == R_386_8) - if (auto *SS = dyn_cast<SharedSymbol<ELF32LE>>(&S)) - return SS->Sym.getType() == STT_OBJECT; - return false; -} - -bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - if (S.isTls() && Type == R_386_TLS_GD) - return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true); - if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE) - return !isTlsOptimized(Type, &S); - return Type == R_386_GOT32 || relocNeedsPlt(Type, S); -} - -bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { - return isGnuIFunc<ELF32LE>(S) || - (Type == R_386_PLT32 && canBePreempted(&S, true)) || - (Type == R_386_PC32 && S.isShared()); -} - -bool X86TargetInfo::isGotRelative(uint32_t Type) const { - // This relocation does not require got entry, - // but it is relative to got and needs it to be created. - // Here we request for that. - return Type == R_386_GOTOFF; + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } -void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { +uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf, + uint32_t Type) const { switch (Type) { + default: + return 0; case R_386_32: - add32le(Loc, SA); - break; case R_386_GOT32: + case R_386_GOT32X: case R_386_GOTOFF: - add32le(Loc, SA - Out<ELF32LE>::Got->getVA()); - break; case R_386_GOTPC: - add32le(Loc, SA + Out<ELF32LE>::Got->getVA() - P); - break; case R_386_PC32: case R_386_PLT32: - add32le(Loc, SA - P); - break; - case R_386_TLS_GD: - case R_386_TLS_LDM: - case R_386_TLS_TPOFF: { - uint64_t V = SA - Out<ELF32LE>::Got->getVA() - - Out<ELF32LE>::Got->getNumEntries() * 4; - checkInt<32>(V, Type); - write32le(Loc, V); - break; - } - case R_386_TLS_IE: - case R_386_TLS_LDO_32: - write32le(Loc, SA); - break; - case R_386_TLS_LE: - write32le(Loc, SA - Out<ELF32LE>::TlsPhdr->p_memsz); - break; - case R_386_TLS_LE_32: - write32le(Loc, Out<ELF32LE>::TlsPhdr->p_memsz - SA); - break; - default: - error("unrecognized reloc " + Twine(Type)); + return read32le(Buf); } } -bool X86TargetInfo::isTlsOptimized(unsigned Type, const SymbolBody *S) const { - if (Config->Shared || (S && !S->isTls())) - return false; - return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM || - Type == R_386_TLS_GD || - (Type == R_386_TLS_IE && !canBePreempted(S, true)) || - (Type == R_386_TLS_GOTIE && !canBePreempted(S, true)); -} - -bool X86TargetInfo::relocNeedsDynRelative(unsigned Type) const { - return Config->Shared && Type == R_386_TLS_IE; -} - -unsigned X86TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA, - const SymbolBody &S) const { - switch (Type) { - case R_386_TLS_GD: - if (canBePreempted(&S, true)) - relocateTlsGdToIe(Loc, BufEnd, P, SA); - else - relocateTlsGdToLe(Loc, BufEnd, P, SA); - // The next relocation should be against __tls_get_addr, so skip it - return 1; - case R_386_TLS_GOTIE: - case R_386_TLS_IE: - relocateTlsIeToLe(Type, Loc, BufEnd, P, SA); - return 0; - case R_386_TLS_LDM: - relocateTlsLdToLe(Loc, BufEnd, P, SA); - // The next relocation should be against __tls_get_addr, so skip it - return 1; - case R_386_TLS_LDO_32: - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); - return 0; - } - llvm_unreachable("Unknown TLS optimization"); +void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + checkInt<32>(Val, Type); + write32le(Loc, Val); } -// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.1 -// IA-32 Linker Optimizations, http://www.akkadia.org/drepper/tls.pdf) shows -// how GD can be optimized to IE: -// leal x@tlsgd(, %ebx, 1), -// call __tls_get_addr@plt -// Is converted to: -// movl %gs:0, %eax -// addl x@gotntpoff(%ebx), %eax -void X86TargetInfo::relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // leal x@tlsgd(, %ebx, 1), + // call __tls_get_addr@plt + // to + // movl %gs:0,%eax + // subl $x@ntpoff,%eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax - 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax + 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); - relocateOne(Loc + 5, BufEnd, R_386_32, P, - SA - Out<ELF32LE>::Got->getVA() - - Out<ELF32LE>::Got->getNumEntries() * 4); + relocateOne(Loc + 5, R_386_32, Val); } -// GD can be optimized to LE: -// leal x@tlsgd(, %ebx, 1), -// call __tls_get_addr@plt -// Can be converted to: -// movl %gs:0,%eax -// addl $x@ntpoff,%eax -// But gold emits subl $foo@tpoff,%eax instead of addl. -// These instructions are completely equal in behavior. -// This method generates subl to be consistent with gold. -void X86TargetInfo::relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // leal x@tlsgd(, %ebx, 1), + // call __tls_get_addr@plt + // to + // movl %gs:0, %eax + // addl x@gotntpoff(%ebx), %eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax - 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax + 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); - relocateOne(Loc + 5, BufEnd, R_386_32, P, - Out<ELF32LE>::TlsPhdr->p_memsz - SA); -} - -// LD can be optimized to LE: -// leal foo(%reg),%eax -// call ___tls_get_addr -// Is converted to: -// movl %gs:0,%eax -// nop -// leal 0(%esi,1),%esi -void X86TargetInfo::relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P, - uint64_t SA) const { - const uint8_t Inst[] = { - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax - 0x90, // nop - 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi - }; - memcpy(Loc - 2, Inst, sizeof(Inst)); + relocateOne(Loc + 5, R_386_32, Val); } // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. -// Read "ELF Handling For Thread-Local Storage, 5.1 -// IA-32 Linker Optimizations" (http://www.akkadia.org/drepper/tls.pdf) -// by Ulrich Drepper for details. -void X86TargetInfo::relocateTlsIeToLe(unsigned Type, uint8_t *Loc, - uint8_t *BufEnd, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in // position dependent code. - uint8_t *Inst = Loc - 2; - uint8_t *Op = Loc - 1; uint8_t Reg = (Loc[-1] >> 3) & 7; - bool IsMov = *Inst == 0x8b; + if (Type == R_386_TLS_IE) { - // For R_386_TLS_IE relocation we perform the next transformations: - // MOVL foo@INDNTPOFF,%EAX is transformed to MOVL $foo,%EAX - // MOVL foo@INDNTPOFF,%REG is transformed to MOVL $foo,%REG - // ADDL foo@INDNTPOFF,%REG is transformed to ADDL $foo,%REG - // First one is special because when EAX is used the sequence is 5 bytes - // long, otherwise it is 6 bytes. - if (*Op == 0xa1) { - *Op = 0xb8; + if (Loc[-1] == 0xa1) { + // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" + // This case is different from the generic case below because + // this is a 5 byte instruction while below is 6 bytes. + Loc[-1] = 0xb8; + } else if (Loc[-2] == 0x8b) { + // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; } else { - *Inst = IsMov ? 0xc7 : 0x81; - *Op = 0xc0 | ((*Op >> 3) & 7); + // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" + Loc[-2] = 0x81; + Loc[-1] = 0xc0 | Reg; } } else { - // R_386_TLS_GOTIE relocation can be optimized to - // R_386_TLS_LE so that it does not use GOT. - // "MOVL foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVL $foo, %REG". - // "ADDL foo@GOTNTPOFF(%RIP), %REG" is transformed to "LEAL foo(%REG), %REG" - // Note: gold converts to ADDL instead of LEAL. - *Inst = IsMov ? 0xc7 : 0x8d; - if (IsMov) - *Op = 0xc0 | ((*Op >> 3) & 7); - else - *Op = 0x80 | Reg | (Reg << 3); + assert(Type == R_386_TLS_GOTIE); + if (Loc[-2] == 0x8b) { + // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; + } else { + // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" + Loc[-2] = 0x8d; + Loc[-1] = 0x80 | (Reg << 3) | Reg; + } + } + relocateOne(Loc, R_386_TLS_LE, Val); +} + +void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + if (Type == R_386_TLS_LDO_32) { + relocateOne(Loc, R_386_TLS_LE, Val); + return; } - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); + + // Convert + // leal foo(%reg),%eax + // call ___tls_get_addr + // to + // movl %gs:0,%eax + // nop + // leal 0(%esi,1),%esi + const uint8_t Inst[] = { + 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax + 0x90, // nop + 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi + }; + memcpy(Loc - 2, Inst, sizeof(Inst)); } -X86_64TargetInfo::X86_64TargetInfo() { - CopyReloc = R_X86_64_COPY; - PCRelReloc = R_X86_64_PC32; - GotReloc = R_X86_64_GLOB_DAT; - PltReloc = R_X86_64_JUMP_SLOT; - RelativeReloc = R_X86_64_RELATIVE; - IRelativeReloc = R_X86_64_IRELATIVE; - TlsGotReloc = R_X86_64_TPOFF64; - TlsLocalDynamicReloc = R_X86_64_TLSLD; - TlsGlobalDynamicReloc = R_X86_64_TLSGD; - TlsModuleIndexReloc = R_X86_64_DTPMOD64; - TlsOffsetReloc = R_X86_64_DTPOFF64; - LazyRelocations = true; +template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() { + CopyRel = R_X86_64_COPY; + GotRel = R_X86_64_GLOB_DAT; + PltRel = R_X86_64_JUMP_SLOT; + RelativeRel = R_X86_64_RELATIVE; + IRelativeRel = R_X86_64_IRELATIVE; + TlsGotRel = R_X86_64_TPOFF64; + TlsModuleIndexRel = R_X86_64_DTPMOD64; + TlsOffsetRel = R_X86_64_DTPOFF64; + GotEntrySize = 8; + GotPltEntrySize = 8; PltEntrySize = 16; - PltZeroEntrySize = 16; + PltHeaderSize = 16; + TlsGdRelaxSkip = 2; +} + +template <class ELFT> +RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, + const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_X86_64_TPOFF32: + return R_TLS; + case R_X86_64_TLSLD: + return R_TLSLD_PC; + case R_X86_64_TLSGD: + return R_TLSGD_PC; + case R_X86_64_SIZE32: + case R_X86_64_SIZE64: + return R_SIZE; + case R_X86_64_PLT32: + return R_PLT_PC; + case R_X86_64_PC32: + case R_X86_64_PC64: + return R_PC; + case R_X86_64_GOT32: + return R_GOT_FROM_END; + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_GOTTPOFF: + return R_GOT_PC; + } } -void X86_64TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const { - write64le(Buf, Out<ELF64LE>::Dynamic->getVA()); +template <class ELFT> +void X86_64TargetInfo<ELFT>::writeGotPltHeader(uint8_t *Buf) const { + // The first entry holds the value of _DYNAMIC. It is not clear why that is + // required, but it is documented in the psabi and the glibc dynamic linker + // seems to use it (note that this is relevant for linking ld.so, not any + // other program). + write64le(Buf, Out<ELFT>::Dynamic->getVA()); } -void X86_64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { - // Skip 6 bytes of "jmpq *got(%rip)" - write32le(Buf, Plt + 6); +template <class ELFT> +void X86_64TargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, + const SymbolBody &S) const { + // See comments in X86TargetInfo::writeGotPlt. + write32le(Buf, S.getPltVA<ELFT>() + 6); } -void X86_64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { +template <class ELFT> +void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax) }; memcpy(Buf, PltData, sizeof(PltData)); - write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8 - write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16 + uint64_t Got = Out<ELFT>::GotPlt->getVA(); + uint64_t Plt = Out<ELFT>::Plt->getVA(); + write32le(Buf + 2, Got - Plt + 2); // GOT+8 + write32le(Buf + 8, Got - Plt + 4); // GOT+16 } -void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +template <class ELFT> +void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index> @@ -649,275 +629,316 @@ void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); - write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); -} - -bool X86_64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { - if (Type == R_X86_64_32S || Type == R_X86_64_32 || Type == R_X86_64_PC32 || - Type == R_X86_64_64) - if (auto *SS = dyn_cast<SharedSymbol<ELF64LE>>(&S)) - return SS->Sym.getType() == STT_OBJECT; - return false; -} - -bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - if (Type == R_X86_64_TLSGD) - return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true); - if (Type == R_X86_64_GOTTPOFF) - return !isTlsOptimized(Type, &S); - return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S); -} - -bool X86_64TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const { - return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD; -} - -bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { - if (needsCopyRel(Type, S)) - return false; - if (isGnuIFunc<ELF64LE>(S)) - return true; - - switch (Type) { - default: - return false; - case R_X86_64_32: - case R_X86_64_64: - case R_X86_64_PC32: - // This relocation is defined to have a value of (S + A - P). - // The problems start when a non PIC program calls a function in a shared - // library. - // In an ideal world, we could just report an error saying the relocation - // can overflow at runtime. - // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to - // libc.so. - // - // The general idea on how to handle such cases is to create a PLT entry - // and use that as the function value. - // - // For the static linking part, we just return true and everything else - // will use the the PLT entry as the address. - // - // The remaining (unimplemented) problem is making sure pointer equality - // still works. We need the help of the dynamic linker for that. We - // let it know that we have a direct reference to a so symbol by creating - // an undefined symbol with a non zero st_value. Seeing that, the - // dynamic linker resolves the symbol to the value of the symbol we created. - // This is true even for got entries, so pointer equality is maintained. - // To avoid an infinite loop, the only entry that points to the - // real function is a dedicated got entry used by the plt. That is - // identified by special relocation types (R_X86_64_JUMP_SLOT, - // R_386_JMP_SLOT, etc). - return S.isShared(); - case R_X86_64_PLT32: - return canBePreempted(&S, true); - } + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } -bool X86_64TargetInfo::isRelRelative(uint32_t Type) const { - switch (Type) { - default: - return false; - case R_X86_64_DTPOFF32: - case R_X86_64_DTPOFF64: - case R_X86_64_PC8: - case R_X86_64_PC16: - case R_X86_64_PC32: - case R_X86_64_PC64: - case R_X86_64_PLT32: - return true; - } +template <class ELFT> +uint32_t X86_64TargetInfo<ELFT>::getDynRel(uint32_t Type) const { + if (Type == R_X86_64_PC32 || Type == R_X86_64_32) + errorDynRel(Type); + return Type; } -bool X86_64TargetInfo::isSizeReloc(uint32_t Type) const { - return Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64; +template <class ELFT> +bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const { + return Type == R_X86_64_GOTTPOFF; } -bool X86_64TargetInfo::isTlsOptimized(unsigned Type, - const SymbolBody *S) const { - if (Config->Shared || (S && !S->isTls())) - return false; - return Type == R_X86_64_TLSGD || Type == R_X86_64_TLSLD || - Type == R_X86_64_DTPOFF32 || - (Type == R_X86_64_GOTTPOFF && !canBePreempted(S, true)); +template <class ELFT> +bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const { + return Type == R_X86_64_TLSGD; } -// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 -// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows -// how LD can be optimized to LE: -// leaq bar@tlsld(%rip), %rdi -// callq __tls_get_addr@PLT -// leaq bar@dtpoff(%rax), %rcx -// Is converted to: -// .word 0x6666 -// .byte 0x66 -// mov %fs:0,%rax -// leaq bar@tpoff(%rax), %rcx -void X86_64TargetInfo::relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const { - const uint8_t Inst[] = { - 0x66, 0x66, //.word 0x6666 - 0x66, //.byte 0x66 - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax - }; - memcpy(Loc - 3, Inst, sizeof(Inst)); +template <class ELFT> +bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const { + return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 || + Type == R_X86_64_TLSLD; } -// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 -// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows -// how GD can be optimized to LE: -// .byte 0x66 -// leaq x@tlsgd(%rip), %rdi -// .word 0x6666 -// rex64 -// call __tls_get_addr@plt -// Is converted to: -// mov %fs:0x0,%rax -// lea x@tpoff,%rax -void X86_64TargetInfo::relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const { +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + // mov %fs:0x0,%rax + // lea x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); - relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF32, P, SA); + // The original code used a pc relative relocation and so we have to + // compensate for the -4 in had in the addend. + relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4); } -// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 -// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows -// how GD can be optimized to IE: -// .byte 0x66 -// leaq x@tlsgd(%rip), %rdi -// .word 0x6666 -// rex64 -// call __tls_get_addr@plt -// Is converted to: -// mov %fs:0x0,%rax -// addq x@tpoff,%rax -void X86_64TargetInfo::relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const { +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // .byte 0x66 + // leaq x@tlsgd(%rip), %rdi + // .word 0x6666 + // rex64 + // call __tls_get_addr@plt + // to + // mov %fs:0x0,%rax + // addq x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); - relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF64, P + 12, SA); + // Both code sequences are PC relatives, but since we are moving the constant + // forward by 8 bytes we have to subtract the value by 8. + relocateOne(Loc + 8, R_X86_64_PC32, Val - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. -// This function does that. Read "ELF Handling For Thread-Local Storage, -// 5.5 x86-x64 linker optimizations" (http://www.akkadia.org/drepper/tls.pdf) -// by Ulrich Drepper for details. -void X86_64TargetInfo::relocateTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, - uint64_t P, uint64_t SA) const { - // Ulrich's document section 6.5 says that @gottpoff(%rip) must be - // used in MOVQ or ADDQ instructions only. - // "MOVQ foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVQ $foo, %REG". - // "ADDQ foo@GOTTPOFF(%RIP), %REG" is transformed to "LEAQ foo(%REG), %REG" - // (if the register is not RSP/R12) or "ADDQ $foo, %RSP". - // Opcodes info can be found at http://ref.x86asm.net/coder64.html#x48. - uint8_t *Prefix = Loc - 3; - uint8_t *Inst = Loc - 2; - uint8_t *RegSlot = Loc - 1; +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + uint8_t *Inst = Loc - 3; uint8_t Reg = Loc[-1] >> 3; - bool IsMov = *Inst == 0x8b; - bool RspAdd = !IsMov && Reg == 4; - // r12 and rsp registers requires special handling. - // Problem is that for other registers, for example leaq 0xXXXXXXXX(%r11),%r11 - // result out is 7 bytes: 4d 8d 9b XX XX XX XX, - // but leaq 0xXXXXXXXX(%r12),%r12 is 8 bytes: 4d 8d a4 24 XX XX XX XX. - // The same true for rsp. So we convert to addq for them, saving 1 byte that - // we dont have. - if (RspAdd) - *Inst = 0x81; - else - *Inst = IsMov ? 0xc7 : 0x8d; - if (*Prefix == 0x4c) - *Prefix = (IsMov || RspAdd) ? 0x49 : 0x4d; - *RegSlot = (IsMov || RspAdd) ? (0xc0 | Reg) : (0x80 | Reg | (Reg << 3)); - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); + uint8_t *RegSlot = Loc - 1; + + // Note that ADD with RSP or R12 is converted to ADD instead of LEA + // because LEA with these registers needs 4 bytes to encode and thus + // wouldn't fit the space. + + if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { + // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" + memcpy(Inst, "\x48\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { + // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" + memcpy(Inst, "\x49\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { + // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" + memcpy(Inst, "\x4d\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x48\x03", 2) == 0) { + // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" + memcpy(Inst, "\x48\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { + // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" + memcpy(Inst, "\x49\xc7", 2); + *RegSlot = 0xc0 | Reg; + } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { + // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" + memcpy(Inst, "\x48\xc7", 2); + *RegSlot = 0xc0 | Reg; + } else { + fatal("R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); + } + + // The original code used a PC relative relocation. + // Need to compensate for the -4 it had in the addend. + relocateOne(Loc, R_X86_64_TPOFF32, Val + 4); } -// This function applies a TLS relocation with an optimization as described -// in the Ulrich's document. As a result of rewriting instructions at the -// relocation target, relocations immediately follow the TLS relocation (which -// would be applied to rewritten instructions) may have to be skipped. -// This function returns a number of relocations that need to be skipped. -unsigned X86_64TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA, - const SymbolBody &S) const { - switch (Type) { - case R_X86_64_DTPOFF32: - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); - return 0; - case R_X86_64_GOTTPOFF: - relocateTlsIeToLe(Loc, BufEnd, P, SA); - return 0; - case R_X86_64_TLSGD: { - if (canBePreempted(&S, true)) - relocateTlsGdToIe(Loc, BufEnd, P, SA); - else - relocateTlsGdToLe(Loc, BufEnd, P, SA); - // The next relocation should be against __tls_get_addr, so skip it - return 1; +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // Convert + // leaq bar@tlsld(%rip), %rdi + // callq __tls_get_addr@PLT + // leaq bar@dtpoff(%rax), %rcx + // to + // .word 0x6666 + // .byte 0x66 + // mov %fs:0,%rax + // leaq bar@tpoff(%rax), %rcx + if (Type == R_X86_64_DTPOFF64) { + write64le(Loc, Val); + return; } - case R_X86_64_TLSLD: - relocateTlsLdToLe(Loc, BufEnd, P, SA); - // The next relocation should be against __tls_get_addr, so skip it - return 1; + if (Type == R_X86_64_DTPOFF32) { + relocateOne(Loc, R_X86_64_TPOFF32, Val); + return; } - llvm_unreachable("Unknown TLS optimization"); + + const uint8_t Inst[] = { + 0x66, 0x66, // .word 0x6666 + 0x66, // .byte 0x66 + 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax + }; + memcpy(Loc - 3, Inst, sizeof(Inst)); } -void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { +template <class ELFT> +void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { switch (Type) { case R_X86_64_32: - checkUInt<32>(SA, Type); - write32le(Loc, SA); + checkUInt<32>(Val, Type); + write32le(Loc, Val); break; case R_X86_64_32S: - checkInt<32>(SA, Type); - write32le(Loc, SA); - break; - case R_X86_64_64: - write64le(Loc, SA); - break; - case R_X86_64_DTPOFF32: - write32le(Loc, SA); - break; - case R_X86_64_DTPOFF64: - write64le(Loc, SA); - break; + case R_X86_64_TPOFF32: + case R_X86_64_GOT32: case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: case R_X86_64_PC32: + case R_X86_64_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: - write32le(Loc, SA - P); - break; + case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: - write32le(Loc, ZA); - break; - case R_X86_64_SIZE64: - write64le(Loc, ZA); - break; - case R_X86_64_TPOFF32: { - uint64_t Val = SA - Out<ELF64LE>::TlsPhdr->p_memsz; checkInt<32>(Val, Type); write32le(Loc, Val); break; - } - case R_X86_64_TPOFF64: - write32le(Loc, SA - P); + case R_X86_64_64: + case R_X86_64_DTPOFF64: + case R_X86_64_SIZE64: + case R_X86_64_PC64: + write64le(Loc, Val); break; default: - error("unrecognized reloc " + Twine(Type)); + fatal("unrecognized reloc " + Twine(Type)); + } +} + +template <class ELFT> +RelExpr X86_64TargetInfo<ELFT>::adjustRelaxExpr(uint32_t Type, + const uint8_t *Data, + RelExpr RelExpr) const { + if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) + return RelExpr; + const uint8_t Op = Data[-2]; + const uint8_t ModRm = Data[-1]; + // FIXME: When PIC is disabled and foo is defined locally in the + // lower 32 bit address space, memory operand in mov can be converted into + // immediate operand. Otherwise, mov must be changed to lea. We support only + // latter relaxation at this moment. + if (Op == 0x8b) + return R_RELAX_GOT_PC; + // Relax call and jmp. + if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) + return R_RELAX_GOT_PC; + + // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. + // If PIC then no relaxation is available. + // We also don't relax test/binop instructions without REX byte, + // they are 32bit operations and not common to have. + assert(Type == R_X86_64_REX_GOTPCRELX); + return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; +} + +// A subset of relaxations can only be applied for no-PIC. This method +// handles such relaxations. Instructions encoding information was taken from: +// "Intel 64 and IA-32 Architectures Software Developer's Manual V2" +// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ +// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, + uint8_t Op, uint8_t ModRm) const { + const uint8_t Rex = Loc[-3]; + // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". + if (Op == 0x85) { + // See "TEST-Logical Compare" (4-428 Vol. 2B), + // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). + + // ModR/M byte has form XX YYY ZZZ, where + // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). + // XX has different meanings: + // 00: The operand's memory address is in reg1. + // 01: The operand's memory address is reg1 + a byte-sized displacement. + // 10: The operand's memory address is reg1 + a word-sized displacement. + // 11: The operand is reg1 itself. + // If an instruction requires only one operand, the unused reg2 field + // holds extra opcode bits rather than a register code + // 0xC0 == 11 000 000 binary. + // 0x38 == 00 111 000 binary. + // We transfer reg2 to reg1 here as operand. + // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. + + // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 + // See "TEST-Logical Compare" (4-428 Vol. 2B). + Loc[-2] = 0xf7; + + // Move R bit to the B bit in REX byte. + // REX byte is encoded as 0100WRXB, where + // 0100 is 4bit fixed pattern. + // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the + // default operand size is used (which is 32-bit for most but not all + // instructions). + // REX.R This 1-bit value is an extension to the MODRM.reg field. + // REX.X This 1-bit value is an extension to the SIB.index field. + // REX.B This 1-bit value is an extension to the MODRM.rm field or the + // SIB.base field. + // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + relocateOne(Loc, R_X86_64_PC32, Val); + return; + } + + // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub + // or xor operations. + + // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". + // Logic is close to one for test instruction above, but we also + // write opcode extension here, see below for details. + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. + + // Primary opcode is 0x81, opcode extension is one of: + // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, + // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. + // This value was wrote to MODRM.reg in a line above. + // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), + // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for + // descriptions about each operation. + Loc[-2] = 0x81; + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + relocateOne(Loc, R_X86_64_PC32, Val); +} + +template <class ELFT> +void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const { + const uint8_t Op = Loc[-2]; + const uint8_t ModRm = Loc[-1]; + + // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". + if (Op == 0x8b) { + Loc[-2] = 0x8d; + relocateOne(Loc, R_X86_64_PC32, Val); + return; + } + + if (Op != 0xff) { + // We are relaxing a rip relative to an absolute, so compensate + // for the old -4 addend. + assert(!Config->Pic); + relaxGotNoPic(Loc, Val + 4, Op, ModRm); + return; + } + + // Convert call/jmp instructions. + if (ModRm == 0x15) { + // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". + // Instead we convert to "addr32 call foo" where addr32 is an instruction + // prefix. That makes result expression to be a single instruction. + Loc[-2] = 0x67; // addr32 prefix + Loc[-1] = 0xe8; // call + relocateOne(Loc, R_X86_64_PC32, Val); + return; } + + // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". + // jmp doesn't return, so it is fine to use nop here, it is just a stub. + assert(ModRm == 0x25); + Loc[-2] = 0xe9; // jmp + Loc[3] = 0x90; // nop + relocateOne(Loc - 1, R_X86_64_PC32, Val + 1); } // Relocation masks following the #lo(value), #hi(value), #ha(value), @@ -933,41 +954,32 @@ static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } PPCTargetInfo::PPCTargetInfo() {} -void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} -void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} -void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const {} -bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return false; -} -bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { - return false; -} -bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; } -void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { +void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: - write16be(Loc, applyPPCHa(SA)); + write16be(Loc, applyPPCHa(Val)); break; case R_PPC_ADDR16_LO: - write16be(Loc, applyPPCLo(SA)); + write16be(Loc, applyPPCLo(Val)); break; default: - error("unrecognized reloc " + Twine(Type)); + fatal("unrecognized reloc " + Twine(Type)); } } +RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + return R_ABS; +} + PPC64TargetInfo::PPC64TargetInfo() { - PCRelReloc = R_PPC64_REL24; - GotReloc = R_PPC64_GLOB_DAT; - RelativeReloc = R_PPC64_RELATIVE; + PltRel = GotRel = R_PPC64_GLOB_DAT; + RelativeRel = R_PPC64_RELATIVE; + GotEntrySize = 8; + GotPltEntrySize = 8; PltEntrySize = 32; + PltHeaderSize = 0; // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). @@ -981,33 +993,46 @@ PPC64TargetInfo::PPC64TargetInfo() { // // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. - VAStart = 0x10000000; + DefaultImageBase = 0x10000000; } -uint64_t getPPC64TocBase() { - // The TOC consists of sections .got, .toc, .tocbss, .plt in that - // order. The TOC starts where the first of these sections starts. +static uint64_t PPC64TocOffset = 0x8000; - // FIXME: This obviously does not do the right thing when there is no .got - // section, but there is a .toc or .tocbss section. +uint64_t getPPC64TocBase() { + // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The + // TOC starts where the first of these sections starts. We always create a + // .got when we see a relocation that uses it, so for us the start is always + // the .got. uint64_t TocVA = Out<ELF64BE>::Got->getVA(); - if (!TocVA) - TocVA = Out<ELF64BE>::Plt->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. - return TocVA + 0x8000; + return TocVA + PPC64TocOffset; } -void PPC64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} -void PPC64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} -void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_PPC64_TOC16: + case R_PPC64_TOC16_DS: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_HI: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + return R_GOTREL; + case R_PPC64_TOC: + return R_PPC_TOC; + case R_PPC64_REL24: + return R_PPC_PLT_OPD; + } +} + +void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { uint64_t Off = GotEntryAddr - getPPC64TocBase(); // FIXME: What we should do, in theory, is get the offset of the function @@ -1026,181 +1051,193 @@ void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, write32be(Buf + 28, 0x4e800420); // bctr } -bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - if (relocNeedsPlt(Type, S)) - return true; - +static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) { + uint64_t V = Val - PPC64TocOffset; switch (Type) { - default: return false; - case R_PPC64_GOT16: - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16_HA: - case R_PPC64_GOT16_HI: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - return true; - } -} - -bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { - // These are function calls that need to be redirected through a PLT stub. - return Type == R_PPC64_REL24 && canBePreempted(&S, false); -} - -bool PPC64TargetInfo::isRelRelative(uint32_t Type) const { - switch (Type) { - default: - return true; - case R_PPC64_ADDR64: - case R_PPC64_TOC: - return false; + case R_PPC64_TOC16: return {R_PPC64_ADDR16, V}; + case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V}; + case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V}; + case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V}; + case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V}; + case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V}; + default: return {Type, Val}; } } -void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { - uint64_t TB = getPPC64TocBase(); - - // For a TOC-relative relocation, adjust the addend and proceed in terms of - // the corresponding ADDR16 relocation type. - switch (Type) { - case R_PPC64_TOC16: Type = R_PPC64_ADDR16; SA -= TB; break; - case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; SA -= TB; break; - case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; SA -= TB; break; - case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; SA -= TB; break; - case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; SA -= TB; break; - case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; SA -= TB; break; - default: break; - } +void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // For a TOC-relative relocation, proceed in terms of the corresponding + // ADDR16 relocation type. + std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { - checkAlignment<4>(SA, Type); + checkAlignment<4>(Val, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; - write16be(Loc + 2, (AALK & 3) | (SA & 0xfffc)); + write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: - checkInt<16>(SA, Type); - write16be(Loc, SA); + checkInt<16>(Val, Type); + write16be(Loc, Val); break; case R_PPC64_ADDR16_DS: - checkInt<16>(SA, Type); - write16be(Loc, (read16be(Loc) & 3) | (SA & ~3)); + checkInt<16>(Val, Type); + write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: - write16be(Loc, applyPPCHa(SA)); + case R_PPC64_REL16_HA: + write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_ADDR16_HI: - write16be(Loc, applyPPCHi(SA)); + case R_PPC64_REL16_HI: + write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_ADDR16_HIGHER: - write16be(Loc, applyPPCHigher(SA)); + write16be(Loc, applyPPCHigher(Val)); break; case R_PPC64_ADDR16_HIGHERA: - write16be(Loc, applyPPCHighera(SA)); + write16be(Loc, applyPPCHighera(Val)); break; case R_PPC64_ADDR16_HIGHEST: - write16be(Loc, applyPPCHighest(SA)); + write16be(Loc, applyPPCHighest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: - write16be(Loc, applyPPCHighesta(SA)); + write16be(Loc, applyPPCHighesta(Val)); break; case R_PPC64_ADDR16_LO: - write16be(Loc, applyPPCLo(SA)); + write16be(Loc, applyPPCLo(Val)); break; case R_PPC64_ADDR16_LO_DS: - write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(SA) & ~3)); + case R_PPC64_REL16_LO: + write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); break; case R_PPC64_ADDR32: - checkInt<32>(SA, Type); - write32be(Loc, SA); + case R_PPC64_REL32: + checkInt<32>(Val, Type); + write32be(Loc, Val); break; case R_PPC64_ADDR64: - write64be(Loc, SA); - break; - case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(SA - P)); - break; - case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(SA - P)); - break; - case R_PPC64_REL16_LO: - write16be(Loc, applyPPCLo(SA - P)); + case R_PPC64_REL64: + case R_PPC64_TOC: + write64be(Loc, Val); break; case R_PPC64_REL24: { - // If we have an undefined weak symbol, we might get here with a symbol - // address of zero. That could overflow, but the code must be unreachable, - // so don't bother doing anything at all. - if (!SA) - break; - - uint64_t PltStart = Out<ELF64BE>::Plt->getVA(); - uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize(); - bool InPlt = PltStart <= SA && SA < PltEnd; - - if (!InPlt && Out<ELF64BE>::Opd) { - // If this is a local call, and we currently have the address of a - // function-descriptor, get the underlying code address instead. - uint64_t OpdStart = Out<ELF64BE>::Opd->getVA(); - uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize(); - bool InOpd = OpdStart <= SA && SA < OpdEnd; - - if (InOpd) - SA = read64be(&Out<ELF64BE>::OpdBuf[SA - OpdStart]); - } - uint32_t Mask = 0x03FFFFFC; - checkInt<24>(SA - P, Type); - write32be(Loc, (read32be(Loc) & ~Mask) | ((SA - P) & Mask)); - - uint32_t Nop = 0x60000000; - if (InPlt && Loc + 8 <= BufEnd && read32be(Loc + 4) == Nop) - write32be(Loc + 4, 0xe8410028); // ld %r2, 40(%r1) + checkInt<24>(Val, Type); + write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); break; } - case R_PPC64_REL32: - checkInt<32>(SA - P, Type); - write32be(Loc, SA - P); - break; - case R_PPC64_REL64: - write64be(Loc, SA - P); - break; - case R_PPC64_TOC: - write64be(Loc, SA); - break; default: - error("unrecognized reloc " + Twine(Type)); + fatal("unrecognized reloc " + Twine(Type)); } } AArch64TargetInfo::AArch64TargetInfo() { - CopyReloc = R_AARCH64_COPY; - IRelativeReloc = R_AARCH64_IRELATIVE; - GotReloc = R_AARCH64_GLOB_DAT; - PltReloc = R_AARCH64_JUMP_SLOT; - TlsGotReloc = R_AARCH64_TLS_TPREL64; - LazyRelocations = true; + CopyRel = R_AARCH64_COPY; + RelativeRel = R_AARCH64_RELATIVE; + IRelativeRel = R_AARCH64_IRELATIVE; + GotRel = R_AARCH64_GLOB_DAT; + PltRel = R_AARCH64_JUMP_SLOT; + TlsDescRel = R_AARCH64_TLSDESC; + TlsGotRel = R_AARCH64_TLS_TPREL64; + GotEntrySize = 8; + GotPltEntrySize = 8; PltEntrySize = 16; - PltZeroEntrySize = 32; + PltHeaderSize = 32; + + // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant + // 1 of the tls structures and the tcb size is 16. + TcbSize = 16; +} + +RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, + const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_AARCH64_TLSDESC_ADR_PAGE21: + return R_TLSDESC_PAGE; + case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: + return R_TLSDESC; + case R_AARCH64_TLSDESC_CALL: + return R_HINT; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + return R_TLS; + case R_AARCH64_CALL26: + case R_AARCH64_CONDBR19: + case R_AARCH64_JUMP26: + case R_AARCH64_TSTBR14: + return R_PLT_PC; + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_ADR_PREL_LO21: + return R_PC; + case R_AARCH64_ADR_PREL_PG_HI21: + return R_PAGE_PC; + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + return R_GOT; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + return R_GOT_PAGE_PC; + } +} + +RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) { + if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) + return R_RELAX_TLS_GD_TO_IE_PAGE_PC; + return R_RELAX_TLS_GD_TO_IE_ABS; + } + return Expr; +} + +bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { + switch (Type) { + default: + return false; + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + return true; + } } -unsigned AArch64TargetInfo::getDynReloc(unsigned Type) const { +bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const { + return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || + Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; +} + +uint32_t AArch64TargetInfo::getDynRel(uint32_t Type) const { if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64) return Type; - StringRef S = getELFRelocationTypeName(EM_AARCH64, Type); - error("Relocation " + S + " cannot be used when making a shared object; " - "recompile with -fPIC."); + // Keep it going with a dummy value so that we can find more reloc errors. + errorDynRel(Type); + return R_AARCH64_ABS32; } -void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { +void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write64le(Buf, Out<ELF64LE>::Plt->getVA()); } -void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { +static uint64_t getAArch64Page(uint64_t Expr) { + return Expr & (~static_cast<uint64_t>(0xFFF)); +} + +void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) @@ -1213,18 +1250,17 @@ void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, }; memcpy(Buf, PltData, sizeof(PltData)); - relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr + 4, - GotEntryAddr + 16); - relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 8, - GotEntryAddr + 16); - relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 12, - GotEntryAddr + 16); + uint64_t Got = Out<ELF64LE>::GotPlt->getVA(); + uint64_t Plt = Out<ELF64LE>::Plt->getVA(); + relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); + relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); + relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } -void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] @@ -1233,377 +1269,851 @@ void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, }; memcpy(Buf, Inst, sizeof(Inst)); - relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr, - GotEntryAddr); - relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4, - GotEntryAddr); - relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8, - GotEntryAddr); + relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr)); + relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr); + relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr); } -unsigned AArch64TargetInfo::getTlsGotReloc(unsigned Type) const { - if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || - Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) - return Type; - return TlsGotReloc; +static void updateAArch64Addr(uint8_t *L, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); } -bool AArch64TargetInfo::isTlsDynReloc(unsigned Type, - const SymbolBody &S) const { - return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || - Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; +static inline void updateAArch64Add(uint8_t *L, uint64_t Imm) { + or32le(L, (Imm & 0xFFF) << 10); } -bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { - if (Config->Shared) - return false; +void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { switch (Type) { - default: - return false; case R_AARCH64_ABS16: + case R_AARCH64_PREL16: + checkIntUInt<16>(Val, Type); + write16le(Loc, Val); + break; case R_AARCH64_ABS32: + case R_AARCH64_PREL32: + checkIntUInt<32>(Val, Type); + write32le(Loc, Val); + break; case R_AARCH64_ABS64: + case R_AARCH64_PREL64: + write64le(Loc, Val); + break; case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_ADR_PREL_LO21: + // This relocation stores 12 bits and there's no instruction + // to do it. Instead, we do a 32 bits store of the value + // of r_addend bitwise-or'ed Loc. This assumes that the addend + // bits in Loc are zero. + or32le(Loc, (Val & 0xFFF) << 10); + break; + case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSDESC_ADR_PAGE21: + checkInt<33>(Val, Type); + updateAArch64Addr(Loc, Val >> 12); + break; + case R_AARCH64_ADR_PREL_LO21: + checkInt<21>(Val, Type); + updateAArch64Addr(Loc, Val); + break; + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + checkInt<28>(Val, Type); + or32le(Loc, (Val & 0x0FFFFFFC) >> 2); + break; + case R_AARCH64_CONDBR19: + checkInt<21>(Val, Type); + or32le(Loc, (Val & 0x1FFFFC) << 3); + break; + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12_NC: + checkAlignment<8>(Val, Type); + or32le(Loc, (Val & 0xFF8) << 7); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + or32le(Loc, (Val & 0x0FF8) << 6); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + or32le(Loc, (Val & 0x0FFC) << 9); + break; case R_AARCH64_LDST8_ABS_LO12_NC: + or32le(Loc, (Val & 0xFFF) << 10); + break; case R_AARCH64_LDST32_ABS_LO12_NC: + or32le(Loc, (Val & 0xFFC) << 8); + break; case R_AARCH64_LDST64_ABS_LO12_NC: - if (auto *SS = dyn_cast<SharedSymbol<ELF64LE>>(&S)) - return SS->Sym.getType() == STT_OBJECT; - return false; + or32le(Loc, (Val & 0xFF8) << 7); + break; + case R_AARCH64_TSTBR14: + checkInt<16>(Val, Type); + or32le(Loc, (Val & 0xFFFC) << 3); + break; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + checkInt<24>(Val, Type); + updateAArch64Add(Loc, Val >> 12); + break; + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: + updateAArch64Add(Loc, Val); + break; + default: + fatal("unrecognized reloc " + Twine(Type)); } } -bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, - const SymbolBody &S) const { +void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // TLSDESC Global-Dynamic relocation are in the form: + // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] + // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // .tlsdesccall [R_AARCH64_TLSDESC_CALL] + // blr x1 + // And it can optimized to: + // movz x0, #0x0, lsl #16 + // movk x0, #0x10 + // nop + // nop + checkUInt<32>(Val, Type); + switch (Type) { - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - return true; + case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_CALL: + write32le(Loc, 0xd503201f); // nop + return; + case R_AARCH64_TLSDESC_ADR_PAGE21: + write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz + return; + case R_AARCH64_TLSDESC_LD64_LO12_NC: + write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk + return; default: - return relocNeedsPlt(Type, S); + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type, - const SymbolBody &S) const { - if (isGnuIFunc<ELF64LE>(S)) - return true; +void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + // TLSDESC Global-Dynamic relocation are in the form: + // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] + // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // .tlsdesccall [R_AARCH64_TLSDESC_CALL] + // blr x1 + // And it can optimized to: + // adrp x0, :gottprel:v + // ldr x0, [x0, :gottprel_lo12:v] + // nop + // nop + switch (Type) { + case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_CALL: + write32le(Loc, 0xd503201f); // nop + break; + case R_AARCH64_TLSDESC_ADR_PAGE21: + write32le(Loc, 0x90000000); // adrp + relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); + break; + case R_AARCH64_TLSDESC_LD64_LO12_NC: + write32le(Loc, 0xf9400000); // ldr + relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); + break; default: - return false; - case R_AARCH64_CALL26: - case R_AARCH64_CONDBR19: - case R_AARCH64_JUMP26: - case R_AARCH64_TSTBR14: - return canBePreempted(&S, true); + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -static void updateAArch64Adr(uint8_t *L, uint64_t Imm) { - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5; - uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5); - write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); +void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + checkUInt<32>(Val, Type); + + if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { + // Generate MOVZ. + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); + return; + } + if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { + // Generate MOVK. + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); + return; + } + llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } -// Page(Expr) is the page address of the expression Expr, defined -// as (Expr & ~0xFFF). (This applies even if the machine page size -// supported by the platform has a different value.) -static uint64_t getAArch64Page(uint64_t Expr) { - return Expr & (~static_cast<uint64_t>(0xFFF)); +AMDGPUTargetInfo::AMDGPUTargetInfo() { + GotRel = R_AMDGPU_ABS64; + GotEntrySize = 8; } -void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, uint64_t SA, - uint64_t ZA, uint8_t *PairedLoc) const { +void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { switch (Type) { - case R_AARCH64_ABS16: - checkIntUInt<16>(SA, Type); - write16le(Loc, SA); - break; - case R_AARCH64_ABS32: - checkIntUInt<32>(SA, Type); - write32le(Loc, SA); - break; - case R_AARCH64_ABS64: - write64le(Loc, SA); - break; - case R_AARCH64_ADD_ABS_LO12_NC: - // This relocation stores 12 bits and there's no instruction - // to do it. Instead, we do a 32 bits store of the value - // of r_addend bitwise-or'ed Loc. This assumes that the addend - // bits in Loc are zero. - or32le(Loc, (SA & 0xFFF) << 10); - break; - case R_AARCH64_ADR_GOT_PAGE: { - uint64_t X = getAArch64Page(SA) - getAArch64Page(P); - checkInt<33>(X, Type); - updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] + case R_AMDGPU_GOTPCREL: + case R_AMDGPU_REL32: + write32le(Loc, Val); break; + default: + fatal("unrecognized reloc " + Twine(Type)); } - case R_AARCH64_ADR_PREL_LO21: { - uint64_t X = SA - P; - checkInt<21>(X, Type); - updateAArch64Adr(Loc, X & 0x1FFFFF); - break; +} + +RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + case R_AMDGPU_REL32: + return R_PC; + case R_AMDGPU_GOTPCREL: + return R_GOT_PC; + default: + fatal("do not know how to handle relocation " + Twine(Type)); } - case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { - uint64_t X = getAArch64Page(SA) - getAArch64Page(P); - checkInt<33>(X, Type); - updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] - break; +} + +ARMTargetInfo::ARMTargetInfo() { + CopyRel = R_ARM_COPY; + RelativeRel = R_ARM_RELATIVE; + IRelativeRel = R_ARM_IRELATIVE; + GotRel = R_ARM_GLOB_DAT; + PltRel = R_ARM_JUMP_SLOT; + TlsGotRel = R_ARM_TLS_TPOFF32; + TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; + TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotEntrySize = 4; + GotPltEntrySize = 4; + PltEntrySize = 16; + PltHeaderSize = 20; +} + +RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_ARM_THM_JUMP11: + return R_PC; + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + return R_PLT_PC; + case R_ARM_GOTOFF32: + // (S + A) - GOT_ORG + return R_GOTREL; + case R_ARM_GOT_BREL: + // GOT(S) + A - GOT_ORG + return R_GOT_OFF; + case R_ARM_GOT_PREL: + // GOT(S) + - GOT_ORG + return R_GOT_PC; + case R_ARM_BASE_PREL: + // B(S) + A - P + // FIXME: currently B(S) assumed to be .got, this may not hold for all + // platforms. + return R_GOTONLY_PC; + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_PREL31: + case R_ARM_REL32: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: + return R_PC; } - case R_AARCH64_CALL26: - case R_AARCH64_JUMP26: { - uint64_t X = SA - P; - checkInt<28>(X, Type); - or32le(Loc, (X & 0x0FFFFFFC) >> 2); +} + +uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const { + if (Type == R_ARM_ABS32) + return Type; + // Keep it going with a dummy value so that we can find more reloc errors. + errorDynRel(Type); + return R_ARM_ABS32; +} + +void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { + write32le(Buf, Out<ELF32LE>::Plt->getVA()); +} + +void ARMTargetInfo::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! + 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 + 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr + 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] + 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t GotPlt = Out<ELF32LE>::GotPlt->getVA(); + uint64_t L1 = Out<ELF32LE>::Plt->getVA() + 8; + write32le(Buf + 16, GotPlt - L1 - 8); +} + +void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + // FIXME: Using simple code sequence with simple relocations. + // There is a more optimal sequence but it requires support for the group + // relocations. See ELF for the ARM Architecture Appendix A.3 + const uint8_t PltData[] = { + 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 + 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc + 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] + 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 + }; + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t L1 = PltEntryAddr + 4; + write32le(Buf + 12, GotEntryAddr - L1 - 8); +} + +RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType, + const InputFile &File, + const SymbolBody &S) const { + // A state change from ARM to Thumb and vice versa must go through an + // interworking thunk if the relocation type is not R_ARM_CALL or + // R_ARM_THM_CALL. + switch (RelocType) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + // Source is ARM, all PLT entries are ARM so no interworking required. + // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). + if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1)) + return R_THUNK_PC; break; - } - case R_AARCH64_CONDBR19: { - uint64_t X = SA - P; - checkInt<21>(X, Type); - or32le(Loc, (X & 0x1FFFFC) << 3); + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + // Source is Thumb, all PLT entries are ARM so interworking is required. + // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). + if (Expr == R_PLT_PC) + return R_THUNK_PLT_PC; + if ((S.getVA<ELF32LE>() & 1) == 0) + return R_THUNK_PC; break; } - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - checkAlignment<8>(SA, Type); - or32le(Loc, (SA & 0xFF8) << 7); + return Expr; +} + +void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { + switch (Type) { + case R_ARM_NONE: break; - case R_AARCH64_LDST8_ABS_LO12_NC: - or32le(Loc, (SA & 0xFFF) << 10); + case R_ARM_ABS32: + case R_ARM_BASE_PREL: + case R_ARM_GOTOFF32: + case R_ARM_GOT_BREL: + case R_ARM_GOT_PREL: + case R_ARM_REL32: + write32le(Loc, Val); break; - case R_AARCH64_LDST32_ABS_LO12_NC: - or32le(Loc, (SA & 0xFFC) << 8); + case R_ARM_PREL31: + checkInt<31>(Val, Type); + write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; - case R_AARCH64_LDST64_ABS_LO12_NC: - or32le(Loc, (SA & 0xFF8) << 7); + case R_ARM_CALL: + // R_ARM_CALL is used for BL and BLX instructions, depending on the + // value of bit 0 of Val, we must select a BL or BLX instruction + if (Val & 1) { + // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. + // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' + checkInt<26>(Val, Type); + write32le(Loc, 0xfa000000 | // opcode + ((Val & 2) << 23) | // H + ((Val >> 2) & 0x00ffffff)); // imm24 + break; + } + if ((read32le(Loc) & 0xfe000000) == 0xfa000000) + // BLX (always unconditional) instruction to an ARM Target, select an + // unconditional BL. + write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); + // fall through as BL encoding is shared with B + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + checkInt<26>(Val, Type); + write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; - case R_AARCH64_PREL16: - checkIntUInt<16>(SA - P, Type); - write16le(Loc, SA - P); + case R_ARM_THM_JUMP11: + checkInt<12>(Val, Type); + write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; - case R_AARCH64_PREL32: - checkIntUInt<32>(SA - P, Type); - write32le(Loc, SA - P); + case R_ARM_THM_JUMP19: + // Encoding T3: Val = S:J2:J1:imm6:imm11:0 + checkInt<21>(Val, Type); + write16le(Loc, + (read16le(Loc) & 0xfbc0) | // opcode cond + ((Val >> 10) & 0x0400) | // S + ((Val >> 12) & 0x003f)); // imm6 + write16le(Loc + 2, + 0x8000 | // opcode + ((Val >> 8) & 0x0800) | // J2 + ((Val >> 5) & 0x2000) | // J1 + ((Val >> 1) & 0x07ff)); // imm11 break; - case R_AARCH64_PREL64: - write64le(Loc, SA - P); + case R_ARM_THM_CALL: + // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the + // value of bit 0 of Val, we must select a BL or BLX instruction + if ((Val & 1) == 0) { + // Ensure BLX destination is 4-byte aligned. As BLX instruction may + // only be two byte aligned. This must be done before overflow check + Val = alignTo(Val, 4); + } + // Bit 12 is 0 for BLX, 1 for BL + write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); + // Fall through as rest of encoding is the same as B.W + case R_ARM_THM_JUMP24: + // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 + // FIXME: Use of I1 and I2 require v6T2ops + checkInt<25>(Val, Type); + write16le(Loc, + 0xf000 | // opcode + ((Val >> 14) & 0x0400) | // S + ((Val >> 12) & 0x03ff)); // imm10 + write16le(Loc + 2, + (read16le(Loc + 2) & 0xd000) | // opcode + (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 + (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 + ((Val >> 1) & 0x07ff)); // imm11 + break; + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVW_PREL_NC: + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | + (Val & 0x0fff)); break; - case R_AARCH64_TSTBR14: { - uint64_t X = SA - P; - checkInt<16>(X, Type); - or32le(Loc, (X & 0xFFFC) << 3); + case R_ARM_MOVT_ABS: + case R_ARM_MOVT_PREL: + checkInt<32>(Val, Type); + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | + (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); + break; + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVT_PREL: + // Encoding T1: A = imm4:i:imm3:imm8 + checkInt<32>(Val, Type); + write16le(Loc, + 0xf2c0 | // opcode + ((Val >> 17) & 0x0400) | // i + ((Val >> 28) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val >> 12) & 0x7000) | // imm3 + ((Val >> 16) & 0x00ff)); // imm8 break; + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVW_PREL_NC: + // Encoding T3: A = imm4:i:imm3:imm8 + write16le(Loc, + 0xf240 | // opcode + ((Val >> 1) & 0x0400) | // i + ((Val >> 12) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val << 4) & 0x7000) | // imm3 + (Val & 0x00ff)); // imm8 + break; + default: + fatal("unrecognized reloc " + Twine(Type)); + } +} + +uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, + uint32_t Type) const { + switch (Type) { + default: + return 0; + case R_ARM_ABS32: + case R_ARM_BASE_PREL: + case R_ARM_GOTOFF32: + case R_ARM_GOT_BREL: + case R_ARM_GOT_PREL: + case R_ARM_REL32: + return SignExtend64<32>(read32le(Buf)); + case R_ARM_PREL31: + return SignExtend64<31>(read32le(Buf)); + case R_ARM_CALL: + case R_ARM_JUMP24: + case R_ARM_PC24: + case R_ARM_PLT32: + return SignExtend64<26>(read32le(Buf) << 2); + case R_ARM_THM_JUMP11: + return SignExtend64<12>(read16le(Buf) << 1); + case R_ARM_THM_JUMP19: { + // Encoding T3: A = S:J2:J1:imm10:imm6:0 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<20>(((Hi & 0x0400) << 10) | // S + ((Lo & 0x0800) << 8) | // J2 + ((Lo & 0x2000) << 5) | // J1 + ((Hi & 0x003f) << 12) | // imm6 + ((Lo & 0x07ff) << 1)); // imm11:0 + } + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: { + // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 + // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) + // FIXME: I1 and I2 require v6T2ops + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<24>(((Hi & 0x0400) << 14) | // S + (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 + (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 + ((Hi & 0x003ff) << 12) | // imm0 + ((Lo & 0x007ff) << 1)); // imm11:0 + } + // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and + // MOVT is in the range -32768 <= A < 32768 + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: { + uint64_t Val = read32le(Buf) & 0x000f0fff; + return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); + } + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: { + // Encoding T3: A = imm4:i:imm3:imm8 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 + ((Hi & 0x0400) << 1) | // i + ((Lo & 0x7000) >> 4) | // imm3 + (Lo & 0x00ff)); // imm8 } + } +} + +template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() { + GotPltHeaderEntriesNum = 2; + PageSize = 65536; + GotEntrySize = sizeof(typename ELFT::uint); + GotPltEntrySize = sizeof(typename ELFT::uint); + PltEntrySize = 16; + PltHeaderSize = 32; + CopyRel = R_MIPS_COPY; + PltRel = R_MIPS_JUMP_SLOT; + if (ELFT::Is64Bits) { + RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; + TlsGotRel = R_MIPS_TLS_TPREL64; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; + TlsOffsetRel = R_MIPS_TLS_DTPREL64; + } else { + RelativeRel = R_MIPS_REL32; + TlsGotRel = R_MIPS_TLS_TPREL32; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; + TlsOffsetRel = R_MIPS_TLS_DTPREL32; + } +} + +template <class ELFT> +RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, + const SymbolBody &S) const { + if (ELFT::Is64Bits) + // See comment in the calculateMips64RelChain. + Type &= 0xff; + switch (Type) { default: - error("unrecognized reloc " + Twine(Type)); + return R_ABS; + case R_MIPS_JALR: + return R_HINT; + case R_MIPS_GPREL16: + case R_MIPS_GPREL32: + return R_GOTREL; + case R_MIPS_26: + return R_PLT; + case R_MIPS_HI16: + case R_MIPS_LO16: + case R_MIPS_GOT_OFST: + // MIPS _gp_disp designates offset between start of function and 'gp' + // pointer into GOT. __gnu_local_gp is equal to the current value of + // the 'gp'. Therefore any relocations against them do not require + // dynamic relocation. + if (&S == ElfSym<ELFT>::MipsGpDisp) + return R_PC; + return R_ABS; + case R_MIPS_PC32: + case R_MIPS_PC16: + case R_MIPS_PC19_S2: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: + case R_MIPS_PCHI16: + case R_MIPS_PCLO16: + return R_PC; + case R_MIPS_GOT16: + if (S.isLocal()) + return R_MIPS_GOT_LOCAL_PAGE; + // fallthrough + case R_MIPS_CALL16: + case R_MIPS_GOT_DISP: + case R_MIPS_TLS_GOTTPREL: + return R_MIPS_GOT_OFF; + case R_MIPS_GOT_PAGE: + return R_MIPS_GOT_LOCAL_PAGE; + case R_MIPS_TLS_GD: + return R_MIPS_TLSGD; + case R_MIPS_TLS_LDM: + return R_MIPS_TLSLD; } } -AMDGPUTargetInfo::AMDGPUTargetInfo() {} +template <class ELFT> +uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const { + if (Type == R_MIPS_32 || Type == R_MIPS_64) + return RelativeRel; + // Keep it going with a dummy value so that we can find more reloc errors. + errorDynRel(Type); + return R_MIPS_32; +} -void AMDGPUTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { - llvm_unreachable("not implemented"); +template <class ELFT> +bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const { + return Type == R_MIPS_TLS_LDM; } -void AMDGPUTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { - llvm_unreachable("not implemented"); +template <class ELFT> +bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const { + return Type == R_MIPS_TLS_GD; } -void AMDGPUTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - llvm_unreachable("not implemented"); +template <class ELFT> +void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { + write32<ELFT::TargetEndianness>(Buf, Out<ELFT>::Plt->getVA()); } -bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return false; +static uint16_t mipsHigh(uint64_t V) { return (V + 0x8000) >> 16; } + +template <endianness E, uint8_t BSIZE, uint8_t SHIFT> +static int64_t getPcRelocAddend(const uint8_t *Loc) { + uint32_t Instr = read32<E>(Loc); + uint32_t Mask = 0xffffffff >> (32 - BSIZE); + return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT); } -bool AMDGPUTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { - return false; +template <endianness E, uint8_t BSIZE, uint8_t SHIFT> +static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { + uint32_t Mask = 0xffffffff >> (32 - BSIZE); + uint32_t Instr = read32<E>(Loc); + if (SHIFT > 0) + checkAlignment<(1 << SHIFT)>(V, Type); + checkInt<BSIZE + SHIFT>(V, Type); + write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); } -// Implementing relocations for AMDGPU is low priority since most -// programs don't use relocations now. Thus, this function is not -// actually called (relocateOne is called for each relocation). -// That's why the AMDGPU port works without implementing this function. -void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA, - uint8_t *PairedLoc) const { - llvm_unreachable("not implemented"); +template <endianness E> +static void writeMipsHi16(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32<E>(Loc); + write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(V)); } -template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() { - PageSize = 65536; - GotHeaderEntriesNum = 2; +template <endianness E> +static void writeMipsLo16(uint8_t *Loc, uint64_t V) { + uint32_t Instr = read32<E>(Loc); + write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff)); } template <class ELFT> -void MipsTargetInfo<ELFT>::writeGotHeaderEntries(uint8_t *Buf) const { - typedef typename ELFFile<ELFT>::Elf_Off Elf_Off; - auto *P = reinterpret_cast<Elf_Off *>(Buf); - // Module pointer - P[1] = ELFT::Is64Bits ? 0x8000000000000000 : 0x80000000; +void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const { + const endianness E = ELFT::TargetEndianness; + write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) + write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) + write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) + write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28 + write32<E>(Buf + 16, 0x03e07825); // move $15, $31 + write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 + write32<E>(Buf + 24, 0x0320f809); // jalr $25 + write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2 + uint64_t Got = Out<ELFT>::GotPlt->getVA(); + writeMipsHi16<E>(Buf, Got); + writeMipsLo16<E>(Buf + 4, Got); + writeMipsLo16<E>(Buf + 8, Got); } template <class ELFT> -void MipsTargetInfo<ELFT>::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} -template <class ELFT> -void MipsTargetInfo<ELFT>::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} -template <class ELFT> -void MipsTargetInfo<ELFT>::writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const {} +void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const endianness E = ELFT::TargetEndianness; + write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) + write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) + write32<E>(Buf + 8, 0x03200008); // jr $25 + write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) + writeMipsHi16<E>(Buf, GotEntryAddr); + writeMipsLo16<E>(Buf + 4, GotEntryAddr); + writeMipsLo16<E>(Buf + 12, GotEntryAddr); +} template <class ELFT> -bool MipsTargetInfo<ELFT>::relocNeedsGot(uint32_t Type, - const SymbolBody &S) const { - return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16; +RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type, + const InputFile &File, + const SymbolBody &S) const { + // Any MIPS PIC code function is invoked with its address in register $t9. + // So if we have a branch instruction from non-PIC code to the PIC one + // we cannot make the jump directly and need to create a small stubs + // to save the target function address. + // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Type != R_MIPS_26) + return Expr; + auto *F = dyn_cast<ELFFileBase<ELFT>>(&File); + if (!F) + return Expr; + // If current file has PIC code, LA25 stub is not required. + if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) + return Expr; + auto *D = dyn_cast<DefinedRegular<ELFT>>(&S); + if (!D || !D->Section) + return Expr; + // LA25 is required if target file has PIC code + // or target symbol is a PIC symbol. + const ELFFile<ELFT> &DefFile = D->Section->getFile()->getObj(); + bool PicFile = DefFile.getHeader()->e_flags & EF_MIPS_PIC; + bool PicSym = (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC; + return (PicFile || PicSym) ? R_THUNK_ABS : Expr; } template <class ELFT> -bool MipsTargetInfo<ELFT>::relocNeedsPlt(uint32_t Type, - const SymbolBody &S) const { - return false; +uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf, + uint32_t Type) const { + const endianness E = ELFT::TargetEndianness; + switch (Type) { + default: + return 0; + case R_MIPS_32: + case R_MIPS_GPREL32: + return read32<E>(Buf); + case R_MIPS_26: + // FIXME (simon): If the relocation target symbol is not a PLT entry + // we should use another expression for calculation: + // ((A << 2) | (P & 0xf0000000)) >> 2 + return SignExtend64<28>(read32<E>(Buf) << 2); + case R_MIPS_GPREL16: + case R_MIPS_LO16: + case R_MIPS_PCLO16: + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_TPREL_HI16: + case R_MIPS_TLS_TPREL_LO16: + return SignExtend64<16>(read32<E>(Buf)); + case R_MIPS_PC16: + return getPcRelocAddend<E, 16, 2>(Buf); + case R_MIPS_PC19_S2: + return getPcRelocAddend<E, 19, 2>(Buf); + case R_MIPS_PC21_S2: + return getPcRelocAddend<E, 21, 2>(Buf); + case R_MIPS_PC26_S2: + return getPcRelocAddend<E, 26, 2>(Buf); + case R_MIPS_PC32: + return getPcRelocAddend<E, 32, 0>(Buf); + } } -static uint16_t mipsHigh(uint64_t V) { return (V + 0x8000) >> 16; } - -template <endianness E, uint8_t BSIZE> -static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t P, - uint64_t SA) { - uint32_t Mask = ~(0xffffffff << BSIZE); - uint32_t Instr = read32<E>(Loc); - int64_t A = SignExtend64<BSIZE + 2>((Instr & Mask) << 2); - checkAlignment<4>(SA + A, Type); - int64_t V = SA + A - P; - checkInt<BSIZE + 2>(V, Type); - write32<E>(Loc, (Instr & ~Mask) | ((V >> 2) & Mask)); +static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type, + uint64_t Val) { + // MIPS N64 ABI packs multiple relocations into the single relocation + // record. In general, all up to three relocations can have arbitrary + // types. In fact, Clang and GCC uses only a few combinations. For now, + // we support two of them. That is allow to pass at least all LLVM + // test suite cases. + // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 + // <any relocation> / R_MIPS_64 / R_MIPS_NONE + // The first relocation is a 'real' relocation which is calculated + // using the corresponding symbol's value. The second and the third + // relocations used to modify result of the first one: extend it to + // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation + // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf + uint32_t Type2 = (Type >> 8) & 0xff; + uint32_t Type3 = (Type >> 16) & 0xff; + if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) + return std::make_pair(Type, Val); + if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) + return std::make_pair(Type2, Val); + if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) + return std::make_pair(Type3, -Val); + error("unsupported relocations combination " + Twine(Type)); + return std::make_pair(Type & 0xff, Val); } template <class ELFT> -void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, uint64_t SA, - uint64_t ZA, uint8_t *PairedLoc) const { +void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { const endianness E = ELFT::TargetEndianness; + // Thread pointer and DRP offsets from the start of TLS data area. + // https://www.linux-mips.org/wiki/NPTL + if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16) + Val -= 0x8000; + else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16) + Val -= 0x7000; + if (ELFT::Is64Bits) + std::tie(Type, Val) = calculateMips64RelChain(Type, Val); switch (Type) { case R_MIPS_32: - add32<E>(Loc, SA); + case R_MIPS_GPREL32: + write32<E>(Loc, Val); break; - case R_MIPS_CALL16: - case R_MIPS_GOT16: { - int64_t V = SA - getMipsGpAddr<ELFT>(); - if (Type == R_MIPS_GOT16) - checkInt<16>(V, Type); - write32<E>(Loc, (read32<E>(Loc) & 0xffff0000) | (V & 0xffff)); + case R_MIPS_64: + write64<E>(Loc, Val); break; - } - case R_MIPS_GPREL16: { - uint32_t Instr = read32<E>(Loc); - int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr<ELFT>(); - checkInt<16>(V, Type); - write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff)); + case R_MIPS_26: + write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | (Val >> 2)); break; - } - case R_MIPS_GPREL32: - write32<E>(Loc, SA + int32_t(read32<E>(Loc)) - getMipsGpAddr<ELFT>()); + case R_MIPS_GOT_DISP: + case R_MIPS_GOT_PAGE: + case R_MIPS_GOT16: + case R_MIPS_GPREL16: + case R_MIPS_TLS_GD: + case R_MIPS_TLS_LDM: + checkInt<16>(Val, Type); + // fallthrough + case R_MIPS_CALL16: + case R_MIPS_GOT_OFST: + case R_MIPS_LO16: + case R_MIPS_PCLO16: + case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_GOTTPREL: + case R_MIPS_TLS_TPREL_LO16: + writeMipsLo16<E>(Loc, Val); break; - case R_MIPS_HI16: { - uint32_t Instr = read32<E>(Loc); - if (PairedLoc) { - uint64_t AHL = ((Instr & 0xffff) << 16) + - SignExtend64<16>(read32<E>(PairedLoc) & 0xffff); - write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA + AHL)); - } else { - warning("Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16"); - write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA)); - } + case R_MIPS_HI16: + case R_MIPS_PCHI16: + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_TPREL_HI16: + writeMipsHi16<E>(Loc, Val); break; - } case R_MIPS_JALR: // Ignore this optimization relocation for now break; - case R_MIPS_LO16: { - uint32_t Instr = read32<E>(Loc); - int64_t AHL = SignExtend64<16>(Instr & 0xffff); - write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL) & 0xffff)); - break; - } case R_MIPS_PC16: - applyMipsPcReloc<E, 16>(Loc, Type, P, SA); + applyMipsPcReloc<E, 16, 2>(Loc, Type, Val); break; case R_MIPS_PC19_S2: - applyMipsPcReloc<E, 19>(Loc, Type, P, SA); + applyMipsPcReloc<E, 19, 2>(Loc, Type, Val); break; case R_MIPS_PC21_S2: - applyMipsPcReloc<E, 21>(Loc, Type, P, SA); + applyMipsPcReloc<E, 21, 2>(Loc, Type, Val); break; case R_MIPS_PC26_S2: - applyMipsPcReloc<E, 26>(Loc, Type, P, SA); - break; - case R_MIPS_PCHI16: { - uint32_t Instr = read32<E>(Loc); - if (PairedLoc) { - uint64_t AHL = ((Instr & 0xffff) << 16) + - SignExtend64<16>(read32<E>(PairedLoc) & 0xffff); - write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA + AHL - P)); - } else { - warning("Can't find matching R_MIPS_PCLO16 relocation for R_MIPS_PCHI16"); - write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA - P)); - } + applyMipsPcReloc<E, 26, 2>(Loc, Type, Val); break; - } - case R_MIPS_PCLO16: { - uint32_t Instr = read32<E>(Loc); - int64_t AHL = SignExtend64<16>(Instr & 0xffff); - write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL - P) & 0xffff)); + case R_MIPS_PC32: + applyMipsPcReloc<E, 32, 0>(Loc, Type, Val); break; - } default: - error("unrecognized reloc " + Twine(Type)); + fatal("unrecognized reloc " + Twine(Type)); } } template <class ELFT> -bool MipsTargetInfo<ELFT>::isRelRelative(uint32_t Type) const { - switch (Type) { - default: - return false; - case R_MIPS_PC16: - case R_MIPS_PC19_S2: - case R_MIPS_PC21_S2: - case R_MIPS_PC26_S2: - case R_MIPS_PCHI16: - case R_MIPS_PCLO16: - return true; - } +bool MipsTargetInfo<ELFT>::usesOnlyLowPageBits(uint32_t Type) const { + return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } - -// _gp is a MIPS-specific ABI-defined symbol which points to -// a location that is relative to GOT. This function returns -// the value for the symbol. -template <class ELFT> typename ELFFile<ELFT>::uintX_t getMipsGpAddr() { - unsigned GPOffset = 0x7ff0; - if (uint64_t V = Out<ELFT>::Got->getVA()) - return V + GPOffset; - return 0; -} - -template uint32_t getMipsGpAddr<ELF32LE>(); -template uint32_t getMipsGpAddr<ELF32BE>(); -template uint64_t getMipsGpAddr<ELF64LE>(); -template uint64_t getMipsGpAddr<ELF64BE>(); } } diff --git a/ELF/Target.h b/ELF/Target.h index e9c5f4b31ae4..d335c1e051b7 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -10,76 +10,57 @@ #ifndef LLD_ELF_TARGET_H #define LLD_ELF_TARGET_H +#include "InputSection.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELF.h" #include <memory> namespace lld { -namespace elf2 { +namespace elf { +class InputFile; class SymbolBody; class TargetInfo { public: - unsigned getPageSize() const { return PageSize; } - uint64_t getVAStart() const; - unsigned getCopyReloc() const { return CopyReloc; } - unsigned getGotReloc() const { return GotReloc; } - unsigned getPltReloc() const { return PltReloc; } - unsigned getRelativeReloc() const { return RelativeReloc; } - unsigned getIRelativeReloc() const { return IRelativeReloc; } - bool isTlsLocalDynamicReloc(unsigned Type) const { - return Type == TlsLocalDynamicReloc; - } - bool isTlsGlobalDynamicReloc(unsigned Type) const { - return Type == TlsGlobalDynamicReloc; - } - unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; } - unsigned getTlsOffsetReloc() const { return TlsOffsetReloc; } - unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; } - unsigned getPltEntrySize() const { return PltEntrySize; } - bool supportsLazyRelocations() const { return LazyRelocations; } - unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; } - unsigned getGotPltHeaderEntriesNum() const { return GotPltHeaderEntriesNum; } - virtual unsigned getDynReloc(unsigned Type) const { return Type; } - virtual bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const { - return false; - } - virtual unsigned getTlsGotReloc(unsigned Type = -1) const { - return TlsGotReloc; - } - virtual void writeGotHeaderEntries(uint8_t *Buf) const; - virtual void writeGotPltHeaderEntries(uint8_t *Buf) const; - virtual void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const = 0; - virtual void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const = 0; - virtual void writePltEntry(uint8_t *Buf, uint64_t GotAddr, - uint64_t GotEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const = 0; + virtual bool isTlsInitialExecRel(uint32_t Type) const; + virtual bool isTlsLocalDynamicRel(uint32_t Type) const; + virtual bool isTlsGlobalDynamicRel(uint32_t Type) const; + virtual uint32_t getDynRel(uint32_t Type) const { return Type; } + virtual void writeGotPltHeader(uint8_t *Buf) const {} + virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {}; + virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const; - // Returns true if a relocation is relative to the place being relocated, - // such as relocations used for PC-relative instructions. Such relocations - // need not be fixed up if an image is loaded to a different address than - // the link-time address. So we don't have to emit a relocation for the - // dynamic linker if isRelRelative returns true. - virtual bool isRelRelative(uint32_t Type) const; + // If lazy binding is supported, the first entry of the PLT has code + // to call the dynamic linker to resolve PLT entries the first time + // they are called. This function writes that code. + virtual void writePltHeader(uint8_t *Buf) const {} - virtual bool isSizeReloc(uint32_t Type) const; - virtual bool relocNeedsDynRelative(unsigned Type) const { return false; } - virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; - virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; - virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, uint64_t ZA = 0, - uint8_t *PairedLoc = nullptr) const = 0; - virtual bool isGotRelative(uint32_t Type) const; - virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S) const; - virtual bool needsCopyRel(uint32_t Type, const SymbolBody &S) const; - virtual unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, uint64_t SA, - const SymbolBody &S) const; + virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const {} + + // Returns true if a relocation only uses the low bits of a value such that + // all those bits are in in the same page. For example, if the relocation + // only uses the low 12 bits in a system with 4k pages. If this is true, the + // bits will always have the same value at runtime and we don't have to emit + // a dynamic relocation. + virtual bool usesOnlyLowPageBits(uint32_t Type) const; + + // Decide whether a Thunk is needed for the relocation from File + // targeting S. Returns one of: + // Expr if there is no Thunk required + // R_THUNK_ABS if thunk is required and expression is absolute + // R_THUNK_PC if thunk is required and expression is pc rel + // R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel + virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, + const InputFile &File, + const SymbolBody &S) const; + virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0; + virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0; virtual ~TargetInfo(); -protected: + unsigned TlsGdRelaxSkip = 1; unsigned PageSize = 4096; // On freebsd x86_64 the first page cannot be mmaped. @@ -88,34 +69,44 @@ protected: // Given that, the smallest value that can be used in here is 0x10000. // If using 2MB pages, the smallest page aligned address that works is // 0x200000, but it looks like every OS uses 4k pages for executables. - uint64_t VAStart = 0x10000; + uint64_t DefaultImageBase = 0x10000; + + uint32_t CopyRel; + uint32_t GotRel; + uint32_t PltRel; + uint32_t RelativeRel; + uint32_t IRelativeRel; + uint32_t TlsDescRel; + uint32_t TlsGotRel; + uint32_t TlsModuleIndexRel; + uint32_t TlsOffsetRel; + unsigned GotEntrySize; + unsigned GotPltEntrySize; + unsigned PltEntrySize; + unsigned PltHeaderSize; - unsigned CopyReloc; - unsigned PCRelReloc; - unsigned GotReloc; - unsigned PltReloc; - unsigned RelativeReloc; - unsigned IRelativeReloc; - unsigned TlsGotReloc = 0; - unsigned TlsLocalDynamicReloc = 0; - unsigned TlsGlobalDynamicReloc = 0; - unsigned TlsModuleIndexReloc; - unsigned TlsOffsetReloc; - unsigned PltEntrySize = 8; - unsigned PltZeroEntrySize = 0; - unsigned GotHeaderEntriesNum = 0; + // At least on x86_64 positions 1 and 2 are used by the first plt entry + // to support lazy loading. unsigned GotPltHeaderEntriesNum = 3; - bool LazyRelocations = false; + + // Set to 0 for variant 2 + unsigned TcbSize = 0; + + virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr Expr) const; + virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; + virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; + virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; + virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; + virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; }; +StringRef getRelName(uint32_t Type); uint64_t getPPC64TocBase(); -template <class ELFT> -typename llvm::object::ELFFile<ELFT>::uintX_t getMipsGpAddr(); - -template <class ELFT> bool isGnuIFunc(const SymbolBody &S); +const unsigned MipsGPOffset = 0x7ff0; -extern std::unique_ptr<TargetInfo> Target; +extern TargetInfo *Target; TargetInfo *createTarget(); } } diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp new file mode 100644 index 000000000000..1ebbb17f3032 --- /dev/null +++ b/ELF/Thunks.cpp @@ -0,0 +1,268 @@ +//===- Thunks.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file contains Thunk subclasses. +// +// A thunk is a small piece of code written after an input section +// which is used to jump between "incompatible" functions +// such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions. +// +// If a jump target is too far and its address doesn't fit to a +// short jump instruction, we need to create a thunk too, but we +// haven't supported it yet. +// +// i386 and x86-64 don't need thunks. +// +//===---------------------------------------------------------------------===// + +#include "Thunks.h" +#include "Error.h" +#include "InputFiles.h" +#include "InputSection.h" +#include "OutputSections.h" +#include "Symbols.h" +#include "Target.h" +#include "llvm/Support/Allocator.h" + +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; + +namespace lld { +namespace elf { + +namespace { +// Specific ARM Thunk implementations. The naming convention is: +// Source State, TargetState, Target Requirement, ABS or PI, Range +template <class ELFT> +class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> { +public: + ARMToThumbV7ABSLongThunk(const SymbolBody &Dest, + const InputSection<ELFT> &Owner) + : Thunk<ELFT>(Dest, Owner) {} + + uint32_t size() const override { return 12; } + void writeTo(uint8_t *Buf) const override; +}; + +template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> { +public: + ARMToThumbV7PILongThunk(const SymbolBody &Dest, + const InputSection<ELFT> &Owner) + : Thunk<ELFT>(Dest, Owner) {} + + uint32_t size() const override { return 16; } + void writeTo(uint8_t *Buf) const override; +}; + +template <class ELFT> +class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> { +public: + ThumbToARMV7ABSLongThunk(const SymbolBody &Dest, + const InputSection<ELFT> &Owner) + : Thunk<ELFT>(Dest, Owner) {} + + uint32_t size() const override { return 10; } + void writeTo(uint8_t *Buf) const override; +}; + +template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> { +public: + ThumbToARMV7PILongThunk(const SymbolBody &Dest, + const InputSection<ELFT> &Owner) + : Thunk<ELFT>(Dest, Owner) {} + + uint32_t size() const override { return 12; } + void writeTo(uint8_t *Buf) const override; +}; + +// MIPS LA25 thunk +template <class ELFT> class MipsThunk final : public Thunk<ELFT> { +public: + MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner) + : Thunk<ELFT>(Dest, Owner) {} + + uint32_t size() const override { return 16; } + void writeTo(uint8_t *Buf) const override; +}; +} // anonymous namespace + +// ARM Target Thunks +template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) { + return S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>(); +} + +template <class ELFT> +void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { + const uint8_t Data[] = { + 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S + 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S + 0x1c, 0xff, 0x2f, 0xe1, // bx ip + }; + uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S); + Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S); +} + +template <class ELFT> +void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { + const uint8_t Data[] = { + 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S + 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S + 0x60, 0x47, // bx ip + }; + uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S); + Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S); +} + +template <class ELFT> +void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { + const uint8_t Data[] = { + 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) + 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8) + 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc + 0x1c, 0xff, 0x2f, 0xe1, // bx r12 + }; + uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); + uint64_t P = this->getVA(); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16); + Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12); +} + +template <class ELFT> +void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { + const uint8_t Data[] = { + 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) + 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4) + 0xfc, 0x44, // L1: add r12, pc + 0x60, 0x47, // bx r12 + }; + uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); + uint64_t P = this->getVA(); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12); + Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8); +} + +// Write MIPS LA25 thunk code to call PIC function from the non-PIC one. +template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const { + const endianness E = ELFT::TargetEndianness; + + uint64_t S = this->Destination.template getVA<ELFT>(); + write32<E>(Buf, 0x3c190000); // lui $25, %hi(func) + write32<E>(Buf + 4, 0x08000000 | (S >> 2)); // j func + write32<E>(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func) + write32<E>(Buf + 12, 0x00000000); // nop + Target->relocateOne(Buf, R_MIPS_HI16, S); + Target->relocateOne(Buf + 8, R_MIPS_LO16, S); +} + +template <class ELFT> +Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O) + : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {} + +template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const { + return Owner.OutSec->getVA() + Owner.OutSecOff + Offset; +} + +template <class ELFT> Thunk<ELFT>::~Thunk() {} + +// Creates a thunk for Thumb-ARM interworking. +template <class ELFT> +static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S, + InputSection<ELFT> &IS) { + // ARM relocations need ARM to Thumb interworking Thunks. + // Thumb relocations need Thumb to ARM relocations. + // Use position independent Thunks if we require position independent code. + BumpPtrAllocator &Alloc = IS.getFile()->Alloc; + switch (Reloc) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + if (Config->Pic) + return new (Alloc) ARMToThumbV7PILongThunk<ELFT>(S, IS); + return new (Alloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS); + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + if (Config->Pic) + return new (Alloc) ThumbToARMV7PILongThunk<ELFT>(S, IS); + return new (Alloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS); + } + fatal("unrecognized relocation type"); +} + +template <class ELFT> +static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) { + // Only one Thunk supported per symbol. + if (S.hasThunk<ELFT>()) + return; + + // ARM Thunks are added to the same InputSection as the relocation. This + // isn't strictly necessary but it makes it more likely that a limited range + // branch can reach the Thunk, and it makes Thunks to the PLT section easier + Thunk<ELFT> *T = createThunkArm(Reloc, S, IS); + IS.addThunk(T); + if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S)) + Sym->ThunkData = T; + else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S)) + Sym->ThunkData = T; + else + fatal("symbol not DefinedRegular or Shared"); +} + +template <class ELFT> +static void addThunkMips(uint32_t RelocType, SymbolBody &S, + InputSection<ELFT> &IS) { + // Only one Thunk supported per symbol. + if (S.hasThunk<ELFT>()) + return; + + // Mips Thunks are added to the InputSection defining S. + auto *R = cast<DefinedRegular<ELFT>>(&S); + auto *Sec = cast<InputSection<ELFT>>(R->Section); + auto *T = new (IS.getFile()->Alloc) MipsThunk<ELFT>(S, *Sec); + Sec->addThunk(T); + R->ThunkData = T; +} + +template <class ELFT> +void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) { + if (Config->EMachine == EM_ARM) + addThunkARM<ELFT>(RelocType, S, IS); + else if (Config->EMachine == EM_MIPS) + addThunkMips<ELFT>(RelocType, S, IS); + else + llvm_unreachable("add Thunk only supported for ARM and Mips"); +} + +template void addThunk<ELF32LE>(uint32_t, SymbolBody &, + InputSection<ELF32LE> &); +template void addThunk<ELF32BE>(uint32_t, SymbolBody &, + InputSection<ELF32BE> &); +template void addThunk<ELF64LE>(uint32_t, SymbolBody &, + InputSection<ELF64LE> &); +template void addThunk<ELF64BE>(uint32_t, SymbolBody &, + InputSection<ELF64BE> &); + +template class Thunk<ELF32LE>; +template class Thunk<ELF32BE>; +template class Thunk<ELF64LE>; +template class Thunk<ELF64BE>; + +} // namespace elf +} // namespace lld diff --git a/ELF/Thunks.h b/ELF/Thunks.h new file mode 100644 index 000000000000..b937d7918491 --- /dev/null +++ b/ELF/Thunks.h @@ -0,0 +1,56 @@ +//===- Thunks.h --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_THUNKS_H +#define LLD_ELF_THUNKS_H + +#include "Relocations.h" + +namespace lld { +namespace elf { +class SymbolBody; +template <class ELFT> class InputSection; + +// Class to describe an instance of a Thunk. +// A Thunk is a code-sequence inserted by the linker in between a caller and +// the callee. The relocation to the callee is redirected to the Thunk, which +// after executing transfers control to the callee. Typical uses of Thunks +// include transferring control from non-pi to pi and changing state on +// targets like ARM. +// +// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk +// is stored in a field of the Symbol Destination. +// Thunks to be written to an InputSection are recorded by the InputSection. +template <class ELFT> class Thunk { + typedef typename ELFT::uint uintX_t; + +public: + Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner); + virtual ~Thunk(); + + virtual uint32_t size() const { return 0; } + virtual void writeTo(uint8_t *Buf) const {} + uintX_t getVA() const; + +protected: + const SymbolBody &Destination; + const InputSection<ELFT> &Owner; + uint64_t Offset; +}; + +// For a Relocation to symbol S from InputSection Src, create a Thunk and +// update the fields of S and the InputSection that the Thunk body will be +// written to. At present there are implementations for ARM and Mips Thunks. +template <class ELFT> +void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src); + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index fbecfc601ac1..387bec3d8fb2 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -9,362 +9,353 @@ #include "Writer.h" #include "Config.h" +#include "LinkerScript.h" #include "OutputSections.h" +#include "Relocations.h" +#include "Strings.h" #include "SymbolTable.h" #include "Target.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; namespace { // The writer writes a SymbolTable result to a file. template <class ELFT> class Writer { public: - typedef typename ELFFile<ELFT>::uintX_t uintX_t; - typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; - typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr; - typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; - typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Ehdr Elf_Ehdr; + typedef typename ELFT::Phdr Elf_Phdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::Rela Elf_Rela; Writer(SymbolTable<ELFT> &S) : Symtab(S) {} void run(); private: + // This describes a program header entry. + // Each contains type, access flags and range of output sections that will be + // placed in it. + struct Phdr { + Phdr(unsigned Type, unsigned Flags) { + H.p_type = Type; + H.p_flags = Flags; + } + Elf_Phdr H = {}; + OutputSectionBase<ELFT> *First = nullptr; + OutputSectionBase<ELFT> *Last = nullptr; + }; + void copyLocalSymbols(); void addReservedSymbols(); void createSections(); void addPredefinedSections(); + bool needsGot(); - template <bool isRela> - void scanRelocs(InputSectionBase<ELFT> &C, - iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels); - - void scanRelocs(InputSection<ELFT> &C); - void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec); - void updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA); + void createPhdrs(); void assignAddresses(); - void buildSectionMap(); + void assignFileOffsets(); + void setPhdrs(); + void fixHeaders(); + void fixSectionAlignments(); void fixAbsoluteSymbols(); - void openFile(StringRef OutputPath); + void openFile(); void writeHeader(); void writeSections(); - bool isDiscarded(InputSectionBase<ELFT> *IS) const; - StringRef getOutputSectionName(StringRef S) const; + void writeBuildId(); bool needsInterpSection() const { return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty(); } bool isOutputDynamic() const { - return !Symtab.getSharedFiles().empty() || Config->Shared; + return !Symtab.getSharedFiles().empty() || Config->Pic; } - int getPhdrsNum() const; - OutputSection<ELFT> *getBss(); void addCommonSymbols(std::vector<DefinedCommon *> &Syms); - void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms); - std::unique_ptr<llvm::FileOutputBuffer> Buffer; + std::unique_ptr<FileOutputBuffer> Buffer; BumpPtrAllocator Alloc; std::vector<OutputSectionBase<ELFT> *> OutputSections; std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections; - unsigned getNumSections() const { return OutputSections.size() + 1; } void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSectionBase<ELFT> *Sec); - void setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags, uintX_t FileOff, - uintX_t VA, uintX_t Size, uintX_t Align); - void copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From); - bool HasRelro = false; SymbolTable<ELFT> &Symtab; - std::vector<Elf_Phdr> Phdrs; + std::vector<Phdr> Phdrs; uintX_t FileSize; uintX_t SectionHeaderOff; - - llvm::StringMap<llvm::StringRef> InputToOutputSection; }; } // anonymous namespace -template <class ELFT> static bool shouldUseRela() { return ELFT::Is64Bits; } +template <class ELFT> +StringRef elf::getOutputSectionName(InputSectionBase<ELFT> *S) { + StringRef Dest = Script<ELFT>::X->getOutputSection(S); + if (!Dest.empty()) + return Dest; -template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) { - // Initialize output sections that are handled by Writer specially. - // Don't reorder because the order of initialization matters. - InterpSection<ELFT> Interp; - Out<ELFT>::Interp = &Interp; - StringTableSection<ELFT> ShStrTab(".shstrtab", false); - Out<ELFT>::ShStrTab = &ShStrTab; - StringTableSection<ELFT> StrTab(".strtab", false); - if (!Config->StripAll) - Out<ELFT>::StrTab = &StrTab; - StringTableSection<ELFT> DynStrTab(".dynstr", true); - Out<ELFT>::DynStrTab = &DynStrTab; + StringRef Name = S->getSectionName(); + for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", + ".init_array.", ".fini_array.", ".ctors.", ".dtors.", + ".tbss.", ".gcc_except_table.", ".tdata."}) + if (Name.startswith(V)) + return V.drop_back(); + return Name; +} + +template <class ELFT> +void elf::reportDiscarded(InputSectionBase<ELFT> *IS, + const std::unique_ptr<elf::ObjectFile<ELFT>> &File) { + if (!Config->PrintGcSections || !IS || IS->Live) + return; + errs() << "removing unused section from '" << IS->getSectionName() + << "' in file '" << File->getName() << "'\n"; +} + +template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) { + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Ehdr Elf_Ehdr; + + // Create singleton output sections. + OutputSection<ELFT> Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + DynamicSection<ELFT> Dynamic; + EhOutputSection<ELFT> EhFrame; GotSection<ELFT> Got; - Out<ELFT>::Got = &Got; - GotPltSection<ELFT> GotPlt; - if (Target->supportsLazyRelocations()) - Out<ELFT>::GotPlt = &GotPlt; + InterpSection<ELFT> Interp; PltSection<ELFT> Plt; - Out<ELFT>::Plt = &Plt; - std::unique_ptr<SymbolTableSection<ELFT>> SymTab; + RelocationSection<ELFT> RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn", + Config->ZCombreloc); + StringTableSection<ELFT> DynStrTab(".dynstr", true); + StringTableSection<ELFT> ShStrTab(".shstrtab", false); + SymbolTableSection<ELFT> DynSymTab(DynStrTab); + VersionTableSection<ELFT> VerSym; + VersionNeedSection<ELFT> VerNeed; + + OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC); + ElfHeader.setSize(sizeof(Elf_Ehdr)); + OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC); + ProgramHeaders.updateAlignment(sizeof(uintX_t)); + + // Instantiate optional output sections if they are needed. + std::unique_ptr<BuildIdSection<ELFT>> BuildId; + std::unique_ptr<EhFrameHeader<ELFT>> EhFrameHdr; + std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab; + std::unique_ptr<GotPltSection<ELFT>> GotPlt; + std::unique_ptr<HashTableSection<ELFT>> HashTab; + std::unique_ptr<RelocationSection<ELFT>> RelaPlt; + std::unique_ptr<StringTableSection<ELFT>> StrTab; + std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec; + std::unique_ptr<OutputSection<ELFT>> MipsRldMap; + std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef; + + if (Config->BuildId == BuildIdKind::Fnv1) + BuildId.reset(new BuildIdFnv1<ELFT>); + else if (Config->BuildId == BuildIdKind::Md5) + BuildId.reset(new BuildIdMd5<ELFT>); + else if (Config->BuildId == BuildIdKind::Sha1) + BuildId.reset(new BuildIdSha1<ELFT>); + else if (Config->BuildId == BuildIdKind::Hexstring) + BuildId.reset(new BuildIdHexstring<ELFT>); + + if (Config->EhFrameHdr) + EhFrameHdr.reset(new EhFrameHeader<ELFT>); + + if (Config->GnuHash) + GnuHashTab.reset(new GnuHashTableSection<ELFT>); + if (Config->SysvHash) + HashTab.reset(new HashTableSection<ELFT>); + StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt"; + GotPlt.reset(new GotPltSection<ELFT>); + RelaPlt.reset(new RelocationSection<ELFT>(S, false /*Sort*/)); if (!Config->StripAll) { - SymTab.reset(new SymbolTableSection<ELFT>(*Symtab, *Out<ELFT>::StrTab)); - Out<ELFT>::SymTab = SymTab.get(); + StrTab.reset(new StringTableSection<ELFT>(".strtab", false)); + SymTabSec.reset(new SymbolTableSection<ELFT>(*StrTab)); } - SymbolTableSection<ELFT> DynSymTab(*Symtab, *Out<ELFT>::DynStrTab); + if (Config->EMachine == EM_MIPS && !Config->Shared) { + // This is a MIPS specific section to hold a space within the data segment + // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry. + // See "Dynamic section" in Chapter 5 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + MipsRldMap.reset(new OutputSection<ELFT>(".rld_map", SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE)); + MipsRldMap->setSize(sizeof(uintX_t)); + MipsRldMap->updateAlignment(sizeof(uintX_t)); + } + if (!Config->VersionDefinitions.empty()) + VerDef.reset(new VersionDefinitionSection<ELFT>()); + + Out<ELFT>::Bss = &Bss; + Out<ELFT>::BuildId = BuildId.get(); + Out<ELFT>::DynStrTab = &DynStrTab; Out<ELFT>::DynSymTab = &DynSymTab; - HashTableSection<ELFT> HashTab; - if (Config->SysvHash) - Out<ELFT>::HashTab = &HashTab; - GnuHashTableSection<ELFT> GnuHashTab; - if (Config->GnuHash) - Out<ELFT>::GnuHashTab = &GnuHashTab; - bool IsRela = shouldUseRela<ELFT>(); - RelocationSection<ELFT> RelaDyn(IsRela ? ".rela.dyn" : ".rel.dyn", IsRela); - Out<ELFT>::RelaDyn = &RelaDyn; - RelocationSection<ELFT> RelaPlt(IsRela ? ".rela.plt" : ".rel.plt", IsRela); - if (Target->supportsLazyRelocations()) - Out<ELFT>::RelaPlt = &RelaPlt; - DynamicSection<ELFT> Dynamic(*Symtab); Out<ELFT>::Dynamic = &Dynamic; + Out<ELFT>::EhFrame = &EhFrame; + Out<ELFT>::EhFrameHdr = EhFrameHdr.get(); + Out<ELFT>::GnuHashTab = GnuHashTab.get(); + Out<ELFT>::Got = &Got; + Out<ELFT>::GotPlt = GotPlt.get(); + Out<ELFT>::HashTab = HashTab.get(); + Out<ELFT>::Interp = &Interp; + Out<ELFT>::Plt = &Plt; + Out<ELFT>::RelaDyn = &RelaDyn; + Out<ELFT>::RelaPlt = RelaPlt.get(); + Out<ELFT>::ShStrTab = &ShStrTab; + Out<ELFT>::StrTab = StrTab.get(); + Out<ELFT>::SymTab = SymTabSec.get(); + Out<ELFT>::VerDef = VerDef.get(); + Out<ELFT>::VerSym = &VerSym; + Out<ELFT>::VerNeed = &VerNeed; + Out<ELFT>::MipsRldMap = MipsRldMap.get(); + Out<ELFT>::Opd = nullptr; + Out<ELFT>::OpdBuf = nullptr; + Out<ELFT>::TlsPhdr = nullptr; + Out<ELFT>::ElfHeader = &ElfHeader; + Out<ELFT>::ProgramHeaders = &ProgramHeaders; Writer<ELFT>(*Symtab).run(); } // The main function of the writer. template <class ELFT> void Writer<ELFT>::run() { - buildSectionMap(); if (!Config->DiscardAll) copyLocalSymbols(); addReservedSymbols(); createSections(); - assignAddresses(); - fixAbsoluteSymbols(); - openFile(Config->OutputFile); - writeHeader(); - writeSections(); - error(Buffer->commit()); -} + if (HasError) + return; -namespace { -template <bool Is64Bits> struct SectionKey { - typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t; - StringRef Name; - uint32_t Type; - uintX_t Flags; - uintX_t EntSize; -}; -} -namespace llvm { -template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> { - static SectionKey<Is64Bits> getEmptyKey() { - return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, - 0}; - } - static SectionKey<Is64Bits> getTombstoneKey() { - return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, - 0, 0}; - } - static unsigned getHashValue(const SectionKey<Is64Bits> &Val) { - return hash_combine(Val.Name, Val.Type, Val.Flags, Val.EntSize); - } - static bool isEqual(const SectionKey<Is64Bits> &LHS, - const SectionKey<Is64Bits> &RHS) { - return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) && - LHS.Type == RHS.Type && LHS.Flags == RHS.Flags && - LHS.EntSize == RHS.EntSize; + if (Config->Relocatable) { + assignFileOffsets(); + } else { + createPhdrs(); + fixHeaders(); + if (ScriptConfig->DoLayout) { + Script<ELFT>::X->assignAddresses(OutputSections); + } else { + fixSectionAlignments(); + assignAddresses(); + } + assignFileOffsets(); + setPhdrs(); + fixAbsoluteSymbols(); } -}; + + openFile(); + if (HasError) + return; + writeHeader(); + writeSections(); + writeBuildId(); + if (HasError) + return; + if (auto EC = Buffer->commit()) + error(EC, "failed to write to the output file"); } -// The reason we have to do this early scan is as follows -// * To mmap the output file, we need to know the size -// * For that, we need to know how many dynamic relocs we will have. -// It might be possible to avoid this by outputting the file with write: -// * Write the allocated output sections, computing addresses. -// * Apply relocations, recording which ones require a dynamic reloc. -// * Write the dynamic relocations. -// * Write the rest of the file. template <class ELFT> -template <bool isRela> -void Writer<ELFT>::scanRelocs( - InputSectionBase<ELFT> &C, - iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) { - typedef Elf_Rel_Impl<ELFT, isRela> RelType; - const ObjectFile<ELFT> &File = *C.getFile(); - for (const RelType &RI : Rels) { - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - SymbolBody *Body = File.getSymbolBody(SymIndex); - uint32_t Type = RI.getType(Config->Mips64EL); - - if (Target->isGotRelative(Type)) - HasGotOffRel = true; - - if (Target->isTlsLocalDynamicReloc(Type)) { - if (Target->isTlsOptimized(Type, nullptr)) - continue; - if (Out<ELFT>::Got->addCurrentModuleTlsIndex()) - Out<ELFT>::RelaDyn->addReloc({&C, &RI}); - continue; - } - - // 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 && Body->isTls() && Target->isTlsGlobalDynamicReloc(Type)) { - bool Opt = Target->isTlsOptimized(Type, Body); - if (!Opt && Out<ELFT>::Got->addDynTlsEntry(Body)) { - Out<ELFT>::RelaDyn->addReloc({&C, &RI}); - Out<ELFT>::RelaDyn->addReloc({nullptr, nullptr}); - Body->setUsedInDynamicReloc(); - continue; - } - if (!canBePreempted(Body, true)) - continue; - } - - if (Body && Body->isTls() && !Target->isTlsDynReloc(Type, *Body)) - continue; +static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) { + if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore) + return; - if (Target->relocNeedsDynRelative(Type)) { - RelType *Rel = new (Alloc) RelType; - Rel->setSymbolAndType(0, Target->getRelativeReloc(), Config->Mips64EL); - Rel->r_offset = RI.r_offset; - Out<ELFT>::RelaDyn->addReloc({&C, Rel}); - } + if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT && + Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef) + return; - bool NeedsGot = false; - bool NeedsPlt = false; - if (Body) { - if (auto *E = dyn_cast<SharedSymbol<ELFT>>(Body)) { - if (E->NeedsCopy) - continue; - if (Target->needsCopyRel(Type, *Body)) - E->NeedsCopy = true; - } - NeedsPlt = Target->relocNeedsPlt(Type, *Body); - if (NeedsPlt) { - if (Body->isInPlt()) - continue; - Out<ELFT>::Plt->addEntry(Body); - } - NeedsGot = Target->relocNeedsGot(Type, *Body); - if (NeedsGot) { - if (NeedsPlt && Target->supportsLazyRelocations()) { - Out<ELFT>::GotPlt->addEntry(Body); - } else { - if (Body->isInGot()) - continue; - Out<ELFT>::Got->addEntry(Body); - } - } - } + std::string Msg = "undefined symbol: " + Sym->getName().str(); + if (Sym->File) + Msg += " in " + getFilename(Sym->File); + if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn) + warning(Msg); + else + error(Msg); +} - // An STT_GNU_IFUNC symbol always uses a PLT entry, and all references - // to the symbol go through the PLT. This is true even for a local - // symbol, although local symbols normally do not require PLT entries. - if (Body && isGnuIFunc<ELFT>(*Body)) { - Body->setUsedInDynamicReloc(); - Out<ELFT>::RelaPlt->addReloc({&C, &RI}); - continue; - } +template <class ELFT> +static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName, + const SymbolBody &B) { + if (B.isFile()) + return false; - if (Config->EMachine == EM_MIPS) { - if (NeedsGot) { - // MIPS ABI has special rules to process GOT entries - // and doesn't require relocation entries for them. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Body->setUsedInDynamicReloc(); - continue; - } - if (Body == Config->MipsGpDisp) - // MIPS _gp_disp designates offset between start of function and gp - // pointer into GOT therefore any relocations against it do not require - // dynamic relocation. - continue; - } + // We keep sections in symtab for relocatable output. + if (B.isSection()) + return Config->Relocatable; - // Here we are creating a relocation for the dynamic linker based on - // a relocation from an object file, but some relocations need no - // load-time fixup. Skip such relocation. - bool CBP = canBePreempted(Body, NeedsGot); - bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeReloc(Type); - if (!CBP && (NoDynrel || !Config->Shared)) - continue; + // If sym references a section in a discarded group, don't keep it. + if (Sec == &InputSection<ELFT>::Discarded) + return false; - if (CBP) - Body->setUsedInDynamicReloc(); - if (NeedsPlt && Target->supportsLazyRelocations()) - Out<ELFT>::RelaPlt->addReloc({&C, &RI}); - else - Out<ELFT>::RelaDyn->addReloc({&C, &RI}); - } -} + if (Config->DiscardNone) + return true; -template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) { - if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC)) - return; + // In ELF assembly .L symbols are normally discarded by the assembler. + // If the assembler fails to do so, the linker discards them if + // * --discard-locals is used. + // * The symbol is in a SHF_MERGE section, which is normally the reason for + // the assembler keeping the .L symbol. + if (!SymName.startswith(".L") && !SymName.empty()) + return true; - for (const Elf_Shdr *RelSec : C.RelocSections) - scanRelocs(C, *RelSec); -} + if (Config->DiscardLocals) + return false; -template <class ELFT> -void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S, - const Elf_Shdr &RelSec) { - ELFFile<ELFT> &EObj = S.getFile()->getObj(); - if (RelSec.sh_type == SHT_RELA) - scanRelocs(S, EObj.relas(&RelSec)); - else - scanRelocs(S, EObj.rels(&RelSec)); + return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE); } -template <class ELFT> -static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) { - if (Config->Shared && !Config->NoUndefined) - return; +template <class ELFT> static bool includeInSymtab(const SymbolBody &B) { + if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) + return false; - std::string Msg = "undefined symbol: " + Sym->getName().str(); - if (ELFFileBase<ELFT> *File = Symtab.findFile(Sym)) - Msg += " in " + File->getName().str(); - if (Config->NoInhibitExec) - warning(Msg); - else - error(Msg); + if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) { + // Always include absolute symbols. + if (!D->Section) + return true; + // Exclude symbols pointing to garbage-collected sections. + if (!D->Section->Live) + return false; + if (auto *S = dyn_cast<MergeInputSection<ELFT>>(D->Section)) + if (!S->getSectionPiece(D->Value)->Live) + return false; + } + return true; } // Local symbols are not in the linker's symbol table. This function scans // each object file's symbol table to copy local symbols to the output. template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { - for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) { - for (const Elf_Sym &Sym : F->getLocalSymbols()) { - ErrorOr<StringRef> SymNameOrErr = Sym.getName(F->getStringTable()); - error(SymNameOrErr); - StringRef SymName = *SymNameOrErr; - if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym)) + if (!Out<ELFT>::SymTab) + return; + for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : + Symtab.getObjectFiles()) { + const char *StrTab = F->getStringTable().data(); + for (SymbolBody *B : F->getLocalSymbols()) { + auto *DR = dyn_cast<DefinedRegular<ELFT>>(B); + // No reason to keep local undefined symbol in symtab. + if (!DR) continue; - if (Out<ELFT>::SymTab) - Out<ELFT>::SymTab->addLocalSymbol(SymName); + if (!includeInSymtab<ELFT>(*B)) + continue; + StringRef SymName(StrTab + B->getNameOffset()); + InputSectionBase<ELFT> *Sec = DR->Section; + if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B)) + continue; + ++Out<ELFT>::SymTab->NumLocals; + if (Config->Relocatable) + B->DynsymIndex = Out<ELFT>::SymTab->NumLocals; + F->KeptLocalSyms.push_back( + std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName))); } } } @@ -377,16 +368,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { // thus, within reach of the TOC base pointer). static int getPPC64SectionRank(StringRef SectionName) { return StringSwitch<int>(SectionName) - .Case(".tocbss", 0) - .Case(".branch_lt", 2) - .Case(".toc", 3) - .Case(".toc1", 4) - .Case(".opd", 5) - .Default(1); + .Case(".tocbss", 0) + .Case(".branch_lt", 2) + .Case(".toc", 3) + .Case(".toc1", 4) + .Case(".opd", 5) + .Default(1); } template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) { - typename OutputSectionBase<ELFT>::uintX_t Flags = Sec->getFlags(); + if (!Config->ZRelro) + return false; + typename ELFT::uint Flags = Sec->getFlags(); if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; if (Flags & SHF_TLS) @@ -406,9 +399,13 @@ template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) { // Output section ordering is determined by this function. template <class ELFT> -static bool compareOutputSections(OutputSectionBase<ELFT> *A, - OutputSectionBase<ELFT> *B) { - typedef typename ELFFile<ELFT>::uintX_t uintX_t; +static bool compareSections(OutputSectionBase<ELFT> *A, + OutputSectionBase<ELFT> *B) { + typedef typename ELFT::uint uintX_t; + + int Comp = Script<ELFT>::X->compareSections(A->getName(), B->getName()); + if (Comp != 0) + return Comp < 0; uintX_t AFlags = A->getFlags(); uintX_t BFlags = B->getFlags(); @@ -475,16 +472,6 @@ static bool compareOutputSections(OutputSectionBase<ELFT> *A, return false; } -template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBss() { - if (!Out<ELFT>::Bss) { - Out<ELFT>::Bss = - new OutputSection<ELFT>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); - OwningSections.emplace_back(Out<ELFT>::Bss); - OutputSections.push_back(Out<ELFT>::Bss); - } - return Out<ELFT>::Bss; -} - // Until this function is called, common symbols do not belong to any section. // This function adds them to end of BSS section. template <class ELFT> @@ -495,12 +482,13 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) { // Sort the common symbols by alignment as an heuristic to pack them better. std::stable_sort(Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { - return A->MaxAlignment > B->MaxAlignment; + return A->Alignment > B->Alignment; }); - uintX_t Off = getBss()->getSize(); + uintX_t Off = Out<ELFT>::Bss->getSize(); for (DefinedCommon *C : Syms) { - Off = align(Off, C->MaxAlignment); + Off = alignTo(Off, C->Alignment); + Out<ELFT>::Bss->updateAlignment(C->Alignment); C->OffsetInBss = Off; Off += C->Size; } @@ -508,75 +496,16 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) { Out<ELFT>::Bss->setSize(Off); } -// Reserve space in .bss for copy relocations. template <class ELFT> -void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) { - if (Syms.empty()) - return; - uintX_t Off = getBss()->getSize(); - for (SharedSymbol<ELFT> *C : Syms) { - const Elf_Sym &Sym = C->Sym; - const Elf_Shdr *Sec = C->File->getSection(Sym); - uintX_t SecAlign = Sec->sh_addralign; - unsigned TrailingZeros = - std::min(countTrailingZeros(SecAlign), - countTrailingZeros((uintX_t)Sym.st_value)); - uintX_t Align = 1 << TrailingZeros; - Out<ELFT>::Bss->updateAlign(Align); - Off = align(Off, Align); - C->OffsetInBss = Off; - Off += Sym.st_size; - } - Out<ELFT>::Bss->setSize(Off); -} - -template <class ELFT> -StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const { - auto It = InputToOutputSection.find(S); - if (It != std::end(InputToOutputSection)) - return It->second; - - if (S.startswith(".text.")) - return ".text"; - if (S.startswith(".rodata.")) - return ".rodata"; - if (S.startswith(".data.rel.ro")) - return ".data.rel.ro"; - if (S.startswith(".data.")) - return ".data"; - if (S.startswith(".bss.")) - return ".bss"; - return S; -} - -template <class ELFT> -void reportDiscarded(InputSectionBase<ELFT> *IS, - const std::unique_ptr<ObjectFile<ELFT>> &File) { - if (!Config->PrintGcSections || !IS || IS->isLive()) - return; - llvm::errs() << "removing unused section from '" << IS->getSectionName() - << "' in file '" << File->getName() << "'\n"; -} - -template <class ELFT> -bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *IS) const { - if (!IS || !IS->isLive() || IS == &InputSection<ELFT>::Discarded) - return true; - return InputToOutputSection.lookup(IS->getSectionName()) == "/DISCARD/"; -} - -template <class ELFT> -static bool compareSections(OutputSectionBase<ELFT> *A, - OutputSectionBase<ELFT> *B) { - auto ItA = Config->OutputSections.find(A->getName()); - auto ItEnd = std::end(Config->OutputSections); - if (ItA == ItEnd) - return compareOutputSections(A, B); - auto ItB = Config->OutputSections.find(B->getName()); - if (ItB == ItEnd) - return compareOutputSections(A, B); - - return std::distance(ItA, ItB) > 0; +static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name, + OutputSectionBase<ELFT> *Sec, + typename ELFT::uint Val) { + SymbolBody *S = Table.find(Name); + if (!S) + return nullptr; + if (!S->isUndefined() && !S->isShared()) + return S->symbol(); + return Table.addSynthetic(Name, Sec, Val); } // The beginning and the ending of .rel[a].plt section are marked @@ -585,125 +514,57 @@ static bool compareSections(OutputSectionBase<ELFT> *A, // all IRELATIVE relocs on startup. For dynamic executables, we don't // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. -template <class ELFT> -void Writer<ELFT>::addRelIpltSymbols() { +template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { if (isOutputDynamic() || !Out<ELFT>::RelaPlt) return; - bool IsRela = shouldUseRela<ELFT>(); - - StringRef S = IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; - if (Symtab.find(S)) - Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltStart); - - S = IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - if (Symtab.find(S)) - Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltEnd); -} - -template <class ELFT> static bool includeInSymtab(const SymbolBody &B) { - if (!B.isUsedInRegularObj()) - return false; - - // Don't include synthetic symbols like __init_array_start in every output. - if (auto *U = dyn_cast<DefinedRegular<ELFT>>(&B)) - if (&U->Sym == &ElfSym<ELFT>::IgnoredWeak || - &U->Sym == &ElfSym<ELFT>::Ignored) - return false; - - return true; -} + StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start"; + addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0); -static bool includeInDynamicSymtab(const SymbolBody &B) { - uint8_t V = B.getVisibility(); - if (V != STV_DEFAULT && V != STV_PROTECTED) - return false; - if (Config->ExportDynamic || Config->Shared) - return true; - return B.isUsedInDynamicReloc(); + S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end"; + addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, + DefinedSynthetic<ELFT>::SectionEnd); } -// This class knows how to create an output section for a given -// input section. Output section type is determined by various -// factors, including input section's sh_flags, sh_type and -// linker scripts. -namespace { -template <class ELFT> class OutputSectionFactory { - typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename ELFFile<ELFT>::uintX_t uintX_t; - -public: - std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C, - StringRef OutsecName); - - OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags); - -private: - SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C, - StringRef OutsecName); - - SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map; -}; -} +// The linker is expected to define some symbols depending on +// the linking result. This function defines such symbols. +template <class ELFT> void Writer<ELFT>::addReservedSymbols() { + if (Config->EMachine == EM_MIPS) { + // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer + // so that it points to an absolute address which is relative to GOT. + // See "Global Data Symbols" in Chapter 6 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset); -template <class ELFT> -std::pair<OutputSectionBase<ELFT> *, bool> -OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C, - StringRef OutsecName) { - SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName); - OutputSectionBase<ELFT> *&Sec = Map[Key]; - if (Sec) - return {Sec, false}; + // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between + // start of function and 'gp' pointer into GOT. + Symbol *Sym = + addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset); + if (Sym) + ElfSym<ELFT>::MipsGpDisp = Sym->body(); - switch (C->SectionKind) { - case InputSectionBase<ELFT>::Regular: - Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); - break; - case InputSectionBase<ELFT>::EHFrame: - Sec = new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); - break; - case InputSectionBase<ELFT>::Merge: - Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); - break; - case InputSectionBase<ELFT>::MipsReginfo: - Sec = new MipsReginfoOutputSection<ELFT>(); - break; + // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' + // pointer. This symbol is used in the code generated by .cpload pseudo-op + // in case of using -mno-shared option. + // https://sourceware.org/ml/binutils/2004-12/msg00094.html + addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got, + MipsGPOffset); } - return {Sec, true}; -} - -template <class ELFT> -OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name, - uint32_t Type, - uintX_t Flags) { - return Map.lookup({Name, Type, Flags, 0}); -} - -template <class ELFT> -SectionKey<ELFT::Is64Bits> -OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C, - StringRef OutsecName) { - const Elf_Shdr *H = C->getSectionHdr(); - uintX_t Flags = H->sh_flags & ~SHF_GROUP; - // For SHF_MERGE we create different output sections for each sh_entsize. - // This makes each output section simple and keeps a single level - // mapping from input to output. - uintX_t EntSize = isa<MergeInputSection<ELFT>>(C) ? H->sh_entsize : 0; + // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol + // is magical and is used to produce a R_386_GOTPC relocation. + // The R_386_GOTPC relocation value doesn't actually depend on the + // symbol value, so it could use an index of STN_UNDEF which, according + // to the spec, means the symbol value is 0. + // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in + // the object file. + // The situation is even stranger on x86_64 where the assembly doesn't + // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as + // an undefined symbol in the .o files. + // Given that the symbol is effectively unused, we just create a dummy + // hidden one to avoid the undefined symbol error. + if (!Config->Relocatable) + Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); - // GNU as can give .eh_frame secion type SHT_PROGBITS or SHT_X86_64_UNWIND - // depending on the construct. We want to canonicalize it so that - // there is only one .eh_frame in the end. - uint32_t Type = H->sh_type; - if (Type == SHT_PROGBITS && Config->EMachine == EM_X86_64 && - isa<EHInputSection<ELFT>>(C)) - Type = SHT_X86_64_UNWIND; - - return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, EntSize}; -} - -// The linker is expected to define some symbols depending on -// the linking result. This function defines such symbols. -template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition @@ -711,35 +572,44 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { if (!isOutputDynamic()) Symtab.addIgnored("__tls_get_addr"); - // If the "_end" symbol is referenced, it is expected to point to the address - // right after the data segment. Usually, this symbol points to the end - // of .bss section or to the end of .data section if .bss section is absent. - // The order of the sections can be affected by linker script, - // so it is hard to predict which section will be the last one. - // So, if this symbol is referenced, we just add the placeholder here - // and update its value later. - if (Symtab.find("_end")) - Symtab.addAbsolute("_end", ElfSym<ELFT>::End); + auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1, + DefinedRegular<ELFT> *&Sym2) { + Sym1 = Symtab.addIgnored(S, STV_DEFAULT); - // If there is an undefined symbol "end", we should initialize it - // with the same value as "_end". In any other case it should stay intact, - // because it is an allowable name for a user symbol. - if (SymbolBody *B = Symtab.find("end")) - if (B->isUndefined()) - Symtab.addAbsolute("end", ElfSym<ELFT>::End); + // The name without the underscore is not a reserved name, + // so it is defined only when there is a reference against it. + assert(S.startswith("_")); + S = S.substr(1); + if (SymbolBody *B = Symtab.find(S)) + if (B->isUndefined()) + Sym2 = Symtab.addAbsolute(S, STV_DEFAULT); + }; + + Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2); + Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2); + Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2); +} + +// Sort input sections by section name suffixes for +// __attribute__((init_priority(N))). +template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) { + if (S) + reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini(); +} + +// Sort input sections by the special rule for .ctors and .dtors. +template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) { + if (S) + reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors(); } // Create output section objects and add them to OutputSections. template <class ELFT> void Writer<ELFT>::createSections() { - // Add .interp first because some loaders want to see that section - // on the first page of the executable file when loaded into memory. - if (needsInterpSection()) - OutputSections.push_back(Out<ELFT>::Interp); - // Create output sections for input object file sections. std::vector<OutputSectionBase<ELFT> *> RegularSections; OutputSectionFactory<ELFT> Factory; - for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) { + for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : + Symtab.getObjectFiles()) { for (InputSectionBase<ELFT> *C : F->getSections()) { if (isDiscarded(C)) { reportDiscarded(C, F); @@ -747,8 +617,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { } OutputSectionBase<ELFT> *Sec; bool IsNew; - std::tie(Sec, IsNew) = - Factory.create(C, getOutputSectionName(C->getSectionName())); + std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C)); if (IsNew) { OwningSections.emplace_back(Sec); OutputSections.push_back(Sec); @@ -758,9 +627,6 @@ template <class ELFT> void Writer<ELFT>::createSections() { } } - Out<ELFT>::Bss = static_cast<OutputSection<ELFT> *>( - Factory.lookup(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE)); - // If we have a .opd section (used under PPC64 for function descriptors), // store a pointer to it here so that we can use it later when processing // relocations. @@ -773,56 +639,92 @@ template <class ELFT> void Writer<ELFT>::createSections() { Out<ELFT>::Dynamic->FiniArraySec = Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC); + // Sort section contents for __attribute__((init_priority(N)). + sortInitFini(Out<ELFT>::Dynamic->InitArraySec); + sortInitFini(Out<ELFT>::Dynamic->FiniArraySec); + sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); + sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); + // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. - addStartEndSymbols(); - for (OutputSectionBase<ELFT> *Sec : RegularSections) - addStartStopSymbols(Sec); + if (!Config->Relocatable) { + addStartEndSymbols(); + for (OutputSectionBase<ELFT> *Sec : RegularSections) + addStartStopSymbols(Sec); + } + + // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. + // It should be okay as no one seems to care about the type. + // Even the author of gold doesn't remember why gold behaves that way. + // https://sourceware.org/ml/binutils/2002-03/msg00360.html + if (isOutputDynamic()) + Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0); + + // Define __rel[a]_iplt_{start,end} symbols if needed. + addRelIpltSymbols(); + + // Add scripted symbols with zero values now. + // Real values will be assigned later + Script<ELFT>::X->addScriptedSymbols(); + + if (!Out<ELFT>::EhFrame->empty()) { + OutputSections.push_back(Out<ELFT>::EhFrame); + Out<ELFT>::EhFrame->finalize(); + } // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. - for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) { + for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : + Symtab.getObjectFiles()) { for (InputSectionBase<ELFT> *C : F->getSections()) { if (isDiscarded(C)) continue; - if (auto *S = dyn_cast<InputSection<ELFT>>(C)) - scanRelocs(*S); - else if (auto *S = dyn_cast<EHInputSection<ELFT>>(C)) + if (auto *S = dyn_cast<InputSection<ELFT>>(C)) { + scanRelocations(*S); + continue; + } + if (auto *S = dyn_cast<EhInputSection<ELFT>>(C)) if (S->RelocSection) - scanRelocs(*S, *S->RelocSection); + scanRelocations(*S, *S->RelocSection); } } - // Define __rel[a]_iplt_{start,end} symbols if needed. - addRelIpltSymbols(); + for (OutputSectionBase<ELFT> *Sec : OutputSections) + Sec->assignOffsets(); // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. std::vector<DefinedCommon *> CommonSymbols; - std::vector<SharedSymbol<ELFT> *> CopyRelSymbols; - for (auto &P : Symtab.getSymbols()) { - SymbolBody *Body = P.second->Body; - if (auto *U = dyn_cast<Undefined>(Body)) - if (!U->isWeak() && !U->canKeepUndefined()) - reportUndefined<ELFT>(Symtab, Body); + for (Symbol *S : Symtab.getSymbols()) { + SymbolBody *Body = S->body(); + + // We only report undefined symbols in regular objects. This means that we + // will accept an undefined reference in bitcode if it can be optimized out. + if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak()) + reportUndefined<ELFT>(Symtab, Body); if (auto *C = dyn_cast<DefinedCommon>(Body)) CommonSymbols.push_back(C); - if (auto *SC = dyn_cast<SharedSymbol<ELFT>>(Body)) - if (SC->NeedsCopy) - CopyRelSymbols.push_back(SC); if (!includeInSymtab<ELFT>(*Body)) continue; if (Out<ELFT>::SymTab) Out<ELFT>::SymTab->addSymbol(Body); - if (isOutputDynamic() && includeInDynamicSymtab(*Body)) + if (isOutputDynamic() && S->includeInDynsym()) { Out<ELFT>::DynSymTab->addSymbol(Body); + if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body)) + if (SS->file()->isNeeded()) + Out<ELFT>::VerNeed->addSymbol(SS); + } } + + // Do not proceed if there was an undefined symbol. + if (HasError) + return; + addCommonSymbols(CommonSymbols); - addCopyRelSymbols(CopyRelSymbols); // So far we have added sections from input object files. // This function adds linker-created Out<ELFT>::* sections. @@ -831,25 +733,47 @@ template <class ELFT> void Writer<ELFT>::createSections() { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections<ELFT>); - for (unsigned I = 0, N = OutputSections.size(); I < N; ++I) { - OutputSections[I]->SectionIndex = I + 1; - HasRelro |= (Config->ZRelro && isRelroSection(OutputSections[I])); + unsigned I = 1; + for (OutputSectionBase<ELFT> *Sec : OutputSections) { + Sec->SectionIndex = I++; + Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName())); } - for (OutputSectionBase<ELFT> *Sec : OutputSections) - Out<ELFT>::ShStrTab->reserve(Sec->getName()); - // Finalizers fix each section's size. - // .dynamic section's finalizer may add strings to .dynstr, - // so finalize that early. - // Likewise, .dynsym is finalized early since that may fill up .gnu.hash. - Out<ELFT>::Dynamic->finalize(); + // .dynsym is finalized early since that may fill up .gnu.hash. if (isOutputDynamic()) Out<ELFT>::DynSymTab->finalize(); - // Fill other section headers. + // Fill other section headers. The dynamic table is finalized + // at the end because some tags like RELSZ depend on result + // of finalizing other sections. The dynamic string table is + // finalized once the .dynamic finalizer has added a few last + // strings. See DynamicSection::finalize() for (OutputSectionBase<ELFT> *Sec : OutputSections) - Sec->finalize(); + if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic) + Sec->finalize(); + + if (isOutputDynamic()) + Out<ELFT>::Dynamic->finalize(); + + // Now that all output offsets are fixed. Finalize mergeable sections + // to fix their maps from input offsets to output offsets. + for (OutputSectionBase<ELFT> *Sec : OutputSections) + Sec->finalizePieces(); +} + +template <class ELFT> bool Writer<ELFT>::needsGot() { + if (!Out<ELFT>::Got->empty()) + return true; + + // We add the .got section to the result for dynamic MIPS target because + // its address and properties are mentioned in the .dynamic section. + if (Config->EMachine == EM_MIPS) + return true; + + // If we have a relocation that is relative to GOT (such as GOTOFFREL), + // we need to emit a GOT even if it's empty. + return Out<ELFT>::Got->HasGotOffRel; } // This function add Out<ELFT>::* sections to OutputSections. @@ -859,6 +783,17 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { OutputSections.push_back(C); }; + // A core file does not usually contain unmodified segments except + // the first page of the executable. Add the build ID section to beginning of + // the file so that the section is included in the first page. + if (Out<ELFT>::BuildId) + OutputSections.insert(OutputSections.begin(), Out<ELFT>::BuildId); + + // Add .interp at first because some loaders want to see that section + // on the first page of the executable file when loaded into memory. + if (needsInterpSection()) + OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp); + // This order is not the same as the final output order // because we sort the sections using their attributes below. Add(Out<ELFT>::SymTab); @@ -866,25 +801,21 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Add(Out<ELFT>::StrTab); if (isOutputDynamic()) { Add(Out<ELFT>::DynSymTab); + + bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0; + if (Out<ELFT>::VerDef || HasVerNeed) + Add(Out<ELFT>::VerSym); + Add(Out<ELFT>::VerDef); + if (HasVerNeed) + Add(Out<ELFT>::VerNeed); + Add(Out<ELFT>::GnuHashTab); Add(Out<ELFT>::HashTab); Add(Out<ELFT>::Dynamic); Add(Out<ELFT>::DynStrTab); if (Out<ELFT>::RelaDyn->hasRelocs()) Add(Out<ELFT>::RelaDyn); - - // This is a MIPS specific section to hold a space within the data segment - // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry. - // See "Dynamic section" in Chapter 5 in the following document: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS && !Config->Shared) { - Out<ELFT>::MipsRldMap = new OutputSection<ELFT>(".rld_map", SHT_PROGBITS, - SHF_ALLOC | SHF_WRITE); - Out<ELFT>::MipsRldMap->setSize(ELFT::Is64Bits ? 8 : 4); - Out<ELFT>::MipsRldMap->updateAlign(ELFT::Is64Bits ? 8 : 4); - OwningSections.emplace_back(Out<ELFT>::MipsRldMap); - Add(Out<ELFT>::MipsRldMap); - } + Add(Out<ELFT>::MipsRldMap); } // We always need to add rel[a].plt to output if it has entries. @@ -894,22 +825,16 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Out<ELFT>::RelaPlt->Static = !isOutputDynamic(); } - bool needsGot = !Out<ELFT>::Got->empty(); - // We add the .got section to the result for dynamic MIPS target because - // its address and properties are mentioned in the .dynamic section. - if (Config->EMachine == EM_MIPS) - needsGot |= isOutputDynamic(); - // If we have a relocation that is relative to GOT (such as GOTOFFREL), - // we need to emit a GOT even if it's empty. - if (HasGotOffRel) - needsGot = true; - - if (needsGot) + if (needsGot()) Add(Out<ELFT>::Got); if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty()) Add(Out<ELFT>::GotPlt); if (!Out<ELFT>::Plt->empty()) Add(Out<ELFT>::Plt); + if (!Out<ELFT>::EhFrame->empty()) + Add(Out<ELFT>::EhFrameHdr); + if (Out<ELFT>::Bss->getSize() > 0) + Add(Out<ELFT>::Bss); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -918,11 +843,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSectionBase<ELFT> *OS) { if (OS) { - Symtab.addSynthetic(Start, *OS, 0); - Symtab.addSynthetic(End, *OS, OS->getSize()); + this->Symtab.addSynthetic(Start, OS, 0); + this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd); } else { - Symtab.addIgnored(Start); - Symtab.addIgnored(End); + addOptionalSynthetic(this->Symtab, Start, + (OutputSectionBase<ELFT> *)nullptr, 0); + addOptionalSynthetic(this->Symtab, End, + (OutputSectionBase<ELFT> *)nullptr, 0); } }; @@ -934,19 +861,6 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { Out<ELFT>::Dynamic->FiniArraySec); } -static bool isAlpha(char C) { - return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; -} - -static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); } - -// Returns true if S is valid as a C language identifier. -static bool isValidCIdentifier(StringRef S) { - if (S.empty() || !isAlpha(S[0])) - return false; - return std::all_of(S.begin() + 1, S.end(), isAlnum); -} - // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_<secname> and // __stop_<secname> symbols. They are at beginning and end of the section, @@ -962,14 +876,22 @@ void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) { StringRef Stop = Saver.save("__stop_" + S); if (SymbolBody *B = Symtab.find(Start)) if (B->isUndefined()) - Symtab.addSynthetic(Start, *Sec, 0); + Symtab.addSynthetic(Start, Sec, 0); if (SymbolBody *B = Symtab.find(Stop)) if (B->isUndefined()) - Symtab.addSynthetic(Stop, *Sec, Sec->getSize()); + Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd); } -template <class ELFT> static bool needsPhdr(OutputSectionBase<ELFT> *Sec) { - return Sec->getFlags() & SHF_ALLOC; +template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) { + if (!(Sec->getFlags() & SHF_ALLOC)) + return false; + + // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is + // responsible for allocating space for them, not the PT_LOAD that + // contains the TLS initialization image. + if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) + return false; + return true; } static uint32_t toPhdrFlags(uint64_t Flags) { @@ -981,269 +903,341 @@ static uint32_t toPhdrFlags(uint64_t Flags) { return Ret; } -/// For AMDGPU we need to use custom segment kinds in order to specify which -/// address space data should be loaded into. -template <class ELFT> -static uint32_t getAmdgpuPhdr(OutputSectionBase<ELFT> *Sec) { - uint32_t Flags = Sec->getFlags(); - if (Flags & SHF_AMDGPU_HSA_CODE) - return PT_AMDGPU_HSA_LOAD_CODE_AGENT; - if ((Flags & SHF_AMDGPU_HSA_GLOBAL) && !(Flags & SHF_AMDGPU_HSA_AGENT)) - return PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM; - return PT_LOAD; -} - -template <class ELFT> -void Writer<ELFT>::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, - uintX_t VA) { - if (!GnuRelroPhdr->p_type) - setPhdr(GnuRelroPhdr, PT_GNU_RELRO, PF_R, Cur->p_offset, Cur->p_vaddr, - VA - Cur->p_vaddr, 1 /*p_align*/); - GnuRelroPhdr->p_filesz = VA - Cur->p_vaddr; - GnuRelroPhdr->p_memsz = VA - Cur->p_vaddr; -} - -// Visits all sections to create PHDRs and to assign incremental, -// non-overlapping addresses to output sections. -template <class ELFT> void Writer<ELFT>::assignAddresses() { - uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr); - uintX_t FileOff = sizeof(Elf_Ehdr); +// Decide which program headers to create and which sections to include in each +// one. +template <class ELFT> void Writer<ELFT>::createPhdrs() { + auto AddHdr = [this](unsigned Type, unsigned Flags) { + return &*Phdrs.emplace(Phdrs.end(), Type, Flags); + }; - // Calculate and reserve the space for the program header first so that - // the first section can start right after the program header. - Phdrs.resize(getPhdrsNum()); - size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); + auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) { + Hdr.Last = Sec; + if (!Hdr.First) + Hdr.First = Sec; + Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlignment()); + }; // The first phdr entry is PT_PHDR which describes the program header itself. - setPhdr(&Phdrs[0], PT_PHDR, PF_R, FileOff, VA, PhdrSize, /*Align=*/8); - FileOff += PhdrSize; - VA += PhdrSize; + Phdr &Hdr = *AddHdr(PT_PHDR, PF_R); + AddSec(Hdr, Out<ELFT>::ProgramHeaders); // PT_INTERP must be the second entry if exists. - int PhdrIdx = 0; - Elf_Phdr *Interp = nullptr; - if (needsInterpSection()) - Interp = &Phdrs[++PhdrIdx]; + if (needsInterpSection()) { + Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags())); + AddSec(Hdr, Out<ELFT>::Interp); + } // Add the first PT_LOAD segment for regular output sections. - setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff, - Target->getPageSize()); + uintX_t Flags = PF_R; + Phdr *Load = AddHdr(PT_LOAD, Flags); + AddSec(*Load, Out<ELFT>::ElfHeader); + AddSec(*Load, Out<ELFT>::ProgramHeaders); - Elf_Phdr GnuRelroPhdr = {}; - Elf_Phdr TlsPhdr{}; - bool RelroAligned = false; - uintX_t ThreadBssOffset = 0; - // Create phdrs as we assign VAs and file offsets to all output sections. + Phdr TlsHdr(PT_TLS, PF_R); + Phdr RelRo(PT_GNU_RELRO, PF_R); + Phdr Note(PT_NOTE, PF_R); for (OutputSectionBase<ELFT> *Sec : OutputSections) { - Elf_Phdr *PH = &Phdrs[PhdrIdx]; - if (needsPhdr<ELFT>(Sec)) { - uintX_t Flags = toPhdrFlags(Sec->getFlags()); - bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec); - bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned; - if (FirstNonRelRo || PH->p_flags != Flags) { - VA = align(VA, Target->getPageSize()); - FileOff = align(FileOff, Target->getPageSize()); - if (FirstNonRelRo) - RelroAligned = true; - } + if (!(Sec->getFlags() & SHF_ALLOC)) + break; - if (PH->p_flags != Flags) { - // Flags changed. Create a new PT_LOAD. - PH = &Phdrs[++PhdrIdx]; - uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD - : getAmdgpuPhdr(Sec); - setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize()); - } + // If we meet TLS section then we create TLS header + // and put all TLS sections inside for futher use when + // assign addresses. + if (Sec->getFlags() & SHF_TLS) + AddSec(TlsHdr, Sec); - if (Sec->getFlags() & SHF_TLS) { - if (!TlsPhdr.p_vaddr) - setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign()); - if (Sec->getType() != SHT_NOBITS) - VA = align(VA, Sec->getAlign()); - uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign()); - Sec->setVA(TVA); - TlsPhdr.p_memsz += Sec->getSize(); - if (Sec->getType() == SHT_NOBITS) { - ThreadBssOffset = TVA - VA + Sec->getSize(); - } else { - TlsPhdr.p_filesz += Sec->getSize(); - VA += Sec->getSize(); - } - TlsPhdr.p_align = std::max<uintX_t>(TlsPhdr.p_align, Sec->getAlign()); - } else { - VA = align(VA, Sec->getAlign()); - Sec->setVA(VA); - VA += Sec->getSize(); - if (InRelRo) - updateRelro(PH, &GnuRelroPhdr, VA); - } - } + if (!needsPtLoad<ELFT>(Sec)) + continue; - FileOff = align(FileOff, Sec->getAlign()); - Sec->setFileOffset(FileOff); - if (Sec->getType() != SHT_NOBITS) - FileOff += Sec->getSize(); - if (needsPhdr<ELFT>(Sec)) { - PH->p_filesz = FileOff - PH->p_offset; - PH->p_memsz = VA - PH->p_vaddr; + // If flags changed then we want new load segment. + uintX_t NewFlags = toPhdrFlags(Sec->getFlags()); + if (Flags != NewFlags) { + Load = AddHdr(PT_LOAD, NewFlags); + Flags = NewFlags; } - } - if (TlsPhdr.p_vaddr) { - // The TLS pointer goes after PT_TLS. At least glibc will align it, - // so round up the size to make sure the offsets are correct. - TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align); - Phdrs[++PhdrIdx] = TlsPhdr; - Out<ELFT>::TlsPhdr = &Phdrs[PhdrIdx]; + AddSec(*Load, Sec); + + if (isRelroSection(Sec)) + AddSec(RelRo, Sec); + if (Sec->getType() == SHT_NOTE) + AddSec(Note, Sec); } + // Add the TLS segment unless it's empty. + if (TlsHdr.First) + Phdrs.push_back(std::move(TlsHdr)); + // Add an entry for .dynamic. if (isOutputDynamic()) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_DYNAMIC; - copyPhdr(PH, Out<ELFT>::Dynamic); + Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags())); + AddSec(H, Out<ELFT>::Dynamic); } - if (HasRelro) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - *PH = GnuRelroPhdr; + // PT_GNU_RELRO includes all sections that should be marked as + // read-only by dynamic linker after proccessing relocations. + if (RelRo.First) + Phdrs.push_back(std::move(RelRo)); + + // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. + if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) { + Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME, + toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags())); + AddSec(Hdr, Out<ELFT>::EhFrameHdr); } // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. - if (!Config->ZExecStack) { - Elf_Phdr *PH = &Phdrs[++PhdrIdx]; - PH->p_type = PT_GNU_STACK; - PH->p_flags = PF_R | PF_W; + if (!Config->ZExecStack) + AddHdr(PT_GNU_STACK, PF_R | PF_W); + + if (Note.First) + Phdrs.push_back(std::move(Note)); + + Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size()); +} + +// The first section of each PT_LOAD and the first section after PT_GNU_RELRO +// have to be page aligned so that the dynamic linker can set the permissions. +template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { + for (const Phdr &P : Phdrs) + if (P.H.p_type == PT_LOAD) + P.First->PageAlign = true; + + for (const Phdr &P : Phdrs) { + if (P.H.p_type != PT_GNU_RELRO) + continue; + // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we + // have to align it to a page. + auto End = OutputSections.end(); + auto I = std::find(OutputSections.begin(), End, P.Last); + if (I == End || (I + 1) == End) + continue; + OutputSectionBase<ELFT> *Sec = *(I + 1); + if (needsPtLoad(Sec)) + Sec->PageAlign = true; } +} - // Fix up PT_INTERP as we now know the address of .interp section. - if (Interp) { - Interp->p_type = PT_INTERP; - copyPhdr(Interp, Out<ELFT>::Interp); +// We should set file offsets and VAs for elf header and program headers +// sections. These are special, we do not include them into output sections +// list, but have them to simplify the code. +template <class ELFT> void Writer<ELFT>::fixHeaders() { + uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Config->ImageBase; + Out<ELFT>::ElfHeader->setVA(BaseVA); + uintX_t Off = Out<ELFT>::ElfHeader->getSize(); + Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA); +} + +// Assign VAs (addresses at run-time) to output sections. +template <class ELFT> void Writer<ELFT>::assignAddresses() { + uintX_t VA = Config->ImageBase + Out<ELFT>::ElfHeader->getSize() + + Out<ELFT>::ProgramHeaders->getSize(); + + uintX_t ThreadBssOffset = 0; + for (OutputSectionBase<ELFT> *Sec : OutputSections) { + uintX_t Alignment = Sec->getAlignment(); + if (Sec->PageAlign) + Alignment = std::max<uintX_t>(Alignment, Target->PageSize); + + // We only assign VAs to allocated sections. + if (needsPtLoad<ELFT>(Sec)) { + VA = alignTo(VA, Alignment); + Sec->setVA(VA); + VA += Sec->getSize(); + } else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) { + uintX_t TVA = VA + ThreadBssOffset; + TVA = alignTo(TVA, Alignment); + Sec->setVA(TVA); + ThreadBssOffset = TVA - VA + Sec->getSize(); + } } +} - // Add space for section headers. - SectionHeaderOff = align(FileOff, ELFT::Is64Bits ? 8 : 4); - FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); +// Adjusts the file alignment for a given output section and returns +// its new file offset. The file offset must be the same with its +// virtual address (modulo the page size) so that the loader can load +// executables without any address adjustment. +template <class ELFT, class uintX_t> +static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) { + uintX_t Alignment = Sec->getAlignment(); + if (Sec->PageAlign) + Alignment = std::max<uintX_t>(Alignment, Target->PageSize); + Off = alignTo(Off, Alignment); - // Update "_end" and "end" symbols so that they - // point to the end of the data segment. - ElfSym<ELFT>::End.st_value = VA; + // Relocatable output does not have program headers + // and does not need any other offset adjusting. + if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC)) + return Off; + return alignTo(Off, Target->PageSize, Sec->getVA()); } -// Returns the number of PHDR entries. -template <class ELFT> int Writer<ELFT>::getPhdrsNum() const { - bool Tls = false; - int I = 2; // 2 for PT_PHDR and first PT_LOAD - if (needsInterpSection()) - ++I; - if (isOutputDynamic()) - ++I; - if (!Config->ZExecStack) - ++I; - uintX_t Last = PF_R; - for (OutputSectionBase<ELFT> *Sec : OutputSections) { - if (!needsPhdr<ELFT>(Sec)) - continue; - if (Sec->getFlags() & SHF_TLS) - Tls = true; - uintX_t Flags = toPhdrFlags(Sec->getFlags()); - if (Last != Flags) { - Last = Flags; - ++I; +// Assign file offsets to output sections. +template <class ELFT> void Writer<ELFT>::assignFileOffsets() { + uintX_t Off = 0; + + auto Set = [&](OutputSectionBase<ELFT> *Sec) { + if (Sec->getType() == SHT_NOBITS) { + Sec->setFileOffset(Off); + return; + } + + Off = getFileAlignment<ELFT>(Off, Sec); + Sec->setFileOffset(Off); + Off += Sec->getSize(); + }; + + Set(Out<ELFT>::ElfHeader); + Set(Out<ELFT>::ProgramHeaders); + for (OutputSectionBase<ELFT> *Sec : OutputSections) + Set(Sec); + + SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); + FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); +} + +// Finalize the program headers. We call this function after we assign +// file offsets and VAs to all sections. +template <class ELFT> void Writer<ELFT>::setPhdrs() { + for (Phdr &P : Phdrs) { + Elf_Phdr &H = P.H; + OutputSectionBase<ELFT> *First = P.First; + OutputSectionBase<ELFT> *Last = P.Last; + if (First) { + H.p_filesz = Last->getFileOff() - First->getFileOff(); + if (Last->getType() != SHT_NOBITS) + H.p_filesz += Last->getSize(); + H.p_memsz = Last->getVA() + Last->getSize() - First->getVA(); + H.p_offset = First->getFileOff(); + H.p_vaddr = First->getVA(); + } + if (H.p_type == PT_LOAD) + H.p_align = Target->PageSize; + else if (H.p_type == PT_GNU_RELRO) + H.p_align = 1; + H.p_paddr = H.p_vaddr; + + // The TLS pointer goes after PT_TLS. At least glibc will align it, + // so round up the size to make sure the offsets are correct. + if (H.p_type == PT_TLS) { + Out<ELFT>::TlsPhdr = &H; + H.p_memsz = alignTo(H.p_memsz, H.p_align); } } - if (Tls) - ++I; - if (HasRelro) - ++I; - return I; } -static uint32_t getELFFlags() { - if (Config->EMachine != EM_MIPS) - return 0; +static uint32_t getMipsEFlags(bool Is64Bits) { // FIXME: In fact ELF flags depends on ELF flags of input object files // and selected emulation. For now just use hard coded values. - uint32_t V = EF_MIPS_ABI_O32 | EF_MIPS_CPIC | EF_MIPS_ARCH_32R2; + if (Is64Bits) + return EF_MIPS_CPIC | EF_MIPS_PIC | EF_MIPS_ARCH_64R2; + + uint32_t V = EF_MIPS_CPIC | EF_MIPS_ABI_O32 | EF_MIPS_ARCH_32R2; if (Config->Shared) V |= EF_MIPS_PIC; return V; } -template <class ELFT> -static typename ELFFile<ELFT>::uintX_t getEntryAddr() { - if (Config->EntrySym) { - if (SymbolBody *E = Config->EntrySym->repl()) - return getSymVA<ELFT>(*E); - return 0; - } +template <class ELFT> static typename ELFT::uint getEntryAddr() { + if (Symbol *S = Config->EntrySym) + return S->body()->getVA<ELFT>(); if (Config->EntryAddr != uint64_t(-1)) return Config->EntryAddr; return 0; } +template <class ELFT> static uint8_t getELFEncoding() { + if (ELFT::TargetEndianness == llvm::support::little) + return ELFDATA2LSB; + return ELFDATA2MSB; +} + +static uint16_t getELFType() { + if (Config->Pic) + return ET_DYN; + if (Config->Relocatable) + return ET_REL; + return ET_EXEC; +} + // This function is called after we have assigned address and size // to each section. This function fixes some predefined absolute // symbol values that depend on section address and size. template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() { - // Update __rel[a]_iplt_{start,end} symbols so that they point - // to beginning or ending of .rela.plt section, respectively. - if (Out<ELFT>::RelaPlt) { - uintX_t Start = Out<ELFT>::RelaPlt->getVA(); - ElfSym<ELFT>::RelaIpltStart.st_value = Start; - ElfSym<ELFT>::RelaIpltEnd.st_value = Start + Out<ELFT>::RelaPlt->getSize(); - } + auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) { + if (S1) + S1->Value = V; + if (S2) + S2->Value = V; + }; - // Update MIPS _gp absolute symbol so that it points to the static data. - if (Config->EMachine == EM_MIPS) - ElfSym<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>(); + // _etext is the first location after the last read-only loadable segment. + // _edata is the first location after the last read-write loadable segment. + // _end is the first location after the uninitialized data region. + for (Phdr &P : Phdrs) { + Elf_Phdr &H = P.H; + if (H.p_type != PT_LOAD) + continue; + Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, H.p_vaddr + H.p_memsz); + + uintX_t Val = H.p_vaddr + H.p_filesz; + if (H.p_flags & PF_W) + Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val); + else + Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val); + } } template <class ELFT> void Writer<ELFT>::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); + auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf); + // Write the ELF header. auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf); EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; - EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little - ? ELFDATA2LSB - : ELFDATA2MSB; + EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>(); EHdr->e_ident[EI_VERSION] = EV_CURRENT; - - auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf); EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI(); - - EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC; - EHdr->e_machine = FirstObj.getEMachine(); + EHdr->e_type = getELFType(); + EHdr->e_machine = FirstObj.EMachine; EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr<ELFT>(); - EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_shoff = SectionHeaderOff; - EHdr->e_flags = getELFFlags(); EHdr->e_ehsize = sizeof(Elf_Ehdr); - EHdr->e_phentsize = sizeof(Elf_Phdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = getNumSections(); + EHdr->e_shnum = OutputSections.size() + 1; EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex; + if (Config->EMachine == EM_MIPS) + EHdr->e_flags = getMipsEFlags(ELFT::Is64Bits); + + if (!Config->Relocatable) { + EHdr->e_phoff = sizeof(Elf_Ehdr); + EHdr->e_phentsize = sizeof(Elf_Phdr); + } + // Write the program header table. - memcpy(Buf + EHdr->e_phoff, &Phdrs[0], Phdrs.size() * sizeof(Phdrs[0])); + auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff); + for (Phdr &P : Phdrs) + *HBuf++ = P.H; // Write the section header table. Note that the first table entry is null. - auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); + auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); for (OutputSectionBase<ELFT> *Sec : OutputSections) Sec->writeHeaderTo(++SHdrs); } -template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) { +template <class ELFT> void Writer<ELFT>::openFile() { ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable); - error(BufferOrErr, "failed to open " + Path); - Buffer = std::move(*BufferOrErr); + FileOutputBuffer::create(Config->OutputFile, FileSize, + FileOutputBuffer::F_executable); + if (auto EC = BufferOrErr.getError()) + error(EC, "failed to open " + Config->OutputFile); + else + Buffer = std::move(*BufferOrErr); } // Write section contents to a mmap'ed file. @@ -1257,53 +1251,33 @@ template <class ELFT> void Writer<ELFT>::writeSections() { Sec->writeTo(Buf + Sec->getFileOff()); } - // Write all sections but string table sections. We know the sizes of the - // string tables already, but they may not have actual strings yet (only - // room may be reserved), because writeTo() is allowed to add actual - // strings to the string tables. for (OutputSectionBase<ELFT> *Sec : OutputSections) - if (Sec != Out<ELFT>::Opd && Sec->getType() != SHT_STRTAB) + if (Sec != Out<ELFT>::Opd) Sec->writeTo(Buf + Sec->getFileOff()); - - // Write string table sections. - for (OutputSectionBase<ELFT> *Sec : OutputSections) - if (Sec != Out<ELFT>::Opd && Sec->getType() == SHT_STRTAB) - Sec->writeTo(Buf + Sec->getFileOff()); -} - -template <class ELFT> -void Writer<ELFT>::setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags, - uintX_t FileOff, uintX_t VA, uintX_t Size, - uintX_t Align) { - PH->p_type = Type; - PH->p_flags = Flags; - PH->p_offset = FileOff; - PH->p_vaddr = VA; - PH->p_paddr = VA; - PH->p_filesz = Size; - PH->p_memsz = Size; - PH->p_align = Align; } -template <class ELFT> -void Writer<ELFT>::copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From) { - PH->p_flags = toPhdrFlags(From->getFlags()); - PH->p_offset = From->getFileOff(); - PH->p_vaddr = From->getVA(); - PH->p_paddr = From->getVA(); - PH->p_filesz = From->getSize(); - PH->p_memsz = From->getSize(); - PH->p_align = From->getAlign(); -} +template <class ELFT> void Writer<ELFT>::writeBuildId() { + if (!Out<ELFT>::BuildId) + return; -template <class ELFT> void Writer<ELFT>::buildSectionMap() { - for (const std::pair<StringRef, std::vector<StringRef>> &OutSec : - Config->OutputSections) - for (StringRef Name : OutSec.second) - InputToOutputSection[Name] = OutSec.first; + // Compute a hash of all sections except .debug_* sections. + // We skip debug sections because they tend to be very large + // and their contents are very likely to be the same as long as + // other sections are the same. + uint8_t *Start = Buffer->getBufferStart(); + uint8_t *Last = Start; + std::vector<ArrayRef<uint8_t>> Regions; + for (OutputSectionBase<ELFT> *Sec : OutputSections) { + uint8_t *End = Start + Sec->getFileOff(); + if (!Sec->getName().startswith(".debug_")) + Regions.push_back({Last, End}); + Last = End; + } + Regions.push_back({Last, Start + FileSize}); + Out<ELFT>::BuildId->writeBuildId(Regions); } -template void elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab); -template void elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab); -template void elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab); -template void elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab); +template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab); +template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab); +template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab); +template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab); diff --git a/ELF/Writer.h b/ELF/Writer.h index 40a1711e2bd2..df25d8e404c2 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -10,14 +10,28 @@ #ifndef LLD_ELF_WRITER_H #define LLD_ELF_WRITER_H -namespace lld { -namespace elf2 { +#include <memory> + +namespace llvm { + class StringRef; +} +namespace lld { +namespace elf { +template <class ELFT> class InputSectionBase; +template <class ELFT> class ObjectFile; template <class ELFT> class SymbolTable; template <class ELFT> void writeResult(SymbolTable<ELFT> *Symtab); -template <class ELFT> void markLive(SymbolTable<ELFT> *Symtab); +template <class ELFT> void markLive(); + +template <class ELFT> +llvm::StringRef getOutputSectionName(InputSectionBase<ELFT> *S); + +template <class ELFT> +void reportDiscarded(InputSectionBase<ELFT> *IS, + const std::unique_ptr<elf::ObjectFile<ELFT>> &File); } } |
