forked from OSchip/llvm-project
Read .note.gnu.property sections and emit a merged .note.gnu.property section.
This patch also adds `--require-cet` option for the sake of testing. The actual feature for IBT-aware PLT is not included in this patch. This is a part of https://reviews.llvm.org/D59780. Submitting this first should make it easy to work with a related change (https://reviews.llvm.org/D62609). Differential Revision: https://reviews.llvm.org/D62853 llvm-svn: 362579
This commit is contained in:
parent
aade782a98
commit
2057f8366a
|
@ -82,6 +82,7 @@ struct VersionDefinition {
|
||||||
// Most fields are initialized by the driver.
|
// Most fields are initialized by the driver.
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
uint8_t OSABI = 0;
|
uint8_t OSABI = 0;
|
||||||
|
uint32_t AndFeatures = 0;
|
||||||
llvm::CachePruningPolicy ThinLTOCachePolicy;
|
llvm::CachePruningPolicy ThinLTOCachePolicy;
|
||||||
llvm::StringMap<uint64_t> SectionStartMap;
|
llvm::StringMap<uint64_t> SectionStartMap;
|
||||||
llvm::StringRef Chroot;
|
llvm::StringRef Chroot;
|
||||||
|
@ -147,6 +148,7 @@ struct Configuration {
|
||||||
bool ExportDynamic;
|
bool ExportDynamic;
|
||||||
bool FixCortexA53Errata843419;
|
bool FixCortexA53Errata843419;
|
||||||
bool FormatBinary = false;
|
bool FormatBinary = false;
|
||||||
|
bool RequireCET;
|
||||||
bool GcSections;
|
bool GcSections;
|
||||||
bool GdbIndex;
|
bool GdbIndex;
|
||||||
bool GnuHash = false;
|
bool GnuHash = false;
|
||||||
|
|
|
@ -334,6 +334,9 @@ static void checkOptions() {
|
||||||
if (Config->SingleRoRx && !Script->HasSectionsCommand)
|
if (Config->SingleRoRx && !Script->HasSectionsCommand)
|
||||||
error("-execute-only and -no-rosegment cannot be used together");
|
error("-execute-only and -no-rosegment cannot be used together");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Config->ZRetpolineplt && Config->RequireCET)
|
||||||
|
error("--require-cet may not be used with -z retpolineplt");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *getReproduceOption(opt::InputArgList &Args) {
|
static const char *getReproduceOption(opt::InputArgList &Args) {
|
||||||
|
@ -813,6 +816,7 @@ static void readConfigs(opt::InputArgList &Args) {
|
||||||
Config->FilterList = args::getStrings(Args, OPT_filter);
|
Config->FilterList = args::getStrings(Args, OPT_filter);
|
||||||
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
|
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
|
||||||
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
|
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
|
||||||
|
Config->RequireCET = Args.hasArg(OPT_require_cet);
|
||||||
Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
|
Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
|
||||||
Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
|
Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
|
||||||
Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
|
Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
|
||||||
|
@ -1584,6 +1588,30 @@ static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
|
||||||
Symtab->wrap(W.Sym, W.Real, W.Wrap);
|
Symtab->wrap(W.Sym, W.Real, W.Wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To enable CET (x86's hardware-assited control flow enforcement), each
|
||||||
|
// source file must be compiled with -fcf-protection. Object files compiled
|
||||||
|
// with the flag contain feature flags indicating that they are compatible
|
||||||
|
// with CET. We enable the feature only when all object files are compatible
|
||||||
|
// with CET.
|
||||||
|
//
|
||||||
|
// This function returns the merged feature flags. If 0, we cannot enable CET.
|
||||||
|
//
|
||||||
|
// Note that the CET-aware PLT is not implemented yet. We do error
|
||||||
|
// check only.
|
||||||
|
template <class ELFT> static uint32_t getAndFeatures() {
|
||||||
|
if (Config->EMachine != EM_386 && Config->EMachine != EM_X86_64)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t Ret = -1;
|
||||||
|
for (InputFile *F : ObjectFiles) {
|
||||||
|
uint32_t Features = cast<ObjFile<ELFT>>(F)->AndFeatures;
|
||||||
|
if (!Features && Config->RequireCET)
|
||||||
|
error(toString(F) + ": --require-cet: file is not compatible with CET");
|
||||||
|
Ret &= Features;
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *LibcallRoutineNames[] = {
|
static const char *LibcallRoutineNames[] = {
|
||||||
#define HANDLE_LIBCALL(code, name) name,
|
#define HANDLE_LIBCALL(code, name) name,
|
||||||
#include "llvm/IR/RuntimeLibcalls.def"
|
#include "llvm/IR/RuntimeLibcalls.def"
|
||||||
|
@ -1762,6 +1790,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
|
||||||
(S->Name.startswith(".debug") || S->Name.startswith(".zdebug"));
|
(S->Name.startswith(".debug") || S->Name.startswith(".zdebug"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Read .note.gnu.property sections from input object files which
|
||||||
|
// contain a hint to tweak linker's and loader's behaviors.
|
||||||
|
Config->AndFeatures = getAndFeatures<ELFT>();
|
||||||
|
|
||||||
Config->EFlags = Target->calcEFlags();
|
Config->EFlags = Target->calcEFlags();
|
||||||
// MaxPageSize (sometimes called abi page size) is the maximum page size that
|
// MaxPageSize (sometimes called abi page size) is the maximum page size that
|
||||||
// the output can be run on. For example if the OS can use 4k or 64k page
|
// the output can be run on. For example if the OS can use 4k or 64k page
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "llvm/Object/ELFObjectFile.h"
|
#include "llvm/Object/ELFObjectFile.h"
|
||||||
#include "llvm/Support/ARMAttributeParser.h"
|
#include "llvm/Support/ARMAttributeParser.h"
|
||||||
#include "llvm/Support/ARMBuildAttributes.h"
|
#include "llvm/Support/ARMBuildAttributes.h"
|
||||||
|
#include "llvm/Support/Endian.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
#include "llvm/Support/TarWriter.h"
|
#include "llvm/Support/TarWriter.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
@ -34,6 +35,7 @@ using namespace llvm::ELF;
|
||||||
using namespace llvm::object;
|
using namespace llvm::object;
|
||||||
using namespace llvm::sys;
|
using namespace llvm::sys;
|
||||||
using namespace llvm::sys::fs;
|
using namespace llvm::sys::fs;
|
||||||
|
using namespace llvm::support::endian;
|
||||||
|
|
||||||
using namespace lld;
|
using namespace lld;
|
||||||
using namespace lld::elf;
|
using namespace lld::elf;
|
||||||
|
@ -753,6 +755,68 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a source file is compiled with x86 hardware-assisted call flow control
|
||||||
|
// enabled, the generated object file contains feature flags indicating that
|
||||||
|
// fact. This function reads the feature flags and returns it.
|
||||||
|
//
|
||||||
|
// Essentially we want to read a single 32-bit value in this function, but this
|
||||||
|
// function is rather complicated because the value is buried deep inside a
|
||||||
|
// .note.gnu.property section.
|
||||||
|
//
|
||||||
|
// The section consists of one or more NOTE records. Each NOTE record consists
|
||||||
|
// of zero or more type-length-value fields. We want to find a field of a
|
||||||
|
// certain type. It seems a bit too much to just store a 32-bit value, perhaps
|
||||||
|
// the ABI is unnecessarily complicated.
|
||||||
|
template <class ELFT>
|
||||||
|
static uint32_t readAndFeatures(ObjFile<ELFT> *Obj, ArrayRef<uint8_t> Data) {
|
||||||
|
using Elf_Nhdr = typename ELFT::Nhdr;
|
||||||
|
using Elf_Note = typename ELFT::Note;
|
||||||
|
|
||||||
|
while (!Data.empty()) {
|
||||||
|
// Read one NOTE record.
|
||||||
|
if (Data.size() < sizeof(Elf_Nhdr))
|
||||||
|
fatal(toString(Obj) + ": .note.gnu.property: section too short");
|
||||||
|
|
||||||
|
auto *Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data());
|
||||||
|
if (Data.size() < Nhdr->getSize())
|
||||||
|
fatal(toString(Obj) + ": .note.gnu.property: section too short");
|
||||||
|
|
||||||
|
Elf_Note Note(*Nhdr);
|
||||||
|
if (Nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || Note.getName() != "GNU") {
|
||||||
|
Data = Data.slice(Nhdr->getSize());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a body of a NOTE record, which consists of type-length-value fields.
|
||||||
|
ArrayRef<uint8_t> Desc = Note.getDesc();
|
||||||
|
while (!Desc.empty()) {
|
||||||
|
if (Desc.size() < 8)
|
||||||
|
fatal(toString(Obj) + ": .note.gnu.property: section too short");
|
||||||
|
|
||||||
|
uint32_t Type = read32le(Desc.data());
|
||||||
|
uint32_t Size = read32le(Desc.data() + 4);
|
||||||
|
|
||||||
|
if (Type == GNU_PROPERTY_X86_FEATURE_1_AND) {
|
||||||
|
// We found the field.
|
||||||
|
return read32le(Desc.data() + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On 64-bit, a payload may be followed by a 4-byte padding to make its
|
||||||
|
// size a multiple of 8.
|
||||||
|
if (ELFT::Is64Bits)
|
||||||
|
Size = alignTo(Size, 8);
|
||||||
|
|
||||||
|
Desc = Desc.slice(Size + 8); // +8 for Type and Size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to next NOTE record if a note section didn't contain
|
||||||
|
// X86_FEATURES_1_AND description.
|
||||||
|
Data = Data.slice(Nhdr->getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
|
InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
|
||||||
uint32_t Idx = Sec.sh_info;
|
uint32_t Idx = Sec.sh_info;
|
||||||
|
@ -901,6 +965,19 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||||
if (Name == ".note.GNU-stack")
|
if (Name == ".note.GNU-stack")
|
||||||
return &InputSection::Discarded;
|
return &InputSection::Discarded;
|
||||||
|
|
||||||
|
// If an object file is compatible with Intel Control-Flow Enforcement
|
||||||
|
// Technology (CET), it has a .note.gnu.property section containing the
|
||||||
|
// GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
|
||||||
|
//
|
||||||
|
// Since we merge bitmaps from multiple object files to create a new
|
||||||
|
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
|
||||||
|
// file's .note.gnu.property section.
|
||||||
|
if (Name == ".note.gnu.property") {
|
||||||
|
ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec));
|
||||||
|
this->AndFeatures = readAndFeatures(this, Contents);
|
||||||
|
return &InputSection::Discarded;
|
||||||
|
}
|
||||||
|
|
||||||
// Split stacks is a feature to support a discontiguous stack,
|
// Split stacks is a feature to support a discontiguous stack,
|
||||||
// commonly used in the programming language Go. For the details,
|
// commonly used in the programming language Go. For the details,
|
||||||
// see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
|
// see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
|
||||||
|
|
|
@ -228,6 +228,8 @@ public:
|
||||||
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
|
||||||
uint32_t MipsGp0 = 0;
|
uint32_t MipsGp0 = 0;
|
||||||
|
|
||||||
|
uint32_t AndFeatures = 0;
|
||||||
|
|
||||||
// Name of source file obtained from STT_FILE symbol value,
|
// Name of source file obtained from STT_FILE symbol value,
|
||||||
// or empty string if there is no such symbol in object file
|
// or empty string if there is no such symbol in object file
|
||||||
// symbol table.
|
// symbol table.
|
||||||
|
|
|
@ -171,6 +171,10 @@ defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
|
||||||
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
|
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
|
||||||
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
|
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
|
||||||
|
|
||||||
|
// This option is intentionally hidden from the user as the implementation
|
||||||
|
// is not complete.
|
||||||
|
def require_cet: F<"require-cet">;
|
||||||
|
|
||||||
defm format: Eq<"format", "Change the input format of the inputs following this option">,
|
defm format: Eq<"format", "Change the input format of the inputs following this option">,
|
||||||
MetaVarName<"[default,elf,binary]">;
|
MetaVarName<"[default,elf,binary]">;
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,35 @@ static size_t getHashSize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This class represents a linker-synthesized .note.gnu.property section.
|
||||||
|
//
|
||||||
|
// In x86, object files may contain feature flags indicating the features that
|
||||||
|
// they are using. The flags are stored in a .note.gnu.property section.
|
||||||
|
//
|
||||||
|
// lld reads the sections from input files and merges them by computing AND of
|
||||||
|
// the flags. The result is written as a new .note.gnu.property section.
|
||||||
|
//
|
||||||
|
// If the flag is zero (which indicates that the intersection of the feature
|
||||||
|
// sets is empty, or some input files didn't have .note.gnu.property sections),
|
||||||
|
// we don't create this section.
|
||||||
|
GnuPropertySection::GnuPropertySection()
|
||||||
|
: SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE, 4,
|
||||||
|
".note.gnu.property") {}
|
||||||
|
|
||||||
|
void GnuPropertySection::writeTo(uint8_t *Buf) {
|
||||||
|
write32(Buf, 4); // Name size
|
||||||
|
write32(Buf + 4, Config->Is64 ? 16 : 12); // Content size
|
||||||
|
write32(Buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
|
||||||
|
memcpy(Buf + 12, "GNU", 4); // Name string
|
||||||
|
write32(Buf + 16, GNU_PROPERTY_X86_FEATURE_1_AND); // Feature type
|
||||||
|
write32(Buf + 20, 4); // Feature size
|
||||||
|
write32(Buf + 24, Config->AndFeatures); // Feature flags
|
||||||
|
if (Config->Is64)
|
||||||
|
write32(Buf + 28, 0); // Padding
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GnuPropertySection::getSize() const { return Config->Is64 ? 32 : 28; }
|
||||||
|
|
||||||
BuildIdSection::BuildIdSection()
|
BuildIdSection::BuildIdSection()
|
||||||
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
|
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
|
||||||
HashSize(getHashSize()) {}
|
HashSize(getHashSize()) {}
|
||||||
|
|
|
@ -147,6 +147,13 @@ public:
|
||||||
size_t getSize() const override { return 0; }
|
size_t getSize() const override { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GnuPropertySection : public SyntheticSection {
|
||||||
|
public:
|
||||||
|
GnuPropertySection();
|
||||||
|
void writeTo(uint8_t *Buf) override;
|
||||||
|
size_t getSize() const override;
|
||||||
|
};
|
||||||
|
|
||||||
// .note.gnu.build-id section.
|
// .note.gnu.build-id section.
|
||||||
class BuildIdSection : public SyntheticSection {
|
class BuildIdSection : public SyntheticSection {
|
||||||
// First 16 bytes are a header.
|
// First 16 bytes are a header.
|
||||||
|
|
|
@ -433,6 +433,9 @@ template <class ELFT> static void createSyntheticSections() {
|
||||||
In.Iplt = make<PltSection>(true);
|
In.Iplt = make<PltSection>(true);
|
||||||
Add(In.Iplt);
|
Add(In.Iplt);
|
||||||
|
|
||||||
|
if (Config->AndFeatures)
|
||||||
|
Add(make<GnuPropertySection>());
|
||||||
|
|
||||||
// .note.GNU-stack is always added when we are creating a re-linkable
|
// .note.GNU-stack is always added when we are creating a re-linkable
|
||||||
// object file. Other linkers are using the presence of this marker
|
// object file. Other linkers are using the presence of this marker
|
||||||
// section to control the executable-ness of the stack area, but that
|
// section to control the executable-ness of the stack area, but that
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 12
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,20 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 24
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000000
|
||||||
|
.long 4
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,5 @@
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,16 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 12
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 0xfffffffd
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,17 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 16
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,22 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 32
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000000
|
||||||
|
.long 4
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,5 @@
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,17 @@
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 16
|
||||||
|
.long 5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 0xfffffffd
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func2
|
||||||
|
.type func2,@function
|
||||||
|
func2:
|
||||||
|
ret
|
|
@ -0,0 +1,48 @@
|
||||||
|
# REQUIRES: x86
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet1.s -o %t1.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet2.s -o %t2.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet3.s -o %t3.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet4.s -o %t4.o
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t1.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t2.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s
|
||||||
|
|
||||||
|
# CET: Properties: x86 feature: IBT, SHSTK
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t3.o -o %t
|
||||||
|
# RUN: llvm-readelf -S %t | FileCheck -check-prefix=NOCET %s
|
||||||
|
|
||||||
|
# NOCET: Section Headers
|
||||||
|
# NOCET-NOT: .note.gnu.property
|
||||||
|
|
||||||
|
# RUN: not ld.lld -e func1 %t.o %t3.o -o %t --require-cet 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefix=ERROR %s
|
||||||
|
# ERROR: i386-cet.s.tmp3.o: --require-cet: file is not compatible with CET
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t4.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=NOSHSTK -match-full-lines %s
|
||||||
|
|
||||||
|
# Check .note.gnu.protery without property SHSTK.
|
||||||
|
# NOSHSTK: Properties: x86 feature: IBT
|
||||||
|
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.long 4
|
||||||
|
.long 0x10
|
||||||
|
.long 0x5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func1
|
||||||
|
.type func1,@function
|
||||||
|
func1:
|
||||||
|
call func2
|
||||||
|
ret
|
|
@ -0,0 +1,48 @@
|
||||||
|
# REQUIRES: x86
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet1.s -o %t1.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet2.s -o %t2.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet3.s -o %t3.o
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet4.s -o %t4.o
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t1.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t2.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s
|
||||||
|
|
||||||
|
# CET: Properties: x86 feature: IBT, SHSTK
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t3.o -o %t
|
||||||
|
# RUN: llvm-readelf -S %t | FileCheck -check-prefix=NOCET %s
|
||||||
|
|
||||||
|
# NOCET: Section Headers
|
||||||
|
# NOCET-NOT: .note.gnu.property
|
||||||
|
|
||||||
|
# RUN: not ld.lld -e func1 %t.o %t3.o -o %t --require-cet 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefix=ERROR %s
|
||||||
|
# ERROR: x86-64-cet.s.tmp3.o: --require-cet: file is not compatible with CET
|
||||||
|
|
||||||
|
# RUN: ld.lld -e func1 %t.o %t4.o -o %t
|
||||||
|
# RUN: llvm-readelf -n %t | FileCheck -check-prefix=NOSHSTK -match-full-lines %s
|
||||||
|
|
||||||
|
# Check .note.gnu.protery without property SHSTK.
|
||||||
|
# NOSHSTK: Properties: x86 feature: IBT
|
||||||
|
|
||||||
|
.section ".note.gnu.property", "a"
|
||||||
|
.long 4
|
||||||
|
.long 0x10
|
||||||
|
.long 0x5
|
||||||
|
.asciz "GNU"
|
||||||
|
|
||||||
|
.long 0xc0000002
|
||||||
|
.long 4
|
||||||
|
.long 3
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl func1
|
||||||
|
.type func1,@function
|
||||||
|
func1:
|
||||||
|
call func2
|
||||||
|
ret
|
|
@ -592,9 +592,9 @@ class Elf_Note_Impl {
|
||||||
|
|
||||||
template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl;
|
template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl;
|
||||||
|
|
||||||
|
public:
|
||||||
Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {}
|
Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {}
|
||||||
|
|
||||||
public:
|
|
||||||
/// Get the note's name, excluding the terminating null byte.
|
/// Get the note's name, excluding the terminating null byte.
|
||||||
StringRef getName() const {
|
StringRef getName() const {
|
||||||
if (!Nhdr.n_namesz)
|
if (!Nhdr.n_namesz)
|
||||||
|
|
Loading…
Reference in New Issue