[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.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263521 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Lang Hames 2016-03-15 01:43:05 +00:00
parent 2f2c2e3539
commit 875b7560fb
17 changed files with 147 additions and 15 deletions

View File

@ -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; }

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -75,6 +75,7 @@ MCAsmInfo::MCAsmInfo() {
HasSingleParameterDotFile = true;
HasIdentDirective = false;
HasNoDeadStrip = false;
HasAltEntry = false;
WeakDirective = "\t.weak\t";
WeakRefDirective = nullptr;
HasWeakDefDirective = false;

View File

@ -88,6 +88,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() {
HasDotTypeDotSizeDirective = false;
HasNoDeadStrip = true;
HasAltEntry = true;
DwarfUsesRelocationsAcrossSections = false;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View 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)

View File

@ -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
View 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

View File

@ -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: }

View File

@ -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: }

View File

@ -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[] = {