diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 12 | ||||
-rw-r--r-- | lld/ELF/Options.td | 3 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 67 | ||||
-rw-r--r-- | lld/test/ELF/oformat-binary.s | 28 |
5 files changed, 92 insertions, 19 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 3f9b776f414..b2c107ce485 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -92,6 +92,7 @@ struct Configuration { bool Mips64EL = false; bool NoGnuUnique; bool NoUndefinedVersion; + bool OFormatBinary; bool Pic; bool Pie; bool PrintGcSections; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index a85f30fe7a3..451b2e49eab 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -334,6 +334,16 @@ static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) { return UnresolvedPolicy::Error; } +static bool isOutputFormatBinary(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_oformat)) { + StringRef S = Arg->getValue(); + if (S == "binary") + return true; + error("unknown --oformat value: " + S); + } + return false; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -450,6 +460,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } } + Config->OFormatBinary = isOutputFormatBinary(Args); + for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 7245ddfb6d1..0d4738d3df8 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -119,6 +119,9 @@ def no_undefined_version: F<"no-undefined-version">, def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; +def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, + HelpText<"Specify the binary format for the output object file">; + def pie: F<"pie">, HelpText<"Create a position independent executable">; def print_gc_sections: F<"print-gc-sections">, diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index d927ee3a376..4469944792b 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -58,6 +58,7 @@ private: std::vector<Phdr> createPhdrs(); void assignAddresses(); void assignFileOffsets(); + void assignFileOffsetsBinary(); void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); @@ -65,6 +66,7 @@ private: void openFile(); void writeHeader(); void writeSections(); + void writeSectionsBinary(); void writeBuildId(); std::unique_ptr<FileOutputBuffer> Buffer; @@ -268,7 +270,12 @@ template <class ELFT> void Writer<ELFT>::run() { fixSectionAlignments(); assignAddresses(); } - assignFileOffsets(); + + if (!Config->OFormatBinary) + assignFileOffsets(); + else + assignFileOffsetsBinary(); + setPhdrs(); fixAbsoluteSymbols(); } @@ -276,8 +283,12 @@ template <class ELFT> void Writer<ELFT>::run() { openFile(); if (HasError) return; - writeHeader(); - writeSections(); + if (!Config->OFormatBinary) { + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } writeBuildId(); if (HasError) return; @@ -1056,8 +1067,10 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() { // 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 VA = Config->ImageBase; + if (!Config->OFormatBinary) + VA += + Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase<ELFT> *Sec : OutputSections) { @@ -1097,25 +1110,34 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) { return alignTo(Off, Target->PageSize, Sec->getVA()); } +template <class ELFT, class uintX_t> +void setOffset(OutputSectionBase<ELFT> *Sec, uintX_t &Off) { + if (Sec->getType() == SHT_NOBITS) { + Sec->setFileOffset(Off); + return; + } + + Off = getFileAlignment<ELFT>(Off, Sec); + Sec->setFileOffset(Off); + Off += Sec->getSize(); +} + +template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { + uintX_t Off = 0; + for (OutputSectionBase<ELFT> *Sec : OutputSections) + if (Sec->getFlags() & SHF_ALLOC) + setOffset(Sec, Off); + FileSize = alignTo(Off, sizeof(uintX_t)); +} + // Assign file offsets to output sections. template <class ELFT> void Writer<ELFT>::assignFileOffsets() { uintX_t Off = 0; + setOffset(Out<ELFT>::ElfHeader, Off); + setOffset(Out<ELFT>::ProgramHeaders, Off); - 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); + setOffset(Sec, Off); SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); @@ -1262,6 +1284,13 @@ template <class ELFT> void Writer<ELFT>::openFile() { Buffer = std::move(*BufferOrErr); } +template <class ELFT> void Writer<ELFT>::writeSectionsBinary() { + uint8_t *Buf = Buffer->getBufferStart(); + for (OutputSectionBase<ELFT> *Sec : OutputSections) + if (Sec->getFlags() & SHF_ALLOC) + Sec->writeTo(Buf + Sec->getFileOff()); +} + // Write section contents to a mmap'ed file. template <class ELFT> void Writer<ELFT>::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); diff --git a/lld/test/ELF/oformat-binary.s b/lld/test/ELF/oformat-binary.s new file mode 100644 index 00000000000..49db7cdb2c1 --- /dev/null +++ b/lld/test/ELF/oformat-binary.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: ld.lld -o %t.out %t --oformat binary +# RUN: hexdump -C %t.out | FileCheck %s +# CHECK: 00000000 90 11 22 00 00 00 00 00 +# CHECK-NOT: 00000010 + +## Check case when linkerscript is used. +# RUN: echo "SECTIONS { . = 0x1000; }" > %t.script +# RUN: ld.lld -o %t2.out --script %t.script %t --oformat binary +# RUN: hexdump -C %t2.out | FileCheck %s + +# RUN: not ld.lld -o %t3.out %t --oformat foo 2>&1 \ +# RUN: | FileCheck %s --check-prefix ERR +# ERR: unknown --oformat value: foo + +.text +.align 4 +.globl _start +_start: + nop + +.section .mysec.1,"ax" +.byte 0x11 + +.section .mysec.2,"ax" +.byte 0x22 |