summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2010-09-25 05:42:19 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2010-09-25 05:42:19 +0000
commit73ffea47d20bc9f559b4ce0c60166ee504073832 (patch)
treee87577519219fb1ad03bd11f9a15521e65cc5777
parentb0ba0f4170dcfe1dbce17680c16cffce311e3ad8 (diff)
downloadllvm-73ffea47d20bc9f559b4ce0c60166ee504073832.tar.gz
llvm-73ffea47d20bc9f559b4ce0c60166ee504073832.tar.bz2
llvm-73ffea47d20bc9f559b4ce0c60166ee504073832.tar.xz
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
-rw-r--r--lib/MC/ELFObjectWriter.cpp22
-rw-r--r--lib/MC/MCELFStreamer.cpp61
-rw-r--r--lib/Target/X86/X86AsmBackend.cpp6
-rw-r--r--test/MC/ELF/basic-elf.ll2
-rw-r--r--test/MC/ELF/merge.s26
5 files changed, 105 insertions, 12 deletions
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp
index 9eb9bcac46..810af37c6c 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 5dc5ab08da..6bf61a194c 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<const MCFragment*, MCSymbolData*> 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 4b51b69dc2..231f151206 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<const MCSectionELF&>(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 bc9ec13186..1aa43f7884 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 0000000000..82e1d88696
--- /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'