mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-01 13:20:25 +00:00
[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
This commit is contained in:
parent
58109abe91
commit
a9424f39c4
@ -6,6 +6,7 @@ add_lld_library(lldELF
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
EhFrame.cpp
|
||||
ELFCreator.cpp
|
||||
Error.cpp
|
||||
ICF.cpp
|
||||
InputFiles.cpp
|
||||
|
@ -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;
|
||||
|
@ -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<BinaryFile>(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;
|
||||
|
@ -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
|
||||
|
121
lld/ELF/ELFCreator.cpp
Normal file
121
lld/ELF/ELFCreator.cpp
Normal file
@ -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>;
|
58
lld/ELF/ELFCreator.h
Normal file
58
lld/ELF/ELFCreator.h
Normal file
@ -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
|
@ -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> createELFFile(MemoryBufferRef MB) {
|
||||
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>();
|
||||
|
@ -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);
|
||||
|
@ -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<["-"], "E">, Alias<export_dynamic>;
|
||||
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>;
|
||||
|
@ -53,6 +53,12 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
||||
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()));
|
||||
|
52
lld/test/elf/format-binary.test
Normal file
52
lld/test/elf/format-binary.test
Normal file
@ -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: }
|
Loading…
Reference in New Issue
Block a user