Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -92,6 +92,7 @@ bool Mips64EL = false; bool NoGnuUnique; bool NoUndefinedVersion; + bool OFormatBinary; bool Pic; bool Pie; bool PrintGcSections; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -334,6 +334,16 @@ 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 @@ } } + Config->OFormatBinary = isOutputFormatBinary(Args); + for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -119,6 +119,9 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; +def oformat: Separate<["--"], "oformat">, MetaVarName<"">, + 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">, Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -58,6 +58,7 @@ std::vector createPhdrs(); void assignAddresses(); void assignFileOffsets(); + void assignFileOffsetsBinary(); void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); @@ -65,6 +66,7 @@ void openFile(); void writeHeader(); void writeSections(); + void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; @@ -268,7 +270,12 @@ fixSectionAlignments(); assignAddresses(); } - assignFileOffsets(); + + if (!Config->OFormatBinary) + assignFileOffsets(); + else + assignFileOffsetsBinary(); + setPhdrs(); fixAbsoluteSymbols(); } @@ -276,8 +283,12 @@ openFile(); if (HasError) return; - writeHeader(); - writeSections(); + if (!Config->OFormatBinary) { + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } writeBuildId(); if (HasError) return; @@ -1056,8 +1067,10 @@ // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { - uintX_t VA = Config->ImageBase + Out::ElfHeader->getSize() + - Out::ProgramHeaders->getSize(); + uintX_t VA = Config->ImageBase; + if (!Config->OFormatBinary) + VA += + Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { @@ -1097,25 +1110,34 @@ return alignTo(Off, Target->PageSize, Sec->getVA()); } +template +void setOffset(OutputSectionBase *Sec, uintX_t &Off) { + if (Sec->getType() == SHT_NOBITS) { + Sec->setFileOffset(Off); + return; + } + + Off = getFileAlignment(Off, Sec); + Sec->setFileOffset(Off); + Off += Sec->getSize(); +} + +template void Writer::assignFileOffsetsBinary() { + uintX_t Off = 0; + for (OutputSectionBase *Sec : OutputSections) + if (Sec->getFlags() & SHF_ALLOC) + setOffset(Sec, Off); + FileSize = alignTo(Off, sizeof(uintX_t)); +} + // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uintX_t Off = 0; + setOffset(Out::ElfHeader, Off); + setOffset(Out::ProgramHeaders, Off); - auto Set = [&](OutputSectionBase *Sec) { - if (Sec->getType() == SHT_NOBITS) { - Sec->setFileOffset(Off); - return; - } - - Off = getFileAlignment(Off, Sec); - Sec->setFileOffset(Off); - Off += Sec->getSize(); - }; - - Set(Out::ElfHeader); - Set(Out::ProgramHeaders); for (OutputSectionBase *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 @@ Buffer = std::move(*BufferOrErr); } +template void Writer::writeSectionsBinary() { + uint8_t *Buf = Buffer->getBufferStart(); + for (OutputSectionBase *Sec : OutputSections) + if (Sec->getFlags() & SHF_ALLOC) + Sec->writeTo(Buf + Sec->getFileOff()); +} + // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); Index: lld/trunk/test/ELF/oformat-binary.s =================================================================== --- lld/trunk/test/ELF/oformat-binary.s +++ lld/trunk/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