Move ELF to HasReliableSymbolDifference=true. Also take the opportunity to put

symbols defined in merge sections in independent atoms.

llvm-svn: 114786
This commit is contained in:
Rafael Espindola 2010-09-25 05:42:19 +00:00
parent b590a927cd
commit 75d65b9a03
5 changed files with 105 additions and 12 deletions

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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 {

View File

@ -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)

26
llvm/test/MC/ELF/merge.s Normal file
View File

@ -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'