Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -32,6 +32,8 @@ enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; +enum class OutputFormat { Elf, Binary }; + enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore }; struct SymbolVersion { @@ -117,6 +119,7 @@ UnresolvedPolicy UnresolvedSymbols; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; + OutputFormat OFormat; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = -1; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -334,6 +334,15 @@ return UnresolvedPolicy::Error; } +static OutputFormat getOutputFormat(opt::InputArgList &Args) { + StringRef S = getString(Args, OPT_oformat); + if (S == "binary") + return OutputFormat::Binary; + if (!S.empty()) + error("unknown --oformat value:" + S); + return OutputFormat::Elf; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -450,6 +459,8 @@ } } + Config->OFormat = getOutputFormat(Args); + for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ 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: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ 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; @@ -126,7 +128,8 @@ VersionNeedSection VerNeed; OutputSectionBase ElfHeader("", 0, SHF_ALLOC); - ElfHeader.setSize(sizeof(Elf_Ehdr)); + if (Config->OFormat != OutputFormat::Binary) + ElfHeader.setSize(sizeof(Elf_Ehdr)); OutputSectionBase ProgramHeaders("", 0, SHF_ALLOC); ProgramHeaders.updateAlignment(sizeof(uintX_t)); @@ -261,14 +264,21 @@ } else { Phdrs = Script::X->hasPhdrsCommands() ? Script::X->createPhdrs() : createPhdrs(); - fixHeaders(); + if (Config->OFormat == OutputFormat::Elf) + fixHeaders(); + if (ScriptConfig->HasContents) { Script::X->assignAddresses(); } else { fixSectionAlignments(); assignAddresses(); } - assignFileOffsets(); + + if (Config->OFormat == OutputFormat::Elf) + assignFileOffsets(); + else + assignFileOffsetsBinary(); + setPhdrs(); fixAbsoluteSymbols(); } @@ -276,8 +286,12 @@ openFile(); if (HasError) return; - writeHeader(); - writeSections(); + if (Config->OFormat == OutputFormat::Elf) { + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } writeBuildId(); if (HasError) return; @@ -1056,7 +1070,6 @@ template void Writer::assignAddresses() { uintX_t VA = Config->ImageBase + Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); - uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->getAlignment(); @@ -1095,25 +1108,34 @@ return alignTo(Off, Target->PageSize, Sec->getVA()); } +template +void setOffsets(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) + setOffsets(Sec, Off); + FileSize = alignTo(Off, sizeof(uintX_t)); +} + // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uintX_t Off = 0; + setOffsets(Out::ElfHeader, Off); + setOffsets(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); + setOffsets(Sec, Off); SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); @@ -1256,6 +1278,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: test/ELF/oformat-binary.s =================================================================== --- test/ELF/oformat-binary.s +++ test/ELF/oformat-binary.s @@ -0,0 +1,19 @@ +# 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 + +.text +.align 4 +.globl _start +_start: + nop + +.section .mysec.1,"ax" +.byte 0x11 + +.section .mysec.2,"ax" +.byte 0x22