From 6aff2fbd56d4bc2d6029f7c9bd49a97f6dc01213 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Mon, 24 Aug 2009 08:40:12 +0000 Subject: [PATCH] llvm-mc/Mach-O: Support symbol attributes. - This is mostly complete, the main thing missing is .indirect_symbol support (which would be straight-forward, except that the way it is implemented in 'as' makes getting an exact .o match interesting). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79899 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCAssembler.h | 28 +++- lib/MC/MCAssembler.cpp | 11 +- lib/MC/MCMachOStreamer.cpp | 83 ++++++++++- test/MC/MachO/symbol-flags.s | 254 ++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+), 12 deletions(-) create mode 100644 test/MC/MachO/symbol-flags.s diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index bcd678deaa3..aae5f08caaf 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -317,6 +317,13 @@ public: /// unit. unsigned IsExternal : 1; + /// IsPrivateExtern - True if this symbol is private extern. + unsigned IsPrivateExtern : 1; + + /// Flags - The Flags field is used by object file implementations to store + /// additional per symbol information which is not easily classified. + uint32_t Flags; + public: // Only for use as sentinel. MCSymbolData(); @@ -334,13 +341,22 @@ public: uint64_t getOffset() const { return Offset; } void setOffset(uint64_t Value) { Offset = Value; } - /// @} - /// @name Symbol Attributes - /// @{ - - bool isExternal() const { return IsExternal; } - void setExternal(bool Value) { IsExternal = Value; } + /// @} + /// @name Symbol Attributes + /// @{ + + bool isExternal() const { return IsExternal; } + void setExternal(bool Value) { IsExternal = Value; } + + bool isPrivateExtern() const { return IsPrivateExtern; } + void setPrivateExtern(bool Value) { IsPrivateExtern = Value; } + + /// getFlags - Get the (implementation defined) symbol flags. + uint32_t getFlags() const { return Flags; } + /// setFlags - Set the (implementation defined) symbol flags. + void setFlags(uint32_t Value) { Flags = Value; } + /// @} }; diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 80e1b9e43cb..93154225029 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -291,7 +291,8 @@ public: // FIXME: Set STAB bits. - // FIXME: Set private external bit. + if (MSD.SymbolData->isPrivateExtern()) + Type |= STF_PrivateExtern; // Set external bit. if (MSD.SymbolData->isExternal() || Symbol.isUndefined()) @@ -302,7 +303,11 @@ public: Write32(MSD.StringIndex); Write8(Type); Write8(MSD.SectionIndex); - Write16(0); // FIXME: Desc + + // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' + // value. + Write16(MSD.SymbolData->getFlags() & 0xFFFF); + Write32(0); // FIXME: Value } @@ -544,7 +549,7 @@ MCSymbolData::MCSymbolData() : Symbol(*(MCSymbol*)0) {} MCSymbolData::MCSymbolData(MCSymbol &_Symbol, MCFragment *_Fragment, uint64_t _Offset, MCAssembler *A) : Symbol(_Symbol), Fragment(_Fragment), Offset(_Offset), - IsExternal(false) + IsExternal(false), IsPrivateExtern(false), Flags(0) { if (A) A->getSymbolList().push_back(this); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index caff1256d3b..9d60e3ebe1e 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -19,6 +19,27 @@ using namespace llvm; namespace { class MCMachOStreamer : public MCStreamer { + /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest + /// 16 bits of the implementation defined flags. + enum SymbolFlags { // See . + SF_DescFlagsMask = 0xFFFF, + + // Reference type flags. + SF_ReferenceTypeMask = 0x0007, + SF_ReferenceTypeUndefinedNonLazy = 0x0000, + SF_ReferenceTypeUndefinedLazy = 0x0001, + SF_ReferenceTypeDefined = 0x0002, + SF_ReferenceTypePrivateDefined = 0x0003, + SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004, + SF_ReferenceTypePrivateUndefinedLazy = 0x0005, + + // Other 'desc' flags. + SF_NoDeadStrip = 0x0020, + SF_WeakReference = 0x0040, + SF_WeakDefinition = 0x0080 + }; + +private: MCAssembler Assembler; MCSectionData *CurSectionData; @@ -121,6 +142,9 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); SD.setFragment(F); SD.setOffset(F->getContents().size()); + + // This causes the reference type and weak reference flags to be cleared. + SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask)); Symbol->setSection(*CurSection); } @@ -141,18 +165,71 @@ void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) { + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling getSymbolData here is to register the + // symbol with the assembler. + MCSymbolData &SD = getSymbolData(*Symbol); + + // The implementation of symbol attributes is designed to match 'as', but it + // leaves much to desired. It doesn't really make sense to arbitrarily add and + // remove flags, but 'as' allows this (in particular, see .desc). + // + // In the future it might be worth trying to make these operations more well + // defined. switch (Attribute) { - default: - llvm_unreachable("FIXME: Not yet implemented!"); + case MCStreamer::Hidden: + case MCStreamer::Internal: + case MCStreamer::Protected: + case MCStreamer::Weak: + assert(0 && "Invalid symbol attribute for Mach-O!"); + break; case MCStreamer::Global: getSymbolData(*Symbol).setExternal(true); break; + + case MCStreamer::LazyReference: + // FIXME: This requires -dynamic. + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy); + break; + + case MCStreamer::IndirectSymbol: + llvm_unreachable("FIXME: Not yet implemented!"); + break; + + // Since .reference sets the no dead strip bit, it is equivalent to + // .no_dead_strip in practice. + case MCStreamer::Reference: + case MCStreamer::NoDeadStrip: + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + break; + + case MCStreamer::PrivateExtern: + SD.setExternal(true); + SD.setPrivateExtern(true); + break; + + case MCStreamer::WeakReference: + // FIXME: This requires -dynamic. + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_WeakReference); + break; + + case MCStreamer::WeakDefinition: + // FIXME: 'as' enforces that this is defined and global. The manual claims + // it has to be in a coalesced section, but this isn't enforced. + SD.setFlags(SD.getFlags() | SF_WeakDefinition); + break; } } void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - llvm_unreachable("FIXME: Not yet implemented!"); + // Encode the 'desc' value into the lowest implementation defined bits. + assert(DescValue == (DescValue & SF_DescFlagsMask) && + "Invalid .desc value!"); + getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask); } void MCMachOStreamer::EmitLocalSymbol(MCSymbol *Symbol, const MCValue &Value) { diff --git a/test/MC/MachO/symbol-flags.s b/test/MC/MachO/symbol-flags.s new file mode 100644 index 00000000000..e82b0a0447f --- /dev/null +++ b/test/MC/MachO/symbol-flags.s @@ -0,0 +1,254 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .reference sym_ref_A + .reference sym_ref_def_A +sym_ref_def_A: +sym_ref_def_C: + .reference sym_ref_def_C + + .weak_reference sym_weak_ref_A + .weak_reference sym_weak_ref_def_A +sym_weak_ref_def_A: +sym_weak_ref_def_B: + .weak_reference sym_weak_ref_def_B + + .data + .globl sym_weak_def_A + .weak_definition sym_weak_def_A +sym_weak_def_A: + + .lazy_reference sym_lazy_ref_A + .lazy_reference sym_lazy_ref_B +sym_lazy_ref_B: +sym_lazy_ref_C: + .lazy_reference sym_lazy_ref_C + + .private_extern sym_private_ext_A + .private_extern sym_private_ext_B +sym_private_ext_B: +sym_private_ext_C: + .private_extern sym_private_ext_C + .private_extern sym_private_ext_D + .globl sym_private_ext_D + + .no_dead_strip sym_no_dead_strip_A + + .reference sym_ref_A + .desc sym_ref_A, 1 + .desc sym_ref_A, 0x1234 + + .desc sym_desc_flags,0x47 +sym_desc_flags: + +// CHECK: ('cputype', 7) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 296) +// CHECK: ('flag', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 1) +// CHECK: ('size', 192) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 324) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 2) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 324) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: # Section 1 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 324) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 324) +// CHECK: ('nsyms', 16) +// CHECK: ('stroff', 516) +// CHECK: ('strsize', 260) +// CHECK: ('_string_data', '\x00sym_ref_A\x00sym_weak_ref_A\x00sym_weak_def_A\x00sym_lazy_ref_A\x00sym_private_ext_A\x00sym_private_ext_B\x00sym_private_ext_C\x00sym_private_ext_D\x00sym_no_dead_strip_A\x00sym_ref_def_A\x00sym_ref_def_C\x00sym_weak_ref_def_A\x00sym_weak_ref_def_B\x00sym_lazy_ref_B\x00sym_lazy_ref_C\x00sym_desc_flags\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 148) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 32) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_ref_def_A') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 162) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 32) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_ref_def_C') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 176) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_weak_ref_def_A') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 195) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_weak_ref_def_B') +// CHECK: ), +// CHECK: # Symbol 4 +// CHECK: (('n_strx', 214) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 32) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_lazy_ref_B') +// CHECK: ), +// CHECK: # Symbol 5 +// CHECK: (('n_strx', 229) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 32) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_lazy_ref_C') +// CHECK: ), +// CHECK: # Symbol 6 +// CHECK: (('n_strx', 244) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_desc_flags') +// CHECK: ), +// CHECK: # Symbol 7 +// CHECK: (('n_strx', 74) +// CHECK: ('n_type', 0x1f) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_private_ext_B') +// CHECK: ), +// CHECK: # Symbol 8 +// CHECK: (('n_strx', 92) +// CHECK: ('n_type', 0x1f) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_private_ext_C') +// CHECK: ), +// CHECK: # Symbol 9 +// CHECK: (('n_strx', 26) +// CHECK: ('n_type', 0xf) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 128) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_weak_def_A') +// CHECK: ), +// CHECK: # Symbol 10 +// CHECK: (('n_strx', 41) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 33) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_lazy_ref_A') +// CHECK: ), +// CHECK: # Symbol 11 +// CHECK: (('n_strx', 128) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 32) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_no_dead_strip_A') +// CHECK: ), +// CHECK: # Symbol 12 +// CHECK: (('n_strx', 56) +// CHECK: ('n_type', 0x11) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_private_ext_A') +// CHECK: ), +// CHECK: # Symbol 13 +// CHECK: (('n_strx', 110) +// CHECK: ('n_type', 0x11) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_private_ext_D') +// CHECK: ), +// CHECK: # Symbol 14 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 4660) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_ref_A') +// CHECK: ), +// CHECK: # Symbol 15 +// CHECK: (('n_strx', 11) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 64) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'sym_weak_ref_A') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 7) +// CHECK: ('iextdefsym', 7) +// CHECK: ('nextdefsym', 3) +// CHECK: ('iundefsym', 10) +// CHECK: ('nundefsym', 6) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ])