diff options
| author | Simon Atanasyan <simon@atanasyan.com> | 2014-11-06 05:53:10 +0000 |
|---|---|---|
| committer | Simon Atanasyan <simon@atanasyan.com> | 2014-11-06 05:53:10 +0000 |
| commit | b915d07a8e62839ca745a48fc54d2c7ed793ebcd (patch) | |
| tree | 325a59a03a613970db9f69766b32611b0e8f0d5c /lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp | |
| parent | 4c6bd6a10d06be042837df9004d7a5afc5ebca70 (diff) | |
| download | bcm5719-llvm-b915d07a8e62839ca745a48fc54d2c7ed793ebcd.tar.gz bcm5719-llvm-b915d07a8e62839ca745a48fc54d2c7ed793ebcd.zip | |
[Mips] Check ELF flags to prevent linking of incompatible files
1. The path checks ELF header flags to prevent linking of incompatible files.
For example we do not allow to link files with different ABI, -mnan
flags, some combination of target CPU etc.
2. The patch merge ELF header flags from input object files to put their
combination to the generated file. For example, if some input files
have EF_MIPS_NOREORDER flag we need to put this flag to the output
file header.
I use the `parseFile()` (not `canParse()`) method because in case of
recognition of incorrect input flags combination we should show detailed
error message and stop the linking process and should not try to use
another `Reader`.
llvm-svn: 221439
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp')
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp new file mode 100644 index 00000000000..4db009dd84c --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp @@ -0,0 +1,87 @@ +//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.cpp ------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsELFFlagsMerger.h" +#include "lld/Core/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lld; +using namespace lld::elf; + +MipsELFFlagsMerger::MipsELFFlagsMerger() : _flags(0) {} + +uint32_t MipsELFFlagsMerger::getMergedELFFlags() const { return _flags; } + +std::error_code MipsELFFlagsMerger::merge(uint8_t newClass, uint32_t newFlags) { + // Reject 64-bit binaries. + if (newClass != llvm::ELF::ELFCLASS32) + return make_dynamic_error_code( + Twine("Bitness is incompatible with that of the selected target")); + + // We support the only ABI - O32 ... + uint32_t abi = newFlags & llvm::ELF::EF_MIPS_ABI; + if (abi != llvm::ELF::EF_MIPS_ABI_O32) + return make_dynamic_error_code(Twine("Unsupported ABI")); + + // ... and reduced set of architectures ... + uint32_t newArch = newFlags & llvm::ELF::EF_MIPS_ARCH; + switch (newArch) { + case llvm::ELF::EF_MIPS_ARCH_1: + case llvm::ELF::EF_MIPS_ARCH_2: + case llvm::ELF::EF_MIPS_ARCH_32: + case llvm::ELF::EF_MIPS_ARCH_32R2: + case llvm::ELF::EF_MIPS_ARCH_32R6: + break; + default: + return make_dynamic_error_code(Twine("Unsupported architecture")); + } + + // ... and still do not support MIPS-16 extension. + if (newFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16) + return make_dynamic_error_code(Twine("Unsupported extension: MIPS16")); + + std::lock_guard<std::mutex> lock(_mutex); + + // If the old set of flags is empty, use the new one as a result. + if (!_flags) { + _flags = newFlags; + return std::error_code(); + } + + // Check PIC / CPIC flags compatibility. + uint32_t newPic = + newFlags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC); + uint32_t oldPic = _flags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC); + + if ((newPic != 0) != (oldPic != 0)) + llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n"; + + if (newPic != 0) + _flags |= llvm::ELF::EF_MIPS_CPIC; + if (!(newPic & llvm::ELF::EF_MIPS_PIC)) + _flags &= ~llvm::ELF::EF_MIPS_PIC; + + // Check mixing -mnan=2008 / -mnan=legacy modules. + if ((newFlags & llvm::ELF::EF_MIPS_NAN2008) != + (_flags & llvm::ELF::EF_MIPS_NAN2008)) + return make_dynamic_error_code( + Twine("Linking -mnan=2008 and -mnan=legacy modules")); + + // Set the "largest" ISA. + uint32_t oldArch = _flags & llvm::ELF::EF_MIPS_ARCH; + _flags |= std::max(newArch, oldArch); + + _flags |= newFlags & llvm::ELF::EF_MIPS_NOREORDER; + _flags |= newFlags & llvm::ELF::EF_MIPS_MICROMIPS; + _flags |= newFlags & llvm::ELF::EF_MIPS_NAN2008; + + return std::error_code(); +} |

