From 88182132470527e27231f09b25a885893e528c66 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 27 Oct 2010 15:18:17 +0000 Subject: [PATCH] Add support for the .symver directive. This is really ugly, but most of it is contained in the ELF object writer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117448 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/ELFObjectWriter.cpp | 70 ++++++++++++--- lib/MC/MCParser/ELFAsmParser.cpp | 30 +++++++ test/MC/ELF/symref.s | 142 +++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 14 deletions(-) create mode 100644 test/MC/ELF/symref.s diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index f26002371d2..5e11a1553f8 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -134,6 +134,7 @@ namespace { }; SmallPtrSet UsedInReloc; + DenseMap Renames; llvm::DenseMap > Relocations; @@ -292,8 +293,7 @@ namespace { void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout); - void ExecutePostLayoutBinding(MCAssembler &Asm) { - } + void ExecutePostLayoutBinding(MCAssembler &Asm); void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, uint64_t Address, uint64_t Offset, @@ -449,6 +449,30 @@ static const MCSymbol &AliasedSymbol(const MCSymbol &Symbol) { return *S; } +void ELFObjectWriterImpl::ExecutePostLayoutBinding(MCAssembler &Asm) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. + + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Alias = it->getSymbol(); + if (!Alias.isVariable()) + continue; + const MCSymbol &Symbol = AliasedSymbol(Alias); + const StringRef &AliasName = Alias.getName(); + size_t Pos = AliasName.find('@'); + if (Pos == StringRef::npos) + continue; + + StringRef Rest(AliasName.begin() + Pos); + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; + + std::pair t(&Symbol, &Alias); + Renames.insert(t); + } +} + void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, const MCAsmLayout &Layout) { MCSymbolData &OrigData = *MSD.SymbolData; @@ -593,6 +617,9 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); if (!Target.isAbsolute()) { Symbol = &AliasedSymbol(Target.getSymA()->getSymbol()); + const MCSymbol *Renamed = Renames.lookup(Symbol); + if (Renamed) + Symbol = Renamed; MCSymbolData &SD = Asm.getSymbolData(*Symbol); MCFragment *F = SD.getFragment(); @@ -765,10 +792,13 @@ ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, } static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, - bool Used) { + bool Used, bool Renamed) { if (Used) return true; + if (Renamed) + return false; + const MCSymbol &Symbol = Data.getSymbol(); const MCSymbol &A = AliasedSymbol(Symbol); @@ -821,40 +851,52 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); - if (!isInSymtab(Asm, *it, UsedInReloc.count(&Symbol))) + if (!isInSymtab(Asm, *it, UsedInReloc.count(&Symbol), + Renames.count(&Symbol))) continue; ELFSymbolData MSD; MSD.SymbolData = it; bool Local = isLocal(*it); + const MCSymbol &RefSymbol = AliasedSymbol(Symbol); if (it->isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; } else if (Symbol.isAbsolute()) { MSD.SectionIndex = ELF::SHN_ABS; - } else if (Symbol.isVariable()) { - const MCSymbol &RefSymbol = AliasedSymbol(Symbol); - if (RefSymbol.isDefined()) { - MSD.SectionIndex = SectionIndexMap.lookup(&RefSymbol.getSection()); - assert(MSD.SectionIndex && "Invalid section index!"); - } - } else if (Symbol.isUndefined()) { - assert(!Local); + } else if (RefSymbol.isUndefined()) { MSD.SectionIndex = ELF::SHN_UNDEF; // FIXME: Undefined symbols are global, but this is the first place we // are able to set it. if (GetBinding(*it) == ELF::STB_LOCAL) SetBinding(*it, ELF::STB_GLOBAL); + } else if (Symbol.isVariable()) { + MSD.SectionIndex = SectionIndexMap.lookup(&RefSymbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); } - uint64_t &Entry = StringIndexMap[Symbol.getName()]; + // The @@@ in symbol version is replaced with @ in undefined symbols and + // @@ in defined ones. + StringRef Name = Symbol.getName(); + size_t Pos = Name.find("@@@"); + std::string FinalName; + if (Pos != StringRef::npos) { + StringRef Prefix(Name.begin(), Pos); + unsigned n = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; + StringRef Suffix(Name.begin() + Pos + n); + FinalName = Prefix.str() + Suffix.str(); + } else { + FinalName = Name.str(); + } + + uint64_t &Entry = StringIndexMap[FinalName]; if (!Entry) { Entry = StringTable.size(); - StringTable += Symbol.getName(); + StringTable += FinalName; StringTable += '\x00'; } MSD.StringIndex = Entry; diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index 1970124b2d8..33fdf98bcfc 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" @@ -51,6 +52,7 @@ public: AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); } // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is @@ -116,6 +118,7 @@ public: bool ParseDirectivePrevious(StringRef, SMLoc); bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveIdent(StringRef, SMLoc); + bool ParseDirectiveSymver(StringRef, SMLoc); private: bool ParseSectionName(StringRef &SectionName); @@ -377,6 +380,33 @@ bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { return false; } +/// ParseDirectiveSymver +/// ::= .symver foo, bar2@zed +bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (AliasName.find('@') == StringRef::npos) + return TokError("expected a '@' in the name"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext()); + + getStreamer().EmitAssignment(Alias, Value); + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() { diff --git a/test/MC/ELF/symref.s b/test/MC/ELF/symref.s new file mode 100644 index 00000000000..df2395e9a08 --- /dev/null +++ b/test/MC/ELF/symref.s @@ -0,0 +1,142 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump | FileCheck %s + +defined1: +defined2: +defined3: + .symver defined1, bar1@zed + .symver undefined1, bar2@zed + + .symver defined2, bar3@@zed + + .symver defined3, bar5@@@zed + .symver undefined3, bar6@@@zed + + .long defined1 + .long undefined1 + .long defined2 + .long defined3 + .long undefined3 + +// CHECK: # Symbol 0x00000001 +// CHECK-NEXT: (('st_name', 0x00000013) # 'bar1@zed' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000002 +// CHECK-NEXT: (('st_name', 0x00000025) # 'bar3@@zed' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000003 +// CHECK-NEXT: (('st_name', 0x0000002f) # 'bar5@@zed' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000004 +// CHECK-NEXT: (('st_name', 0x00000001) # 'defined1' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000005 +// CHECK-NEXT: (('st_name', 0x0000000a) # 'defined2' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000006 +// CHECK-NEXT: (('st_name', 0x00000000) # '' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000003) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000001) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000007 +// CHECK-NEXT: (('st_name', 0x00000000) # '' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000003) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000002) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000008 +// CHECK-NEXT: (('st_name', 0x00000000) # '' +// CHECK-NEXT: ('st_bind', 0x00000000) +// CHECK-NEXT: ('st_type', 0x00000003) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000003) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x00000009 +// CHECK-NEXT: (('st_name', 0x0000001c) # 'bar2@zed' +// CHECK-NEXT: ('st_bind', 0x00000001) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000000) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 0x0000000a +// CHECK-NEXT: (('st_name', 0x00000039) # 'bar6@zed' +// CHECK-NEXT: ('st_bind', 0x00000001) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000000) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT:]) + +// CHECK: # Relocation 0x00000000 +// CHECK-NEXT: (('r_offset', 0x00000000) +// CHECK-NEXT: ('r_sym', 0x00000006) +// CHECK-NEXT: ('r_type', 0x0000000a) +// CHECK-NEXT: ('r_addend', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Relocation 0x00000001 +// CHECK-NEXT: (('r_offset', 0x00000004) +// CHECK-NEXT: ('r_sym', 0x00000009) +// CHECK-NEXT: ('r_type', 0x0000000a) +// CHECK-NEXT: ('r_addend', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Relocation 0x00000002 +// CHECK-NEXT: (('r_offset', 0x00000008) +// CHECK-NEXT: ('r_sym', 0x00000006) +// CHECK-NEXT: ('r_type', 0x0000000a) +// CHECK-NEXT: ('r_addend', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Relocation 0x00000003 +// CHECK-NEXT: (('r_offset', 0x0000000c) +// CHECK-NEXT: ('r_sym', 0x00000006) +// CHECK-NEXT: ('r_type', 0x0000000a) +// CHECK-NEXT: ('r_addend', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT: # Relocation 0x00000004 +// CHECK-NEXT: (('r_offset', 0x00000010) +// CHECK-NEXT: ('r_sym', 0x0000000a) +// CHECK-NEXT: ('r_type', 0x0000000a) +// CHECK-NEXT: ('r_addend', 0x00000000) +// CHECK-NEXT: ), +// CHECK-NEXT:]) -- 2.34.1