mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[MachO] Add MachO alt-entry directive support.
This patch adds support for the MachO .alt_entry assembly directive, and uses it for global aliases with non-zero GEP offsets. The alt_entry flag indicates that a symbol should be layed out immediately after the preceding symbol. Conceptually it introduces an alternate entry point for a function or data structure. E.g.: safe_foo: // check preconditions for foo .alt_entry fast_foo fast_foo: // body of foo, can assume preconditions. The .alt_entry flag is also implicitly set on assembly aliases of the form: a = b + C where C is a non-zero constant, since these have the same effect as an alt_entry symbol: they introduce a label that cannot be moved relative to the preceding one. Setting the alt_entry flag on aliases of this form fixes http://llvm.org/PR25381. llvm-svn: 263521
This commit is contained in:
parent
b66ed58c06
commit
e025323d29
@ -280,6 +280,10 @@ protected:
|
||||
/// to false.
|
||||
bool HasNoDeadStrip;
|
||||
|
||||
/// True if this target supports the MachO .alt_entry directive. Defaults to
|
||||
/// false.
|
||||
bool HasAltEntry;
|
||||
|
||||
/// Used to declare a global as being a weak symbol. Defaults to ".weak".
|
||||
const char *WeakDirective;
|
||||
|
||||
@ -498,6 +502,7 @@ public:
|
||||
bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; }
|
||||
bool hasIdentDirective() const { return HasIdentDirective; }
|
||||
bool hasNoDeadStrip() const { return HasNoDeadStrip; }
|
||||
bool hasAltEntry() const { return HasAltEntry; }
|
||||
const char *getWeakDirective() const { return WeakDirective; }
|
||||
const char *getWeakRefDirective() const { return WeakRefDirective; }
|
||||
bool hasWeakDefDirective() const { return HasWeakDefDirective; }
|
||||
|
@ -35,6 +35,7 @@ enum MCSymbolAttr {
|
||||
MCSA_Local, ///< .local (ELF)
|
||||
MCSA_NoDeadStrip, ///< .no_dead_strip (MachO)
|
||||
MCSA_SymbolResolver, ///< .symbol_resolver (MachO)
|
||||
MCSA_AltEntry, ///< .alt_entry (MachO)
|
||||
MCSA_PrivateExtern, ///< .private_extern (MachO)
|
||||
MCSA_Protected, ///< .protected (ELF)
|
||||
MCSA_Reference, ///< .reference (MachO)
|
||||
|
@ -33,6 +33,7 @@ class MCSymbolMachO : public MCSymbol {
|
||||
SF_WeakReference = 0x0040,
|
||||
SF_WeakDefinition = 0x0080,
|
||||
SF_SymbolResolver = 0x0100,
|
||||
SF_AltEntry = 0x0200,
|
||||
|
||||
// Common alignment
|
||||
SF_CommonAlignmentMask = 0xF0FF,
|
||||
@ -88,6 +89,14 @@ public:
|
||||
modifyFlags(SF_SymbolResolver, SF_SymbolResolver);
|
||||
}
|
||||
|
||||
void setAltEntry() const {
|
||||
modifyFlags(SF_AltEntry, SF_AltEntry);
|
||||
}
|
||||
|
||||
bool isAltEntry() const {
|
||||
return getFlags() & SF_AltEntry;
|
||||
}
|
||||
|
||||
void setDesc(unsigned Value) const {
|
||||
assert(Value == (Value & SF_DescFlagsMask) &&
|
||||
"Invalid .desc value!");
|
||||
@ -96,7 +105,7 @@ public:
|
||||
|
||||
/// \brief Get the encoded value of the flags as they will be emitted in to
|
||||
/// the MachO binary
|
||||
uint16_t getEncodedFlags() const {
|
||||
uint16_t getEncodedFlags(bool EncodeAsAltEntry) const {
|
||||
uint16_t Flags = getFlags();
|
||||
|
||||
// Common alignment is packed into the 'desc' bits.
|
||||
@ -113,6 +122,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (EncodeAsAltEntry)
|
||||
Flags |= SF_AltEntry;
|
||||
|
||||
return Flags;
|
||||
}
|
||||
|
||||
|
@ -1165,8 +1165,13 @@ bool AsmPrinter::doFinalization(Module &M) {
|
||||
|
||||
EmitVisibility(Name, Alias.getVisibility());
|
||||
|
||||
const MCExpr *Expr = lowerConstant(Alias.getAliasee());
|
||||
|
||||
if (MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr))
|
||||
OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry);
|
||||
|
||||
// Emit the directives as assignments aka .set:
|
||||
OutStreamer->EmitAssignment(Name, lowerConstant(Alias.getAliasee()));
|
||||
OutStreamer->EmitAssignment(Name, Expr);
|
||||
|
||||
// If the aliasee does not correspond to a symbol in the output, i.e. the
|
||||
// alias is not of an object or the aliased object is private, then set the
|
||||
|
@ -75,6 +75,7 @@ MCAsmInfo::MCAsmInfo() {
|
||||
HasSingleParameterDotFile = true;
|
||||
HasIdentDirective = false;
|
||||
HasNoDeadStrip = false;
|
||||
HasAltEntry = false;
|
||||
WeakDirective = "\t.weak\t";
|
||||
WeakRefDirective = nullptr;
|
||||
HasWeakDefDirective = false;
|
||||
|
@ -88,6 +88,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() {
|
||||
|
||||
HasDotTypeDotSizeDirective = false;
|
||||
HasNoDeadStrip = true;
|
||||
HasAltEntry = true;
|
||||
|
||||
DwarfUsesRelocationsAcrossSections = false;
|
||||
|
||||
|
@ -472,6 +472,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
|
||||
OS << "\t.no_dead_strip\t";
|
||||
break;
|
||||
case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;
|
||||
case MCSA_AltEntry: OS << "\t.alt_entry\t"; break;
|
||||
case MCSA_PrivateExtern:
|
||||
OS << "\t.private_extern\t";
|
||||
break;
|
||||
|
@ -283,6 +283,9 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
|
||||
case MCSA_Internal:
|
||||
Symbol->setVisibility(ELF::STV_INTERNAL);
|
||||
break;
|
||||
|
||||
case MCSA_AltEntry:
|
||||
llvm_unreachable("ELF doesn't support this attribute");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "llvm/MC/MCSection.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
#include "llvm/MC/MCSymbolMachO.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
@ -70,6 +71,7 @@ public:
|
||||
|
||||
void ChangeSection(MCSection *Sect, const MCExpr *Subsect) override;
|
||||
void EmitLabel(MCSymbol *Symbol) override;
|
||||
void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
|
||||
void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) override;
|
||||
void EmitAssemblerFlag(MCAssemblerFlag Flag) override;
|
||||
void EmitLinkerOptions(ArrayRef<std::string> Options) override;
|
||||
@ -198,6 +200,16 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
|
||||
cast<MCSymbolMachO>(Symbol)->clearReferenceType();
|
||||
}
|
||||
|
||||
void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
|
||||
MCValue Res;
|
||||
|
||||
if (Value->evaluateAsRelocatable(Res, nullptr, nullptr))
|
||||
if (Res.getSymA() && !Res.getSymB() && Res.getConstant() != 0)
|
||||
cast<MCSymbolMachO>(Symbol)->setAltEntry();
|
||||
|
||||
MCObjectStreamer::EmitAssignment(Symbol, Value);
|
||||
}
|
||||
|
||||
void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) {
|
||||
if (!getAssembler().getBackend().hasDataInCodeSupport())
|
||||
return;
|
||||
@ -346,6 +358,10 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym,
|
||||
Symbol->setSymbolResolver();
|
||||
break;
|
||||
|
||||
case MCSA_AltEntry:
|
||||
Symbol->setAltEntry();
|
||||
break;
|
||||
|
||||
case MCSA_PrivateExtern:
|
||||
Symbol->setExternal(true);
|
||||
Symbol->setPrivateExtern(true);
|
||||
|
@ -350,8 +350,8 @@ private:
|
||||
DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR,
|
||||
DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK,
|
||||
DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL,
|
||||
DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, DK_PRIVATE_EXTERN,
|
||||
DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE,
|
||||
DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, DK_ALT_ENTRY,
|
||||
DK_PRIVATE_EXTERN, DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE,
|
||||
DK_WEAK_DEF_CAN_BE_HIDDEN, DK_COMM, DK_COMMON, DK_LCOMM, DK_ABORT,
|
||||
DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC,
|
||||
DK_IF, DK_IFEQ, DK_IFGE, DK_IFGT, DK_IFLE, DK_IFLT, DK_IFNE, DK_IFB,
|
||||
@ -1598,6 +1598,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
|
||||
return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip);
|
||||
case DK_SYMBOL_RESOLVER:
|
||||
return parseDirectiveSymbolAttribute(MCSA_SymbolResolver);
|
||||
case DK_ALT_ENTRY:
|
||||
return parseDirectiveSymbolAttribute(MCSA_AltEntry);
|
||||
case DK_PRIVATE_EXTERN:
|
||||
return parseDirectiveSymbolAttribute(MCSA_PrivateExtern);
|
||||
case DK_REFERENCE:
|
||||
@ -4625,6 +4627,7 @@ void AsmParser::initializeDirectiveKindMap() {
|
||||
DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE;
|
||||
DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP;
|
||||
DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER;
|
||||
DirectiveKindMap[".alt_entry"] = DK_ALT_ENTRY;
|
||||
DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN;
|
||||
DirectiveKindMap[".reference"] = DK_REFERENCE;
|
||||
DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION;
|
||||
|
@ -334,7 +334,7 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD,
|
||||
if (AliaseeInfo)
|
||||
SectionIndex = AliaseeInfo->SectionIndex;
|
||||
Symbol = AliasedSymbol;
|
||||
// FIXME: Should this update Data as well? Do we need OrigSymbol at all?
|
||||
// FIXME: Should this update Data as well?
|
||||
}
|
||||
|
||||
// Set the N_TYPE bits. See <mach-o/nlist.h>.
|
||||
@ -377,7 +377,9 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD,
|
||||
|
||||
// The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
|
||||
// value.
|
||||
write16(cast<MCSymbolMachO>(Symbol)->getEncodedFlags());
|
||||
bool EncodeAsAltEntry =
|
||||
IsAlias && cast<MCSymbolMachO>(OrigSymbol).isAltEntry();
|
||||
write16(cast<MCSymbolMachO>(Symbol)->getEncodedFlags(EncodeAsAltEntry));
|
||||
if (is64Bit())
|
||||
write64(Address);
|
||||
else
|
||||
|
22
test/CodeGen/X86/alias-gep.ll
Normal file
22
test/CodeGen/X86/alias-gep.ll
Normal file
@ -0,0 +1,22 @@
|
||||
; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=MACHO %s
|
||||
; RUN: llc < %s -mtriple=x86_64-pc-linux | FileCheck --check-prefix=ELF %s
|
||||
|
||||
;MACHO: .globl _offsetSym0
|
||||
;MACHO-NOT: .alt_entry
|
||||
;MACHO: _offsetSym0 = _s
|
||||
;MACHO: .globl _offsetSym1
|
||||
;MACHO: .alt_entry _offsetSym1
|
||||
;MACHO: _offsetSym1 = _s+8
|
||||
|
||||
;ELF: .globl offsetSym0
|
||||
;ELF-NOT: .alt_entry
|
||||
;ELF: offsetSym0 = s
|
||||
;ELF: .globl offsetSym1
|
||||
;ELF-NOT: .alt_entry
|
||||
;ELF: offsetSym1 = s+8
|
||||
|
||||
%struct.S1 = type { i32, i32, i32 }
|
||||
|
||||
@s = global %struct.S1 { i32 31, i32 32, i32 33 }, align 4
|
||||
@offsetSym0 = alias i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s, i64 0, i32 0)
|
||||
@offsetSym1 = alias i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s, i64 0, i32 2)
|
@ -79,7 +79,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000)
|
||||
// CHECK: Type: Section (0xE)
|
||||
// CHECK: Section: __text (0x1)
|
||||
// CHECK: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK: Flags [ (0x20)
|
||||
// CHECK: Flags [ (0x220)
|
||||
// CHECK: AltEntry (0x200)
|
||||
// CHECK: NoDeadStrip (0x20)
|
||||
// CHECK: ]
|
||||
// CHECK: Value: 0xFFFF0001
|
||||
@ -99,7 +100,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000)
|
||||
// CHECK: Type: Section (0xE)
|
||||
// CHECK: Section: __text (0x1)
|
||||
// CHECK: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK: Flags [ (0x0)
|
||||
// CHECK: Flags [ (0x200)
|
||||
// CHECK: AltEntry (0x200)
|
||||
// CHECK: ]
|
||||
// CHECK: Value: 0xFFFF0001
|
||||
// CHECK: }
|
||||
@ -118,7 +120,8 @@ foo_equals2 = (_foo - _bar + 0xffff0000)
|
||||
// CHECK: Type: Section (0xE)
|
||||
// CHECK: Section: __text (0x1)
|
||||
// CHECK: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK: Flags [ (0x20)
|
||||
// CHECK: Flags [ (0x220)
|
||||
// CHECK: AltEntry (0x200)
|
||||
// CHECK: NoDeadStrip (0x20)
|
||||
// CHECK: ]
|
||||
// CHECK: Value: 0xFFFF0001
|
||||
|
55
test/MC/MachO/altentry.s
Normal file
55
test/MC/MachO/altentry.s
Normal file
@ -0,0 +1,55 @@
|
||||
// RUN: llvm-mc -triple x86_64-apple-darwin -filetype=obj %s -o - | llvm-readobj -t | FileCheck %s
|
||||
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Name: _offsetsym0
|
||||
// CHECK: Flags [ (0x0)
|
||||
// CHECK: Value: 0x0
|
||||
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Name: _offsetsym1
|
||||
// CHECK: Flags [ (0x200)
|
||||
// CHECK: Value: 0x4
|
||||
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Name: _offsetsym2
|
||||
// CHECK: Flags [ (0x200)
|
||||
// CHECK: Value: 0x8
|
||||
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Name: _offsetsym3
|
||||
// CHECK: Flags [ (0x200)
|
||||
// CHECK: Value: 0x18
|
||||
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Symbol {
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.comm _g0,4,2
|
||||
.section __DATA,__data
|
||||
.globl _s0
|
||||
.align 3
|
||||
_s0:
|
||||
.long 31
|
||||
.long 32
|
||||
.quad _g0
|
||||
|
||||
.globl _s1
|
||||
.align 3
|
||||
_s1:
|
||||
.long 33
|
||||
.long 34
|
||||
.quad _g0
|
||||
|
||||
.globl _offsetsym0
|
||||
_offsetsym0 = _s0
|
||||
.globl _offsetsym1
|
||||
.alt_entry _offsetsym1
|
||||
_offsetsym1 = _s0+4
|
||||
.globl _offsetsym2
|
||||
.alt_entry _offsetsym2
|
||||
_offsetsym2 = _s0+8
|
||||
.globl _offsetsym3
|
||||
.alt_entry _offsetsym3
|
||||
_offsetsym3 = _s1+8
|
||||
.subsections_via_symbols
|
@ -151,7 +151,7 @@ Lt0_x = Lt0_a - Lt0_b
|
||||
// CHECK-I386: Type: Section (0xE)
|
||||
// CHECK-I386: Section: __data (0x2)
|
||||
// CHECK-I386: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK-I386: Flags [ (0x0)
|
||||
// CHECK-I386: Flags [ (0x200)
|
||||
// CHECK-I386: ]
|
||||
// CHECK-I386: Value: 0x9
|
||||
// CHECK-I386: }
|
||||
@ -208,7 +208,7 @@ Lt0_x = Lt0_a - Lt0_b
|
||||
// CHECK-I386: Type: Undef (0x0)
|
||||
// CHECK-I386: Section: (0x0)
|
||||
// CHECK-I386: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK-I386: Flags [ (0x0)
|
||||
// CHECK-I386: Flags [ (0x200)
|
||||
// CHECK-I386: ]
|
||||
// CHECK-I386: Value: 0x0
|
||||
// CHECK-I386: }
|
||||
@ -360,7 +360,7 @@ Lt0_x = Lt0_a - Lt0_b
|
||||
// CHECK-X86_64: Type: Section (0xE)
|
||||
// CHECK-X86_64: Section: __data (0x2)
|
||||
// CHECK-X86_64: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK-X86_64: Flags [ (0x0)
|
||||
// CHECK-X86_64: Flags [ (0x200)
|
||||
// CHECK-X86_64: ]
|
||||
// CHECK-X86_64: Value: 0x9
|
||||
// CHECK-X86_64: }
|
||||
@ -417,7 +417,7 @@ Lt0_x = Lt0_a - Lt0_b
|
||||
// CHECK-X86_64: Type: Undef (0x0)
|
||||
// CHECK-X86_64: Section: (0x0)
|
||||
// CHECK-X86_64: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK-X86_64: Flags [ (0x0)
|
||||
// CHECK-X86_64: Flags [ (0x200)
|
||||
// CHECK-X86_64: ]
|
||||
// CHECK-X86_64: Value: 0x0
|
||||
// CHECK-X86_64: }
|
||||
|
@ -31,7 +31,8 @@ _baz:
|
||||
// CHECK-NEXT: Type: Section (0xE)
|
||||
// CHECK-NEXT: Section: __text (0x1)
|
||||
// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
|
||||
// CHECK-NEXT: Flags [ (0x0)
|
||||
// CHECK-NEXT: Flags [ (0x200)
|
||||
// CHECK-NEXT: AltEntry (0x200)
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Value: 0x102
|
||||
// CHECK-NEXT: }
|
||||
|
@ -239,7 +239,8 @@ static const EnumEntry<unsigned> MachOSymbolFlags[] = {
|
||||
{ "ReferencedDynamically", 0x10 },
|
||||
{ "NoDeadStrip", 0x20 },
|
||||
{ "WeakRef", 0x40 },
|
||||
{ "WeakDef", 0x80 }
|
||||
{ "WeakDef", 0x80 },
|
||||
{ "AltEntry", 0x200 },
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> MachOSymbolTypes[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user