From 98f8bc9323658c0b875798e030be8420198db39a Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Fri, 30 May 2014 13:22:59 +0000 Subject: MachO: support N_INDR aliases in assembly files. This makes LLVM create N_INDR aliases (to be resolved by the linker) when appropriate. rdar://problem/15125513 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209894 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCMachObjectWriter.h | 2 + include/llvm/Object/SymbolicFile.h | 1 + lib/MC/MachObjectWriter.cpp | 50 ++++++++++++--- lib/Object/MachOObjectFile.cpp | 3 + test/MC/MachO/aliased-symbols.s | 115 +++++++++++++++++++++++++++++++++++ test/MC/MachO/variable-exprs.s | 8 +-- tools/llvm-nm/llvm-nm.cpp | 2 + 7 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 test/MC/MachO/aliased-symbols.s diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h index e7d5bbd5be..12a7f0ee7b 100644 --- a/include/llvm/MC/MCMachObjectWriter.h +++ b/include/llvm/MC/MCMachObjectWriter.h @@ -111,6 +111,8 @@ class MachObjectWriter : public MCObjectWriter { /// @} + MachSymbolData *findSymbolData(const MCSymbol &Sym); + public: MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS, bool _IsLittleEndian) diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 28400e1ab8..7b90048717 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -86,6 +86,7 @@ public: SF_Weak = 1U << 2, // Weak symbol SF_Absolute = 1U << 3, // Absolute symbol SF_Common = 1U << 4, // Symbol has common linkage + SF_Indirect = 1U << 5, SF_FormatSpecific = 1U << 5 // Specific to the object file format // (e.g. section symbols) }; diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index cbaf0b87d6..5214398bbc 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -303,20 +303,50 @@ void MachObjectWriter::WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, assert(OS.tell() - Start == sizeof(MachO::dysymtab_command)); } +MachObjectWriter::MachSymbolData * +MachObjectWriter::findSymbolData(const MCSymbol &Sym) { + for (auto &Entry : LocalSymbolData) + if (&Entry.SymbolData->getSymbol() == &Sym) + return &Entry; + + for (auto &Entry : ExternalSymbolData) + if (&Entry.SymbolData->getSymbol() == &Sym) + return &Entry; + + for (auto &Entry : UndefinedSymbolData) + if (&Entry.SymbolData->getSymbol() == &Sym) + return &Entry; + + return nullptr; +} + void MachObjectWriter::WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) { MCSymbolData &Data = *MSD.SymbolData; - const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbol *Symbol = &Data.getSymbol(); + const MCSymbol *AliasedSymbol = &Symbol->AliasedSymbol(); + uint8_t SectionIndex = MSD.SectionIndex; uint8_t Type = 0; uint16_t Flags = Data.getFlags(); uint64_t Address = 0; + bool IsAlias = Symbol != AliasedSymbol; + + MachSymbolData *AliaseeInfo; + if (IsAlias) { + AliaseeInfo = findSymbolData(*AliasedSymbol); + if (AliaseeInfo) + SectionIndex = AliaseeInfo->SectionIndex; + Symbol = AliasedSymbol; + } // Set the N_TYPE bits. See . // // FIXME: Are the prebound or indirect fields possible here? - if (Symbol.isUndefined()) + if (IsAlias && Symbol->isUndefined()) + Type = MachO::N_INDR; + else if (Symbol->isUndefined()) Type = MachO::N_UNDF; - else if (Symbol.isAbsolute()) + else if (Symbol->isAbsolute()) Type = MachO::N_ABS; else Type = MachO::N_SECT; @@ -327,13 +357,15 @@ void MachObjectWriter::WriteNlist(MachSymbolData &MSD, Type |= MachO::N_PEXT; // Set external bit. - if (Data.isExternal() || Symbol.isUndefined()) + if (Data.isExternal() || (!IsAlias && Symbol->isUndefined())) Type |= MachO::N_EXT; // Compute the symbol address. - if (Symbol.isDefined()) { + if (IsAlias && Symbol->isUndefined()) + Address = AliaseeInfo->StringIndex; + else if (Symbol->isDefined()) Address = getSymbolAddress(&Data, Layout); - } else if (Data.isCommon()) { + else if (Data.isCommon()) { // Common symbols are encoded with the size in the address // field, and their alignment in the flags. Address = Data.getCommonSize(); @@ -344,21 +376,21 @@ void MachObjectWriter::WriteNlist(MachSymbolData &MSD, assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); if (Log2Size > 15) report_fatal_error("invalid 'common' alignment '" + - Twine(Align) + "' for '" + Symbol.getName() + "'", + Twine(Align) + "' for '" + Symbol->getName() + "'", false); // FIXME: Keep this mask with the SymbolFlags enumeration. Flags = (Flags & 0xF0FF) | (Log2Size << 8); } } - if (Layout.getAssembler().isThumbFunc(&Symbol)) + if (Layout.getAssembler().isThumbFunc(Symbol)) Flags |= SF_ThumbFunc; // struct nlist (12 bytes) Write32(MSD.StringIndex); Write8(Type); - Write8(MSD.SectionIndex); + Write8(SectionIndex); // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index c6bab03d01..6dca9750c1 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -584,6 +584,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) Result |= SymbolRef::SF_Undefined; + if ((MachOType & MachO::N_TYPE) == MachO::N_INDR) + Result |= SymbolRef::SF_Indirect; + if (MachOType & MachO::N_STAB) Result |= SymbolRef::SF_FormatSpecific; diff --git a/test/MC/MachO/aliased-symbols.s b/test/MC/MachO/aliased-symbols.s new file mode 100644 index 0000000000..0b4463d055 --- /dev/null +++ b/test/MC/MachO/aliased-symbols.s @@ -0,0 +1,115 @@ +// RUN: llvm-mc -triple thumbv7m-apple-darwin-eabi %s -filetype=obj -o %t +// RUN: llvm-readobj -symbols %t | FileCheck %s + + .data + var1 = var2 + .long var1 + .long var2 + .long var2 + 4 +defined_early: + .long 0 + + alias_to_early = defined_early + alias_to_late = defined_late + +defined_late: + .long 0 + + .global extern_test + extern_test = var2 + + alias_to_local = Ltmp0 +Ltmp0: + +// CHECK: Symbols [ + + // defined_early was defined. Actually has value 0xc. +// CHECK: Symbol { +// CHECK-NEXT: Name: defined_early +// CHECK-NEXT: Type: Section (0xE) +// CHECK-NEXT: Section: __data (0x2) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[DEFINED_EARLY:[0-9A-F]+]] +// CHECK-NEXT: } + + // alias_to_early was an alias to defined_early. But we can resolve it. +// CHECK: Symbol { +// CHECK-NEXT: Name: alias_to_early +// CHECK-NEXT: Type: Section (0xE) +// CHECK-NEXT: Section: __data (0x2) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[DEFINED_EARLY]] +// CHECK-NEXT: } + + // defined_late was defined. Just after defined_early. +// CHECK: Symbol { +// CHECK-NEXT: Name: defined_late +// CHECK-NEXT: Type: Section (0xE) +// CHECK-NEXT: Section: __data (0x2) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[DEFINED_LATE:[0-9A-F]+]] +// CHECK-NEXT: } + + // alias_to_late was an alias to defined_late. But we can resolve it. +// CHECK: Symbol { +// CHECK-NEXT: Name: alias_to_late +// CHECK-NEXT: Type: Section (0xE) +// CHECK-NEXT: Section: __data (0x2) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[DEFINED_LATE]] +// CHECK-NEXT: } + + // alias_to_local is an alias, but what it points to has no + // MachO representation. We must resolve it. +// CHECK: Symbol { +// CHECK-NEXT: Name: alias_to_local (37) +// CHECK-NEXT: Type: Section (0xE) +// CHECK-NEXT: Section: (0x0) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x14 +// CHECK-NEXT: } + + // extern_test was a pure alias to the unknown "var2". + // N_INDR and Extern. +// CHECK: Name: extern_test +// CHECK-NEXT: Extern +// CHECK-NEXT: Type: Indirect (0xA) +// CHECK-NEXT: Section: (0x0) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[VAR2_STRINGINDEX:[0-9a-f]+]] +// CHECK-NEXT: } + + // var1 was another alias to an unknown variable. Not extern this time. +// CHECK: Symbol { +// CHECK-NEXT: Name: var1 (1) +// CHECK-NEXT: Type: Indirect (0xA) +// CHECK-NEXT: Section: (0x0) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x[[VAR2_STRINGINDEX]] +// CHECK-NEXT: } + + // var2 was a normal undefined (extern) symbol. +// CHECK: Symbol { +// CHECK-NEXT: Name: var2 +// CHECK-NEXT: Extern +// CHECK-NEXT: Type: Undef (0x0) +// CHECK-NEXT: Section: (0x0) +// CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: } diff --git a/test/MC/MachO/variable-exprs.s b/test/MC/MachO/variable-exprs.s index 8eeb82f0fa..a7fa45d571 100644 --- a/test/MC/MachO/variable-exprs.s +++ b/test/MC/MachO/variable-exprs.s @@ -202,10 +202,10 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-I386: ), // CHECK-I386: # Symbol 8 // CHECK-I386: (('n_strx', 1) -// CHECK-I386: ('n_type', 0x1) +// CHECK-I386: ('n_type', 0xb) // CHECK-I386: ('n_sect', 0) // CHECK-I386: ('n_desc', 0) -// CHECK-I386: ('n_value', 0) +// CHECK-I386: ('n_value', 4) // CHECK-I386: ('_string', 'd2') // CHECK-I386: ), // CHECK-I386: # Symbol 9 @@ -403,10 +403,10 @@ Lt0_x = Lt0_a - Lt0_b // CHECK-X86_64: ), // CHECK-X86_64: # Symbol 8 // CHECK-X86_64: (('n_strx', 1) -// CHECK-X86_64: ('n_type', 0x1) +// CHECK-X86_64: ('n_type', 0xb) // CHECK-X86_64: ('n_sect', 0) // CHECK-X86_64: ('n_desc', 0) -// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('n_value', 4) // CHECK-X86_64: ('_string', 'd2') // CHECK-X86_64: ), // CHECK-X86_64: # Symbol 9 diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 3be9247c5a..d1cfefe6a3 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -395,6 +395,8 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { switch (NType & MachO::N_TYPE) { case MachO::N_ABS: return 's'; + case MachO::N_INDR: + return 'i'; case MachO::N_SECT: { section_iterator Sec = Obj.section_end(); Obj.getSymbolSection(Symb, Sec); -- cgit v1.2.3