From: Michael J. Spencer Date: Fri, 9 Sep 2016 22:08:04 +0000 (+0000) Subject: [ELF] Add support for -b binary X-Git-Tag: llvmorg-4.0.0-rc1~10167 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a9424f39c4abf117a35454a7b05a13e561fc3b41;p=platform%2Fupstream%2Fllvm.git [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 llvm-svn: 281108 --- diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 2cb6e9a..b9e374a 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -6,6 +6,7 @@ add_lld_library(lldELF Driver.cpp DriverUtils.cpp EhFrame.cpp + ELFCreator.cpp Error.cpp ICF.cpp InputFiles.cpp diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 98246c3..410d910 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -85,6 +85,7 @@ struct Configuration { std::vector BuildIdVector; bool AllowMultipleDefinition; bool AsNeeded = false; + bool Binary = false; bool Bsymbolic; bool BsymbolicFunctions; bool Demangle = true; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 7b64664..31a0f8e 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -116,7 +116,7 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { // 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 Path) { return; MemoryBufferRef MBRef = *Buffer; + if (Config->Binary && !KnownScript) { + Files.push_back(make_unique(MBRef)); + return; + } + switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: readLinkerScript(MBRef); @@ -515,14 +520,27 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { 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; diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 9726430..b16244f 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -27,7 +27,7 @@ extern class LinkerDriver *Driver; class LinkerDriver { public: void main(ArrayRef 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 Cpio; // for reproduce diff --git a/lld/ELF/ELFCreator.cpp b/lld/ELF/ELFCreator.cpp new file mode 100644 index 0000000..37b7392 --- /dev/null +++ b/lld/ELF/ELFCreator.cpp @@ -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 +ELFCreator::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 +typename ELFCreator::Section +ELFCreator::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 +typename ELFCreator::Symbol ELFCreator::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 std::size_t ELFCreator::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 void ELFCreator::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(Out + SymTab->sh_offset); + // Skip null. + ++Sym; + for (Elf_Sym *S : StaticSymbols) + *Sym++ = *S; + + Elf_Shdr *Shdr = reinterpret_cast(Out + Header.e_shoff); + // Skip null. + ++Shdr; + for (Elf_Shdr *S : Sections) + *Shdr++ = *S; +} + +template class elf::ELFCreator; +template class elf::ELFCreator; +template class elf::ELFCreator; +template class elf::ELFCreator; diff --git a/lld/ELF/ELFCreator.h b/lld/ELF/ELFCreator.h new file mode 100644 index 0000000..cfd84c5 --- /dev/null +++ b/lld/ELF/ELFCreator.h @@ -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 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 Sections; + std::vector 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 diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 73bb65d..622dec5 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -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 createELFFile(MemoryBufferRef MB) { return Obj; } +template std::unique_ptr BinaryFile::createELF() { + ELFCreator 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(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; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; + +template std::unique_ptr BinaryFile::createELF(); +template std::unique_ptr BinaryFile::createELF(); +template std::unique_ptr BinaryFile::createELF(); +template std::unique_ptr BinaryFile::createELF(); diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 5978baf..0bababa 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -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 std::unique_ptr createELF(); + +private: + std::vector ELFData; +}; + std::unique_ptr createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = ""); std::unique_ptr createSharedFile(MemoryBufferRef MB); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 881d163..e90eb1a 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -74,6 +74,9 @@ def fatal_warnings: F<"fatal-warnings">, def fini: S<"fini">, MetaVarName<"">, HelpText<"Specify a finalizer function">; +def format: J<"format=">, MetaVarName<"">, + 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<["-"], "E">, Alias; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias; def alias_fini_fini: J<"fini=">, Alias; +def alias_format_b: S<"b">, Alias; def alias_hash_style_hash_style: J<"hash-style=">, Alias; def alias_init_init: J<"init=">, Alias; def alias_l__library: J<"library=">, Alias; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index f758247..7489207 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -53,6 +53,12 @@ void SymbolTable::addFile(std::unique_ptr File) { if (!isCompatible(FileP)) return; + // Binary file + if (auto *F = dyn_cast(FileP)) { + addFile(F->createELF()); + return; + } + // .a file if (auto *F = dyn_cast(FileP)) { ArchiveFiles.emplace_back(cast(File.release())); diff --git a/lld/test/elf/format-binary.test b/lld/test/elf/format-binary.test new file mode 100644 index 0000000..132f77c --- /dev/null +++ b/lld/test/elf/format-binary.test @@ -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: }