Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -83,6 +83,7 @@ llvm::StringRef LtoNewPmPasses; llvm::StringRef OutputFile; llvm::StringRef SoName; + llvm::StringRef Startup; llvm::StringRef Sysroot; std::string RPath; std::vector VersionDefinitions; Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -37,6 +37,7 @@ void readConfigs(llvm::opt::InputArgList &Args); void createFiles(llvm::opt::InputArgList &Args); void inferMachineType(); + void reorderFiles(); template void link(llvm::opt::InputArgList &Args); // True if we are in --whole-archive and --no-whole-archive. Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -691,6 +691,24 @@ error("target emulation unknown: -m or at least one .o file required"); } +// This is for linker script STARTUP command. If STARTUP(foo.o) is +// specified, LLD reorders input files so that foo.o becomes the first +// object file to be linked, assuming that the file's .text section +// will become the executable's entry address. +void LinkerDriver::reorderFiles() { + if (Config->Startup.empty()) + return; + for (auto I = Files.begin(), E = Files.end(); I != E; ++I) { + InputFile *F = *I; + if (F->getName() != Config->Startup) + continue; + Files.erase(I); + Files.insert(Files.begin(), F); + return; + } + warn(Config->Startup + ": STARTUP file not found"); +} + // Parses -image-base option. static uint64_t getImageBase(opt::InputArgList &Args) { // Use default if no -image-base option is given. @@ -743,6 +761,9 @@ if (!isPowerOf2_64(Config->MaxPageSize)) error("max-page-size: value isn't a power of 2"); + // Process linker script STARTUP command. + reorderFiles(); + // Add all files to the symbol table. After this, the symbol table // contains all known names except a few linker-synthesized symbols. for (InputFile *F : Files) Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -973,6 +973,7 @@ void readPhdrs(); void readSearchDir(); void readSections(); + void readStartup(); void readVersion(); void readVersionScriptCommand(); @@ -1069,6 +1070,8 @@ readSearchDir(); } else if (Tok == "SECTIONS") { readSections(); + } else if (Tok == "STARTUP") { + readStartup(); } else if (Tok == "VERSION") { readVersion(); } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { @@ -1243,6 +1246,8 @@ } } +void ScriptParser::readStartup() { Config->Startup = readParenLiteral(); } + static int precedence(StringRef Op) { return StringSwitch(Op) .Cases("*", "/", 5) Index: test/ELF/linkerscript/startup.s =================================================================== --- /dev/null +++ test/ELF/linkerscript/startup.s @@ -0,0 +1,29 @@ +# REQUIRES: x86 + +# RUN: mkdir -p %t.dir +# RUN: cd %t.dir + +# RUN: echo ".quad 0xAAAAAAAAAAAAAAAA" > %t1.s +# RUN: echo ".quad 0xFFFFFFFFFFFFFFFF" > %t2.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t1.s -o foo.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o bar.o + +# RUN: echo "STARTUP(foo.o)" > script +# RUN: ld.lld -o exe -script=script foo.o bar.o +# RUN: llvm-objdump -s exe | FileCheck -check-prefix=FOO %s + +# FOO: Contents of section .text: +# FOO: 201000 aaaaaaaa aaaaaaaa ffffffff ffffffff + +# RUN: echo "STARTUP(bar.o)" > script +# RUN: ld.lld -o exe -script=script foo.o bar.o +# RUN: llvm-objdump -s exe | FileCheck -check-prefix=BAR %s + +# BAR: Contents of section .text: +# BAR: 201000 ffffffff ffffffff aaaaaaaa aaaaaaaa + +# RUN: echo "STARTUP(nosuchfile)" > script +# RUN: ld.lld -o exe -script=script foo.o bar.o 2>&1 \ +# RUN: | FileCheck -check-prefix=WARN %s + +# WARN: nosuchfile: STARTUP file not found