[lld] r281108 - [ELF] Add support for -b binary

Michael J. Spencer via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 9 15:08:04 PDT 2016


Author: mspencer
Date: Fri Sep  9 17:08:04 2016
New Revision: 281108

URL: http://llvm.org/viewvc/llvm-project?rev=281108&view=rev
Log:
[ELF] Add support for -b binary

Implemented by building an ELF file in memory.

elf, default, and binary match gold behavior.

Differential Revision: https://reviews.llvm.org/D24060

Added:
    lld/trunk/ELF/ELFCreator.cpp
    lld/trunk/ELF/ELFCreator.h
    lld/trunk/test/elf/
    lld/trunk/test/elf/format-binary.test
Modified:
    lld/trunk/ELF/CMakeLists.txt
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/Driver.h
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/SymbolTable.cpp

Modified: lld/trunk/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/CMakeLists.txt (original)
+++ lld/trunk/ELF/CMakeLists.txt Fri Sep  9 17:08:04 2016
@@ -6,6 +6,7 @@ add_lld_library(lldELF
   Driver.cpp
   DriverUtils.cpp
   EhFrame.cpp
+  ELFCreator.cpp
   Error.cpp
   ICF.cpp
   InputFiles.cpp

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Fri Sep  9 17:08:04 2016
@@ -85,6 +85,7 @@ struct Configuration {
   std::vector<uint8_t> BuildIdVector;
   bool AllowMultipleDefinition;
   bool AsNeeded = false;
+  bool Binary = false;
   bool Bsymbolic;
   bool BsymbolicFunctions;
   bool Demangle = true;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Fri Sep  9 17:08:04 2016
@@ -116,7 +116,7 @@ LinkerDriver::getArchiveMembers(MemoryBu
 
 // Opens and parses a file. Path has to be resolved already.
 // Newly created memory buffers are owned by this driver.
-void LinkerDriver::addFile(StringRef Path) {
+void LinkerDriver::addFile(StringRef Path, bool KnownScript) {
   using namespace sys::fs;
   if (Config->Verbose)
     outs() << Path << "\n";
@@ -126,6 +126,11 @@ void LinkerDriver::addFile(StringRef Pat
     return;
   MemoryBufferRef MBRef = *Buffer;
 
+  if (Config->Binary && !KnownScript) {
+    Files.push_back(make_unique<BinaryFile>(MBRef));
+    return;
+  }
+
   switch (identify_magic(MBRef.getBuffer())) {
   case file_magic::unknown:
     readLinkerScript(MBRef);
@@ -515,14 +520,27 @@ void LinkerDriver::createFiles(opt::Inpu
     case OPT_l:
       addLibrary(Arg->getValue());
       break;
-    case OPT_alias_script_T:
     case OPT_INPUT:
-    case OPT_script:
       addFile(Arg->getValue());
       break;
+    case OPT_alias_script_T:
+    case OPT_script:
+      addFile(Arg->getValue(), true);
+      break;
     case OPT_as_needed:
       Config->AsNeeded = true;
       break;
+    case OPT_format: {
+      StringRef Val = Arg->getValue();
+      if (Val == "elf" || Val == "default")
+        Config->Binary = false;
+      else if (Val == "binary")
+        Config->Binary = true;
+      else
+        error("unknown " + Arg->getSpelling() + " format: " + Arg->getValue() +
+              " (supported formats: elf, default, binary)");
+      break;
+    }
     case OPT_no_as_needed:
       Config->AsNeeded = false;
       break;

Modified: lld/trunk/ELF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.h (original)
+++ lld/trunk/ELF/Driver.h Fri Sep  9 17:08:04 2016
@@ -27,7 +27,7 @@ extern class LinkerDriver *Driver;
 class LinkerDriver {
 public:
   void main(ArrayRef<const char *> Args);
-  void addFile(StringRef Path);
+  void addFile(StringRef Path, bool KnownScript = false);
   void addLibrary(StringRef Name);
   llvm::LLVMContext Context;      // to parse bitcode ifles
   std::unique_ptr<CpioFile> Cpio; // for reproduce

Added: lld/trunk/ELF/ELFCreator.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ELFCreator.cpp?rev=281108&view=auto
==============================================================================
--- lld/trunk/ELF/ELFCreator.cpp (added)
+++ lld/trunk/ELF/ELFCreator.cpp Fri Sep  9 17:08:04 2016
@@ -0,0 +1,121 @@
+//===- ELFCreator.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ELFCreator.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT>
+ELFCreator<ELFT>::ELFCreator(std::uint16_t Type, std::uint16_t Machine) {
+  std::memcpy(Header.e_ident, "\177ELF", 4);
+  Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+  Header.e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
+                                ? ELFDATA2LSB
+                                : ELFDATA2MSB;
+  Header.e_ident[EI_VERSION] = EV_CURRENT;
+  Header.e_ident[EI_OSABI] = 0;
+  Header.e_type = Type;
+  Header.e_machine = Machine;
+  Header.e_version = EV_CURRENT;
+  Header.e_entry = 0;
+  Header.e_phoff = 0;
+  Header.e_flags = 0;
+  Header.e_ehsize = sizeof(Elf_Ehdr);
+  Header.e_phnum = 0;
+  Header.e_shentsize = sizeof(Elf_Shdr);
+  Header.e_shstrndx = 1;
+
+  ShStrTab = addSection(".shstrtab").Header;
+  ShStrTab->sh_type = SHT_STRTAB;
+  ShStrTab->sh_addralign = 1;
+
+  StrTab = addSection(".strtab").Header;
+  StrTab->sh_type = SHT_STRTAB;
+  StrTab->sh_addralign = 1;
+
+  SymTab = addSection(".symtab").Header;
+  SymTab->sh_type = SHT_SYMTAB;
+  SymTab->sh_link = 2;
+  SymTab->sh_info = 1;
+  SymTab->sh_addralign = sizeof(uintX_t);
+  SymTab->sh_entsize = sizeof(Elf_Sym);
+}
+
+template <class ELFT>
+typename ELFCreator<ELFT>::Section
+ELFCreator<ELFT>::addSection(StringRef Name) {
+  std::size_t NameOff = SecHdrStrTabBuilder.add(Name);
+  auto Shdr = new (Alloc) Elf_Shdr{};
+  Shdr->sh_name = NameOff;
+  Sections.push_back(Shdr);
+  return {Shdr, Sections.size()};
+}
+
+template <class ELFT>
+typename ELFCreator<ELFT>::Symbol ELFCreator<ELFT>::addSymbol(StringRef Name) {
+  std::size_t NameOff = StrTabBuilder.add(Name);
+  auto Sym = new (Alloc) Elf_Sym{};
+  Sym->st_name = NameOff;
+  StaticSymbols.push_back(Sym);
+  return {Sym, StaticSymbols.size()};
+}
+
+template <class ELFT> std::size_t ELFCreator<ELFT>::layout() {
+  SecHdrStrTabBuilder.finalizeInOrder();
+  ShStrTab->sh_size = SecHdrStrTabBuilder.getSize();
+
+  StrTabBuilder.finalizeInOrder();
+  StrTab->sh_size = StrTabBuilder.getSize();
+
+  SymTab->sh_size = (StaticSymbols.size() + 1) * sizeof(Elf_Sym);
+
+  uintX_t Offset = sizeof(Elf_Ehdr);
+  for (Elf_Shdr *Sec : Sections) {
+    Offset = alignTo(Offset, Sec->sh_addralign);
+    Sec->sh_offset = Offset;
+    Offset += Sec->sh_size;
+  }
+
+  Offset = alignTo(Offset, sizeof(uintX_t));
+  Header.e_shoff = Offset;
+  Offset += (Sections.size() + 1) * sizeof(Elf_Shdr);
+  Header.e_shnum = Sections.size() + 1;
+
+  return Offset;
+}
+
+template <class ELFT> void ELFCreator<ELFT>::write(uint8_t *Out) {
+  std::memcpy(Out, &Header, sizeof(Elf_Ehdr));
+  std::copy(SecHdrStrTabBuilder.data().begin(),
+            SecHdrStrTabBuilder.data().end(), Out + ShStrTab->sh_offset);
+  std::copy(StrTabBuilder.data().begin(), StrTabBuilder.data().end(),
+            Out + StrTab->sh_offset);
+
+  Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out + SymTab->sh_offset);
+  // Skip null.
+  ++Sym;
+  for (Elf_Sym *S : StaticSymbols)
+    *Sym++ = *S;
+
+  Elf_Shdr *Shdr = reinterpret_cast<Elf_Shdr *>(Out + Header.e_shoff);
+  // Skip null.
+  ++Shdr;
+  for (Elf_Shdr *S : Sections)
+    *Shdr++ = *S;
+}
+
+template class elf::ELFCreator<ELF32LE>;
+template class elf::ELFCreator<ELF32BE>;
+template class elf::ELFCreator<ELF64LE>;
+template class elf::ELFCreator<ELF64BE>;

Added: lld/trunk/ELF/ELFCreator.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ELFCreator.h?rev=281108&view=auto
==============================================================================
--- lld/trunk/ELF/ELFCreator.h (added)
+++ lld/trunk/ELF/ELFCreator.h Fri Sep  9 17:08:04 2016
@@ -0,0 +1,58 @@
+//===- ELFCreator.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ELF_CREATOR_H
+#define LLD_ELF_ELF_CREATOR_H
+
+#include "lld/Core/LLVM.h"
+
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELFTypes.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class ELFCreator {
+  typedef typename ELFT::uint uintX_t;
+  typedef typename ELFT::Ehdr Elf_Ehdr;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+
+public:
+  struct Section {
+    Elf_Shdr *Header;
+    std::size_t Index;
+  };
+
+  struct Symbol {
+    Elf_Sym *Sym;
+    std::size_t Index;
+  };
+
+  ELFCreator(std::uint16_t Type, std::uint16_t Machine);
+  Section addSection(StringRef Name);
+  Symbol addSymbol(StringRef Name);
+  std::size_t layout();
+  void write(uint8_t *Out);
+
+private:
+  Elf_Ehdr Header;
+  std::vector<Elf_Shdr *> Sections;
+  std::vector<Elf_Sym *> StaticSymbols;
+  llvm::StringTableBuilder SecHdrStrTabBuilder{llvm::StringTableBuilder::ELF};
+  llvm::StringTableBuilder StrTabBuilder{llvm::StringTableBuilder::ELF};
+  llvm::BumpPtrAllocator Alloc;
+  Elf_Shdr *ShStrTab;
+  Elf_Shdr *StrTab;
+  Elf_Shdr *SymTab;
+};
+}
+}
+
+#endif

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Fri Sep  9 17:08:04 2016
@@ -12,6 +12,7 @@
 #include "Error.h"
 #include "InputSection.h"
 #include "LinkerScript.h"
+#include "ELFCreator.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
 #include "llvm/ADT/STLExtras.h"
@@ -19,6 +20,7 @@
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -730,6 +732,48 @@ static std::unique_ptr<InputFile> create
   return Obj;
 }
 
+template <class ELFT> std::unique_ptr<InputFile> BinaryFile::createELF() {
+  ELFCreator<ELFT> ELF(ET_REL, Config->EMachine);
+  auto DataSec = ELF.addSection(".data");
+  DataSec.Header->sh_flags = SHF_ALLOC;
+  DataSec.Header->sh_size = MB.getBufferSize();
+  DataSec.Header->sh_type = SHT_PROGBITS;
+  DataSec.Header->sh_addralign = 8;
+
+  std::string Filepath = MB.getBufferIdentifier();
+  std::transform(Filepath.begin(), Filepath.end(), Filepath.begin(),
+                 [](char C) { return isalnum(C) ? C : '_'; });
+  std::string StartSym = "_binary_" + Filepath + "_start";
+  std::string EndSym = "_binary_" + Filepath + "_end";
+  std::string SizeSym = "_binary_" + Filepath + "_size";
+
+  auto SSym = ELF.addSymbol(StartSym);
+  SSym.Sym->setBindingAndType(STB_GLOBAL, STT_OBJECT);
+  SSym.Sym->st_shndx = DataSec.Index;
+
+  auto ESym = ELF.addSymbol(EndSym);
+  ESym.Sym->setBindingAndType(STB_GLOBAL, STT_OBJECT);
+  ESym.Sym->st_shndx = DataSec.Index;
+  ESym.Sym->st_value = MB.getBufferSize();
+
+  auto SZSym = ELF.addSymbol(SizeSym);
+  SZSym.Sym->setBindingAndType(STB_GLOBAL, STT_OBJECT);
+  SZSym.Sym->st_shndx = SHN_ABS;
+  SZSym.Sym->st_value = MB.getBufferSize();
+
+  std::size_t Size = ELF.layout();
+  ELFData.resize(Size);
+
+  ELF.write(ELFData.data());
+
+  // .data
+  std::copy(MB.getBufferStart(), MB.getBufferEnd(),
+            ELFData.data() + DataSec.Header->sh_offset);
+
+  return createELFFile<ObjectFile>(MemoryBufferRef(
+      StringRef((char *)ELFData.data(), Size), MB.getBufferIdentifier()));
+}
+
 static bool isBitcode(MemoryBufferRef MB) {
   using namespace sys::fs;
   return identify_magic(MB.getBuffer()) == file_magic::bitcode;
@@ -850,3 +894,8 @@ template class elf::SharedFile<ELF32LE>;
 template class elf::SharedFile<ELF32BE>;
 template class elf::SharedFile<ELF64LE>;
 template class elf::SharedFile<ELF64BE>;
+
+template std::unique_ptr<InputFile> BinaryFile::createELF<ELF32LE>();
+template std::unique_ptr<InputFile> BinaryFile::createELF<ELF32BE>();
+template std::unique_ptr<InputFile> BinaryFile::createELF<ELF64LE>();
+template std::unique_ptr<InputFile> BinaryFile::createELF<ELF64BE>();

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Sep  9 17:08:04 2016
@@ -45,6 +45,7 @@ public:
     LazyObjectKind,
     ArchiveKind,
     BitcodeKind,
+    BinaryKind,
   };
 
   Kind kind() const { return FileKind; }
@@ -297,6 +298,18 @@ public:
   bool isNeeded() const { return !AsNeeded || IsUsed; }
 };
 
+class BinaryFile : public InputFile {
+public:
+  explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
+
+  static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
+
+  template <class ELFT> std::unique_ptr<InputFile> createELF();
+
+private:
+  std::vector<uint8_t> ELFData;
+};
+
 std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB,
                                             StringRef ArchiveName = "");
 std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB);

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Fri Sep  9 17:08:04 2016
@@ -74,6 +74,9 @@ def fatal_warnings: F<"fatal-warnings">,
 def fini: S<"fini">, MetaVarName<"<symbol>">,
   HelpText<"Specify a finalizer function">;
 
+def format: J<"format=">, MetaVarName<"<input-format>">,
+  HelpText<"Change the input format of the inputs following this option">;
+
 def gc_sections: F<"gc-sections">,
   HelpText<"Enable garbage collection of unused sections">;
 
@@ -212,6 +215,7 @@ def alias_export_dynamic_E: Flag<["-"],
 def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
   Alias<export_dynamic_symbol>;
 def alias_fini_fini: J<"fini=">, Alias<fini>;
+def alias_format_b: S<"b">, Alias<format>;
 def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
 def alias_init_init: J<"init=">, Alias<init>;
 def alias_l__library: J<"library=">, Alias<l>;

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=281108&r1=281107&r2=281108&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Fri Sep  9 17:08:04 2016
@@ -53,6 +53,12 @@ void SymbolTable<ELFT>::addFile(std::uni
   if (!isCompatible<ELFT>(FileP))
     return;
 
+  // Binary file
+  if (auto *F = dyn_cast<BinaryFile>(FileP)) {
+    addFile(F->createELF<ELFT>());
+    return;
+  }
+
   // .a file
   if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
     ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));

Added: lld/trunk/test/elf/format-binary.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/format-binary.test?rev=281108&view=auto
==============================================================================
--- lld/trunk/test/elf/format-binary.test (added)
+++ lld/trunk/test/elf/format-binary.test Fri Sep  9 17:08:04 2016
@@ -0,0 +1,52 @@
+# REQUIRES: x86
+
+# RUN: echo -n "Fluffle Puff" > %t.binary
+# RUN: ld.lld -m elf_x86_64 -r -b binary %t.binary -o %t.out
+# RUN: llvm-readobj %t.out -sections -section-data -symbols | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -b binary %t.binary -b default %t.o -shared -o %t.out
+
+# CHECK:          Name: .data
+# CHECK-NEXT:     Type: SHT_PROGBITS
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       SHF_ALLOC
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment:
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 466C7566 666C6520 50756666           |Fluffle Puff|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+
+# CHECK:          Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_start
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .data
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_end
+# CHECK-NEXT:     Value: 0xC
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .data
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_size
+# CHECK-NEXT:     Value: 0xC
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Absolute
+# CHECK-NEXT:   }




More information about the llvm-commits mailing list