mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 08:16:49 +00:00
[ELF2] Handle -m option
Parse and apply emulation given with -m option. Check input files to match ELF type and machine architecture provided with -m. Differential Revision: http://reviews.llvm.org/D13055 llvm-svn: 249529
This commit is contained in:
parent
47efaeb36e
commit
1ef7b3ff55
@ -11,12 +11,21 @@
|
||||
#define LLD_ELF_CONFIG_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
enum ELFKind {
|
||||
ELFNoneKind,
|
||||
ELF32LEKind,
|
||||
ELF32BEKind,
|
||||
ELF64LEKind,
|
||||
ELF64BEKind
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
llvm::StringRef DynamicLinker;
|
||||
llvm::StringRef Entry;
|
||||
@ -38,6 +47,8 @@ struct Configuration {
|
||||
bool Shared;
|
||||
bool Static = false;
|
||||
bool WholeArchive = false;
|
||||
ELFKind ElfKind = ELFNoneKind;
|
||||
uint16_t EMachine = llvm::ELF::EM_NONE;
|
||||
};
|
||||
|
||||
extern Configuration *Config;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
@ -34,6 +35,30 @@ void lld::elf2::link(ArrayRef<const char *> Args) {
|
||||
Driver->link(Args.slice(1));
|
||||
}
|
||||
|
||||
static void setELFType(StringRef Emul) {
|
||||
if (Emul == "elf_i386") {
|
||||
Config->ElfKind = ELF32LEKind;
|
||||
Config->EMachine = EM_386;
|
||||
return;
|
||||
}
|
||||
if (Emul == "elf_x86_64") {
|
||||
Config->ElfKind = ELF64LEKind;
|
||||
Config->EMachine = EM_X86_64;
|
||||
return;
|
||||
}
|
||||
if (Emul == "elf32ppc") {
|
||||
Config->ElfKind = ELF32BEKind;
|
||||
Config->EMachine = EM_PPC;
|
||||
return;
|
||||
}
|
||||
if (Emul == "elf64ppc") {
|
||||
Config->ElfKind = ELF64BEKind;
|
||||
Config->EMachine = EM_PPC64;
|
||||
return;
|
||||
}
|
||||
error(Twine("Unknown emulation: ") + Emul);
|
||||
}
|
||||
|
||||
// Makes a path by concatenating Dir and File.
|
||||
// If Dir starts with '=' the result will be preceded by Sysroot,
|
||||
// which can be set with --sysroot command line switch.
|
||||
@ -67,6 +92,28 @@ static std::string searchLibrary(StringRef Path) {
|
||||
error(Twine("Unable to find library -l") + Path);
|
||||
}
|
||||
|
||||
template <template <class> class T>
|
||||
std::unique_ptr<ELFFileBase>
|
||||
LinkerDriver::createELFInputFile(MemoryBufferRef MB) {
|
||||
std::unique_ptr<ELFFileBase> File = createELFFile<T>(MB);
|
||||
const ELFKind ElfKind = File->getELFKind();
|
||||
const uint16_t EMachine = File->getEMachine();
|
||||
|
||||
// Grab target from the first input file if wasn't set by -m option.
|
||||
if (Config->ElfKind == ELFNoneKind) {
|
||||
Config->ElfKind = ElfKind;
|
||||
Config->EMachine = EMachine;
|
||||
return File;
|
||||
}
|
||||
if (ElfKind == Config->ElfKind && EMachine == Config->EMachine)
|
||||
return File;
|
||||
|
||||
if (const ELFFileBase *First = Symtab.getFirstELF())
|
||||
error(MB.getBufferIdentifier() + " is incompatible with " +
|
||||
First->getName());
|
||||
error(MB.getBufferIdentifier() + " is incompatible with target architecture");
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -85,10 +132,10 @@ void LinkerDriver::addFile(StringRef Path) {
|
||||
Symtab.addFile(make_unique<ArchiveFile>(MBRef));
|
||||
return;
|
||||
case file_magic::elf_shared_object:
|
||||
Symtab.addFile(createELFFile<SharedFile>(MBRef));
|
||||
Symtab.addFile(createELFInputFile<SharedFile>(MBRef));
|
||||
return;
|
||||
default:
|
||||
Symtab.addFile(createELFFile<ObjectFile>(MBRef));
|
||||
Symtab.addFile(createELFInputFile<ObjectFile>(MBRef));
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +173,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
if (auto *Arg = Args.getLastArg(OPT_soname))
|
||||
Config->SoName = Arg->getValue();
|
||||
|
||||
if (auto *Arg = Args.getLastArg(OPT_m))
|
||||
setELFType(Arg->getValue());
|
||||
|
||||
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
|
||||
Config->DiscardAll = Args.hasArg(OPT_discard_all);
|
||||
Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
|
||||
@ -185,5 +235,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
case ELF64BEKind:
|
||||
writeResult<object::ELF64BE>(&Symtab);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("Invalid kind");
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ public:
|
||||
void addFile(StringRef Path);
|
||||
|
||||
private:
|
||||
template <template <class> class T>
|
||||
std::unique_ptr<ELFFileBase> createELFInputFile(MemoryBufferRef MB);
|
||||
|
||||
SymbolTable Symtab;
|
||||
ArgParser Parser;
|
||||
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
|
||||
|
@ -38,13 +38,9 @@ uint16_t ELFFileBase::getEMachine() const {
|
||||
return ::getEMachine<ELF64BE>(*this);
|
||||
case ELF64LEKind:
|
||||
return ::getEMachine<ELF64LE>(*this);
|
||||
default:
|
||||
llvm_unreachable("Invalid kind");
|
||||
}
|
||||
llvm_unreachable("Invalid kind");
|
||||
}
|
||||
|
||||
bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const {
|
||||
return getELFKind() == Other.getELFKind() &&
|
||||
getEMachine() == Other.getEMachine();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLD_ELF_INPUT_FILES_H
|
||||
#define LLD_ELF_INPUT_FILES_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "InputSection.h"
|
||||
#include "Error.h"
|
||||
#include "Symbols.h"
|
||||
@ -49,8 +50,6 @@ private:
|
||||
const Kind FileKind;
|
||||
};
|
||||
|
||||
enum ELFKind { ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind };
|
||||
|
||||
class ELFFileBase : public InputFile {
|
||||
public:
|
||||
ELFFileBase(Kind K, ELFKind EKind, MemoryBufferRef M)
|
||||
@ -60,7 +59,6 @@ public:
|
||||
return K == ObjectKind || K == SharedKind;
|
||||
}
|
||||
|
||||
bool isCompatibleWith(const ELFFileBase &Other) const;
|
||||
ELFKind getELFKind() const { return EKind; }
|
||||
|
||||
uint16_t getEMachine() const;
|
||||
|
@ -47,6 +47,9 @@ def init : Separate<["-"], "init">, MetaVarName<"<symbol>">,
|
||||
def l : Joined<["-"], "l">, MetaVarName<"<libName>">,
|
||||
HelpText<"Root name of library to use">;
|
||||
|
||||
def m : Separate<["-"], "m">,
|
||||
HelpText<"Set target emulation">;
|
||||
|
||||
def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">;
|
||||
|
||||
def no_whole_archive : Flag<["--"], "no-whole-archive">,
|
||||
@ -105,7 +108,6 @@ def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
|
||||
def end_group : Flag<["--"], "end-group">;
|
||||
def gc_sections : Flag<["--"], "gc-sections">;
|
||||
def hash_style : Joined<["--"], "hash-style=">;
|
||||
def m : Separate<["-"], "m">;
|
||||
def no_add_needed : Flag<["--"], "no-add-needed">;
|
||||
def no_as_needed : Flag<["--"], "no-as-needed">;
|
||||
def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;
|
||||
|
@ -84,6 +84,8 @@ void SymbolTable::addUndefinedSym(StringRef Name) {
|
||||
case ELF64BEKind:
|
||||
addUndefinedSym<ELF64BE>(Name);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Invalid kind");
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,9 +140,6 @@ template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
|
||||
|
||||
template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
|
||||
const ELFFileBase *Old = getFirstELF();
|
||||
if (Old && !Old->isCompatibleWith(*File))
|
||||
error(Twine(Old->getName() + " is incompatible with " + File->getName()));
|
||||
|
||||
if (auto *O = dyn_cast<ObjectFileBase>(File))
|
||||
ObjectFiles.emplace_back(O);
|
||||
else if (auto *S = dyn_cast<SharedFile<ELFT>>(File))
|
||||
@ -174,6 +173,8 @@ void SymbolTable::addELFFile(ELFFileBase *File) {
|
||||
case ELF64BEKind:
|
||||
addELFFile<ELF64BE>(File);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Invalid kind");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,3 +205,6 @@ _start:
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: not lld -flavor gnu2 %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s
|
||||
# DUP: duplicate symbol: _start in {{.*}} and {{.*}}
|
||||
|
||||
# RUN: not lld -flavor gnu2 %t -o %t -m wrong_emul 2>&1 | FileCheck --check-prefix=UNKNOWN_EMUL %s
|
||||
# UNKNOWN_EMUL: Unknown emulation: wrong_emul
|
||||
|
128
lld/test/elf2/emulation.s
Normal file
128
lld/test/elf2/emulation.s
Normal file
@ -0,0 +1,128 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64
|
||||
# RUN: lld -flavor gnu2 -m elf_x86_64 %tx64 -o %t2x64
|
||||
# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
|
||||
# RUN: lld -flavor gnu2 %tx64 -o %t3x64
|
||||
# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
|
||||
# X86-64: ElfHeader {
|
||||
# X86-64-NEXT: Ident {
|
||||
# X86-64-NEXT: Magic: (7F 45 4C 46)
|
||||
# X86-64-NEXT: Class: 64-bit (0x2)
|
||||
# X86-64-NEXT: DataEncoding: LittleEndian (0x1)
|
||||
# X86-64-NEXT: FileVersion: 1
|
||||
# X86-64-NEXT: OS/ABI: SystemV (0x0)
|
||||
# X86-64-NEXT: ABIVersion: 0
|
||||
# X86-64-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# X86-64-NEXT: }
|
||||
# X86-64-NEXT: Type: Executable (0x2)
|
||||
# X86-64-NEXT: Machine: EM_X86_64 (0x3E)
|
||||
# X86-64-NEXT: Version: 1
|
||||
# X86-64-NEXT: Entry: 0x11000
|
||||
# X86-64-NEXT: ProgramHeaderOffset: 0x40
|
||||
# X86-64-NEXT: SectionHeaderOffset: 0x1060
|
||||
# X86-64-NEXT: Flags [ (0x0)
|
||||
# X86-64-NEXT: ]
|
||||
# X86-64-NEXT: HeaderSize: 64
|
||||
# X86-64-NEXT: ProgramHeaderEntrySize: 56
|
||||
# X86-64-NEXT: ProgramHeaderCount: 1
|
||||
# X86-64-NEXT: SectionHeaderEntrySize: 64
|
||||
# X86-64-NEXT: SectionHeaderCount: 6
|
||||
# X86-64-NEXT: StringTableSectionIndex: 5
|
||||
# X86-64-NEXT: }
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86
|
||||
# RUN: lld -flavor gnu2 -m elf_i386 %tx86 -o %t2x86
|
||||
# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
|
||||
# RUN: lld -flavor gnu2 %tx86 -o %t3x86
|
||||
# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
|
||||
# X86: ElfHeader {
|
||||
# X86-NEXT: Ident {
|
||||
# X86-NEXT: Magic: (7F 45 4C 46)
|
||||
# X86-NEXT: Class: 32-bit (0x1)
|
||||
# X86-NEXT: DataEncoding: LittleEndian (0x1)
|
||||
# X86-NEXT: FileVersion: 1
|
||||
# X86-NEXT: OS/ABI: SystemV (0x0)
|
||||
# X86-NEXT: ABIVersion: 0
|
||||
# X86-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# X86-NEXT: }
|
||||
# X86-NEXT: Type: Executable (0x2)
|
||||
# X86-NEXT: Machine: EM_386 (0x3)
|
||||
# X86-NEXT: Version: 1
|
||||
# X86-NEXT: Entry: 0x11000
|
||||
# X86-NEXT: ProgramHeaderOffset: 0x34
|
||||
# X86-NEXT: SectionHeaderOffset: 0x104C
|
||||
# X86-NEXT: Flags [ (0x0)
|
||||
# X86-NEXT: ]
|
||||
# X86-NEXT: HeaderSize: 52
|
||||
# X86-NEXT: ProgramHeaderEntrySize: 32
|
||||
# X86-NEXT: ProgramHeaderCount: 1
|
||||
# X86-NEXT: SectionHeaderEntrySize: 40
|
||||
# X86-NEXT: SectionHeaderCount: 6
|
||||
# X86-NEXT: StringTableSectionIndex: 5
|
||||
# X86-NEXT: }
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64
|
||||
# RUN: lld -flavor gnu2 -m elf64ppc %tppc64 -o %t2ppc64
|
||||
# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s
|
||||
# RUN: lld -flavor gnu2 %tppc64 -o %t3ppc64
|
||||
# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s
|
||||
# PPC64: ElfHeader {
|
||||
# PPC64-NEXT: Ident {
|
||||
# PPC64-NEXT: Magic: (7F 45 4C 46)
|
||||
# PPC64-NEXT: Class: 64-bit (0x2)
|
||||
# PPC64-NEXT: DataEncoding: BigEndian (0x2)
|
||||
# PPC64-NEXT: FileVersion: 1
|
||||
# PPC64-NEXT: OS/ABI: SystemV (0x0)
|
||||
# PPC64-NEXT: ABIVersion: 0
|
||||
# PPC64-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# PPC64-NEXT: }
|
||||
# PPC64-NEXT: Type: Executable (0x2)
|
||||
# PPC64-NEXT: Machine: EM_PPC64 (0x15)
|
||||
# PPC64-NEXT: Version: 1
|
||||
# PPC64-NEXT: Entry: 0x11000
|
||||
# PPC64-NEXT: ProgramHeaderOffset: 0x40
|
||||
# PPC64-NEXT: SectionHeaderOffset: 0x1060
|
||||
# PPC64-NEXT: Flags [ (0x0)
|
||||
# PPC64-NEXT: ]
|
||||
# PPC64-NEXT: HeaderSize: 64
|
||||
# PPC64-NEXT: ProgramHeaderEntrySize: 56
|
||||
# PPC64-NEXT: ProgramHeaderCount: 1
|
||||
# PPC64-NEXT: SectionHeaderEntrySize: 64
|
||||
# PPC64-NEXT: SectionHeaderCount: 6
|
||||
# PPC64-NEXT: StringTableSectionIndex: 5
|
||||
# PPC64-NEXT: }
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-linux %s -o %tppc
|
||||
# RUN: lld -flavor gnu2 -m elf32ppc %tppc -o %t2ppc
|
||||
# RUN: llvm-readobj -file-headers %t2ppc | FileCheck --check-prefix=PPC %s
|
||||
# RUN: lld -flavor gnu2 %tppc -o %t3ppc
|
||||
# RUN: llvm-readobj -file-headers %t3ppc | FileCheck --check-prefix=PPC %s
|
||||
# PPC: ElfHeader {
|
||||
# PPC-NEXT: Ident {
|
||||
# PPC-NEXT: Magic: (7F 45 4C 46)
|
||||
# PPC-NEXT: Class: 32-bit (0x1)
|
||||
# PPC-NEXT: DataEncoding: BigEndian (0x2)
|
||||
# PPC-NEXT: FileVersion: 1
|
||||
# PPC-NEXT: OS/ABI: SystemV (0x0)
|
||||
# PPC-NEXT: ABIVersion: 0
|
||||
# PPC-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# PPC-NEXT: }
|
||||
# PPC-NEXT: Type: Executable (0x2)
|
||||
# PPC-NEXT: Machine: EM_PPC (0x14)
|
||||
# PPC-NEXT: Version: 1
|
||||
# PPC-NEXT: Entry: 0x11000
|
||||
# PPC-NEXT: ProgramHeaderOffset: 0x34
|
||||
# PPC-NEXT: SectionHeaderOffset: 0x104C
|
||||
# PPC-NEXT: Flags [ (0x0)
|
||||
# PPC-NEXT: ]
|
||||
# PPC-NEXT: HeaderSize: 52
|
||||
# PPC-NEXT: ProgramHeaderEntrySize: 32
|
||||
# PPC-NEXT: ProgramHeaderCount: 1
|
||||
# PPC-NEXT: SectionHeaderEntrySize: 40
|
||||
# PPC-NEXT: SectionHeaderCount: 6
|
||||
# PPC-NEXT: StringTableSectionIndex: 5
|
||||
# PPC-NEXT: }
|
||||
|
||||
# REQUIRES: x86,ppc
|
||||
|
||||
.globl _start;
|
||||
_start:
|
@ -5,22 +5,42 @@
|
||||
|
||||
// RUN: not lld -flavor gnu2 %ta.o %tb.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=A-AND-B %s
|
||||
// A-AND-B: a.o is incompatible with {{.*}}b.o
|
||||
// A-AND-B: b.o is incompatible with {{.*}}a.o
|
||||
|
||||
// RUN: not lld -flavor gnu2 %tb.o %tc.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=B-AND-C %s
|
||||
// B-AND-C: b.o is incompatible with {{.*}}c.o
|
||||
// B-AND-C: c.o is incompatible with {{.*}}b.o
|
||||
|
||||
// RUN: not lld -flavor gnu2 %ta.o %ti686.so -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=A-AND-SO %s
|
||||
// A-AND-SO: a.o is incompatible with {{.*}}i686.so
|
||||
// A-AND-SO: i686.so is incompatible with {{.*}}a.o
|
||||
|
||||
// RUN: not lld -flavor gnu2 %tc.o %ti686.so -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=C-AND-SO %s
|
||||
// C-AND-SO: c.o is incompatible with {{.*}}i686.so
|
||||
// C-AND-SO: i686.so is incompatible with {{.*}}c.o
|
||||
|
||||
// RUN: not lld -flavor gnu2 %ti686.so %tc.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=SO-AND-C %s
|
||||
// SO-AND-C: i686.so is incompatible with {{.*}}c.o
|
||||
// SO-AND-C: c.o is incompatible with {{.*}}i686.so
|
||||
|
||||
// RUN: not lld -flavor gnu2 -m elf64ppc %ta.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=A-ONLY %s
|
||||
// A-ONLY: a.o is incompatible with target architecture
|
||||
|
||||
// RUN: not lld -flavor gnu2 -m elf64ppc %tb.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=B-ONLY %s
|
||||
// B-ONLY: b.o is incompatible with target architecture
|
||||
|
||||
// RUN: not lld -flavor gnu2 -m elf64ppc %tc.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=C-ONLY %s
|
||||
// C-ONLY: c.o is incompatible with target architecture
|
||||
|
||||
// RUN: not lld -flavor gnu2 -m elf_i386 %tc.o %ti686.so -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=C-AND-SO-I386 %s
|
||||
// C-AND-SO-I386: c.o is incompatible with target architecture
|
||||
|
||||
// RUN: not lld -flavor gnu2 -m elf_i386 %ti686.so %tc.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=SO-AND-C-I386 %s
|
||||
// SO-AND-C-I386: c.o is incompatible with {{.*}}i686.so
|
||||
|
||||
// REQUIRES: x86,arm
|
||||
|
Loading…
x
Reference in New Issue
Block a user