[ELF] - Implemented --oformat binary option.
authorGeorge Rimar <grimar@accesssoftek.com>
Thu, 25 Aug 2016 09:05:47 +0000 (09:05 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Thu, 25 Aug 2016 09:05:47 +0000 (09:05 +0000)
-oformat output-format
`-oformat' option can be used to specify the binary format for the output object file.

Patch implements binary format output type.

Differential revision: https://reviews.llvm.org/D23769

llvm-svn: 279726

lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/Options.td
lld/ELF/Writer.cpp
lld/test/ELF/oformat-binary.s [new file with mode: 0644]

index 3f9b776..b2c107c 100644 (file)
@@ -92,6 +92,7 @@ struct Configuration {
   bool Mips64EL = false;
   bool NoGnuUnique;
   bool NoUndefinedVersion;
+  bool OFormatBinary;
   bool Pic;
   bool Pie;
   bool PrintGcSections;
index a85f30f..451b2e4 100644 (file)
@@ -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());
 
index 7245ddf..0d4738d 100644 (file)
@@ -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">,
index d927ee3..4469944 100644 (file)
@@ -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 (file)
index 0000000..49db7cd
--- /dev/null
@@ -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