From 73ffea47d20bc9f559b4ce0c60166ee504073832 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Sat, 25 Sep 2010 05:42:19 +0000 Subject: [PATCH] Move ELF to HasReliableSymbolDifference=true. Also take the opportunity to put symbols defined in merge sections in independent atoms. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@114786 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/ELFObjectWriter.cpp | 22 ++++++++---- lib/MC/MCELFStreamer.cpp | 61 +++++++++++++++++++++++++++++--- lib/Target/X86/X86AsmBackend.cpp | 6 ++++ test/MC/ELF/basic-elf.ll | 2 +- test/MC/ELF/merge.s | 26 ++++++++++++++ 5 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 test/MC/ELF/merge.s diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 9eb9bcac46a..810af37c6c5 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -487,6 +487,13 @@ void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, } } +static const MCSymbolData *getAtom(const MCSymbolData &SD) { + if (!SD.getFragment()) + return 0; + + return SD.getFragment()->getAtom(); +} + // FIXME: this is currently X86/X86_64 only void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, @@ -502,7 +509,7 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, if (!Target.isAbsolute()) { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); MCSymbolData &SD = Asm.getSymbolData(*Symbol); - const MCSymbolData *Base = Asm.getAtom(Layout, &SD); + const MCSymbolData *Base = getAtom(SD); MCFragment *F = SD.getFragment(); // Avoid relocations for cases like jumps and calls in the same file. @@ -515,7 +522,7 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, } if (Base) { - if (F && !SD.isExternal()) { + if (Base != &SD) { Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; MCSectionData *FSD = F->getParent(); @@ -523,8 +530,6 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); } else Index = getSymbolIndexInSymbolTable(Asm, Symbol); - if (Base != &SD) - Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); Addend = Value; // Compensate for the addend on i386. if (Is64Bit) @@ -537,11 +542,14 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, MCSectionData *FSD = F->getParent(); // Offset of the symbol in the section - Addend = Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); + Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); } else { - FixedValue = Value; - return; + Index = getSymbolIndexInSymbolTable(Asm, Symbol); } + Addend = Value; + // Compensate for the addend on i386. + if (Is64Bit) + Value = 0; } } diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 5dc5ab08dab..6bf61a194c6 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -149,20 +149,43 @@ void MCELFStreamer::InitSections() { SetSectionText(); } +static bool isSymbolLinkerVisible(const MCAssembler &Asm, + const MCSymbolData &Data) { + const MCSymbol &Symbol = Data.getSymbol(); + // Absolute temporary labels are never visible. + if (!Symbol.isInSection()) + return false; + + if (Asm.getBackend().doesSectionRequireSymbols(Symbol.getSection())) + return true; + + if (!Data.isExternal()) + return false; + + return Asm.isSymbolLinkerVisible(Symbol); +} + void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + Symbol->setSection(*CurSection); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // We have to create a new fragment if this is an atom defining symbol, + // fragments cannot span atoms. + if (isSymbolLinkerVisible(getAssembler(), SD)) + new MCDataFragment(getCurrentSectionData()); + // FIXME: This is wasteful, we don't necessarily need to create a data // fragment. Instead, we should mark the symbol as pointing into the data // fragment if it exists, otherwise we should just queue the label and set its // fragment pointer when we emit the next fragment. MCDataFragment *F = getOrCreateDataFragment(); - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); SD.setFragment(F); SD.setOffset(F->getContents().size()); - - Symbol->setSection(*CurSection); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { @@ -476,7 +499,37 @@ void MCELFStreamer::EmitInstruction(const MCInst &Inst) { } void MCELFStreamer::Finish() { - getAssembler().Finish(); + // FIXME: We create more atoms than it is necessary. Some relocations to + // merge sections can be implemented with section address + offset, + // figure out which ones and why. + + // First, scan the symbol table to build a lookup table from fragments to + // defining symbols. + DenseMap DefiningSymbolMap; + for (MCAssembler::symbol_iterator it = getAssembler().symbol_begin(), + ie = getAssembler().symbol_end(); it != ie; ++it) { + if (isSymbolLinkerVisible(getAssembler(), *it) && + it->getFragment()) { + // An atom defining symbol should never be internal to a fragment. + assert(it->getOffset() == 0 && "Invalid offset in atom defining symbol!"); + DefiningSymbolMap[it->getFragment()] = it; + } + } + + // Set the fragment atom associations by tracking the last seen atom defining + // symbol. + for (MCAssembler::iterator it = getAssembler().begin(), + ie = getAssembler().end(); it != ie; ++it) { + MCSymbolData *CurrentAtom = 0; + for (MCSectionData::iterator it2 = it->begin(), + ie2 = it->end(); it2 != ie2; ++it2) { + if (MCSymbolData *SD = DefiningSymbolMap.lookup(it2)) + CurrentAtom = SD; + it2->setAtom(CurrentAtom); + } + } + + this->MCObjectStreamer::Finish(); } MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, diff --git a/lib/Target/X86/X86AsmBackend.cpp b/lib/Target/X86/X86AsmBackend.cpp index 4b51b69dc2d..231f151206b 100644 --- a/lib/Target/X86/X86AsmBackend.cpp +++ b/lib/Target/X86/X86AsmBackend.cpp @@ -191,6 +191,12 @@ public: : X86AsmBackend(T), OSType(_OSType) { HasAbsolutizedSet = true; HasScatteredSymbols = true; + HasReliableSymbolDifference = true; + } + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + const MCSectionELF &ES = static_cast(Section); + return ES.getFlags() & MCSectionELF::SHF_MERGE; } bool isVirtualSection(const MCSection &Section) const { diff --git a/test/MC/ELF/basic-elf.ll b/test/MC/ELF/basic-elf.ll index bc9ec131860..1aa43f7884a 100644 --- a/test/MC/ELF/basic-elf.ll +++ b/test/MC/ELF/basic-elf.ll @@ -83,7 +83,7 @@ declare i32 @puts(i8* nocapture) nounwind ; 64: # Relocation 2 ; 64: (('r_offset', 15) ; 64: ('r_type', 10) -; 64: ('r_addend', 6) +; 64: ('r_addend', 0) ; 64: ), ; 64: # Relocation 3 ; 64: (('r_offset', 20) diff --git a/test/MC/ELF/merge.s b/test/MC/ELF/merge.s new file mode 100644 index 00000000000..82e1d88696b --- /dev/null +++ b/test/MC/ELF/merge.s @@ -0,0 +1,26 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump --dump-section-data | FileCheck %s + +// Test that relocations with local symbols in a mergeable section are done +// with a reference to the symbol. Not sure if this is a linker limitation, +// but this matches the behavior of gas. + + .section .sec1,"aM",@progbits,16 +.Lfoo: + .text + movsd .Lfoo(%rip), %xmm1 + +// Relocation refers to symbol 1 + +// CHECK: ('_relocations', [ +// CHECK-NEXT: # Relocation 0 +// CHECK-NEXT: (('r_offset', +// CHECK-NEXT: ('r_sym', 1) +// CHECK-NEXT: ('r_type', +// CHECK-NEXT: ('r_addend', +// CHECK-NEXT: ), +// CHECK-NEXT: ]) + +// Symbol number 1 is .Lfoo + +// CHECK: # Symbol 1 +// CHECK-NEXT: (('st_name', 1) # '.Lfoo'