Support adding relocations for data sections, handling the cases where

global declared symbols are initialized with references from other global
symbols.

llvm-svn: 76540
This commit is contained in:
Bruno Cardoso Lopes 2009-07-21 06:51:32 +00:00
parent 11982922be
commit 12e543228d
4 changed files with 60 additions and 25 deletions

View File

@ -68,6 +68,10 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) {
FnSym->SectionIdx = ES->SectionIdx; FnSym->SectionIdx = ES->SectionIdx;
FnSym->Size = ES->getCurrentPCOffset()-FnStartOff; FnSym->Size = ES->getCurrentPCOffset()-FnStartOff;
// keep track of the emitted function leaving its symbol index as zero
// to be patched up later when emitting the symbol table
EW.setGlobalSymLookup(F, 0);
// Offset from start of Section // Offset from start of Section
FnSym->Value = FnStartOff; FnSym->Value = FnStartOff;

View File

@ -240,30 +240,31 @@ static bool isELFUndefSym(const GlobalValue *GV) {
// isELFBssSym - for an undef or null value, the symbol must go to a bss // isELFBssSym - for an undef or null value, the symbol must go to a bss
// section if it's not weak for linker, otherwise it's a common sym. // section if it's not weak for linker, otherwise it's a common sym.
static bool isELFBssSym(const GlobalValue *GV) { static bool isELFBssSym(const GlobalVariable *GV) {
return (!GV->isDeclaration() && const Constant *CV = GV->getInitializer();
(GV->isNullValue() || isa<UndefValue>(GV)) && return ((CV->isNullValue() || isa<UndefValue>(CV)) && !GV->isWeakForLinker());
!GV->isWeakForLinker());
} }
// isELFCommonSym - for an undef or null value, the symbol must go to a // isELFCommonSym - for an undef or null value, the symbol must go to a
// common section if it's weak for linker, otherwise bss. // common section if it's weak for linker, otherwise bss.
static bool isELFCommonSym(const GlobalValue *GV) { static bool isELFCommonSym(const GlobalVariable *GV) {
return (!GV->isDeclaration() && const Constant *CV = GV->getInitializer();
(GV->isNullValue() || isa<UndefValue>(GV)) return ((CV->isNullValue() || isa<UndefValue>(CV)) && GV->isWeakForLinker());
&& GV->isWeakForLinker());
} }
// isELFDataSym - if the symbol is an initialized but no null constant // isELFDataSym - if the symbol is an initialized but no null constant
// it must go to some kind of data section gathered from TAI // it must go to some kind of data section gathered from TAI
static bool isELFDataSym(const GlobalValue *GV) { static bool isELFDataSym(const Constant *CV) {
return (!GV->isDeclaration() && return (!(CV->isNullValue() || isa<UndefValue>(CV)));
!(GV->isNullValue() || isa<UndefValue>(GV)));
} }
// EmitGlobal - Choose the right section for global and emit it // EmitGlobal - Choose the right section for global and emit it
void ELFWriter::EmitGlobal(const GlobalValue *GV) { void ELFWriter::EmitGlobal(const GlobalValue *GV) {
// Check if the referenced symbol is already emitted
if (GblSymLookup.find(GV) != GblSymLookup.end())
return;
// Handle ELF Bind, Visibility and Type for the current symbol // Handle ELF Bind, Visibility and Type for the current symbol
unsigned SymBind = getGlobalELFBinding(GV); unsigned SymBind = getGlobalELFBinding(GV);
ELFSym *GblSym = new ELFSym(GV); ELFSym *GblSym = new ELFSym(GV);
@ -287,7 +288,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) {
unsigned Size = TD->getTypeAllocSize(GVar->getInitializer()->getType()); unsigned Size = TD->getTypeAllocSize(GVar->getInitializer()->getType());
GblSym->Size = Size; GblSym->Size = Size;
if (isELFCommonSym(GV)) { if (isELFCommonSym(GVar)) {
GblSym->SectionIdx = ELFSection::SHN_COMMON; GblSym->SectionIdx = ELFSection::SHN_COMMON;
getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags, 1); getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags, 1);
@ -296,7 +297,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) {
// value contains its alignment. // value contains its alignment.
GblSym->Value = Align; GblSym->Value = Align;
} else if (isELFBssSym(GV)) { } else if (isELFBssSym(GVar)) {
ELFSection &ES = ELFSection &ES =
getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags); getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags);
GblSym->SectionIdx = ES.SectionIdx; GblSym->SectionIdx = ES.SectionIdx;
@ -336,7 +337,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) {
SymbolList.push_back(GblSym); SymbolList.push_back(GblSym);
} }
GblSymLookup[GV] = SymIdx; setGlobalSymLookup(GV, SymIdx);
} }
void ELFWriter::EmitGlobalConstantStruct(const ConstantStruct *CVS, void ELFWriter::EmitGlobalConstantStruct(const ConstantStruct *CVS,
@ -410,8 +411,37 @@ void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) {
for (unsigned I = 0, E = PTy->getNumElements(); I < E; ++I) for (unsigned I = 0, E = PTy->getNumElements(); I < E; ++I)
EmitGlobalConstant(CP->getOperand(I), GblS); EmitGlobalConstant(CP->getOperand(I), GblS);
return; return;
} else if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
// This is a constant address for a global variable or function and
// therefore must be referenced using a relocation entry.
// Check if the referenced symbol is already emitted
if (GblSymLookup.find(GV) == GblSymLookup.end())
EmitGlobal(GV);
// Create the relocation entry for the global value
MachineRelocation MR =
MachineRelocation::getGV(GblS.getCurrentPCOffset(),
TEW->getAbsoluteLabelMachineRelTy(),
const_cast<GlobalValue*>(GV));
// Fill the data entry with zeros
for (unsigned i=0; i < Size; ++i)
GblS.emitByte(0);
// Add the relocation entry for the current data section
GblS.addRelocation(MR);
return;
} else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
if (CE->getOpcode() == Instruction::BitCast) {
EmitGlobalConstant(CE->getOperand(0), GblS);
return;
} }
llvm_unreachable("unknown global constant"); // See AsmPrinter::EmitConstantValueOnly for other ConstantExpr types
llvm_unreachable("Unsupported ConstantExpr type");
}
llvm_unreachable("Unknown global constant type");
} }
@ -431,19 +461,13 @@ bool ELFWriter::doFinalization(Module &M) {
// Build and emit data, bss and "common" sections. // Build and emit data, bss and "common" sections.
for (Module::global_iterator I = M.global_begin(), E = M.global_end(); for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) { I != E; ++I)
EmitGlobal(I); EmitGlobal(I);
}
// Emit all pending globals // Emit all pending globals
// TODO: this should be done only for referenced symbols
for (SetVector<GlobalValue*>::const_iterator I = PendingGlobals.begin(), for (SetVector<GlobalValue*>::const_iterator I = PendingGlobals.begin(),
E = PendingGlobals.end(); I != E; ++I) { E = PendingGlobals.end(); I != E; ++I)
// No need to emit the symbol again
if (GblSymLookup.find(*I) != GblSymLookup.end())
continue;
EmitGlobal(*I); EmitGlobal(*I);
}
// Emit non-executable stack note // Emit non-executable stack note
if (TAI->getNonexecutableStackDirective()) if (TAI->getNonexecutableStackDirective())
@ -731,7 +755,7 @@ void ELFWriter::EmitSymbolTable() {
EmitSymbol(SymTab, Sym); EmitSymbol(SymTab, Sym);
// Record the symbol table index for each global value // Record the symbol table index for each global value
if (Sym.GV) GblSymLookup[Sym.GV] = i; if (Sym.GV) setGlobalSymLookup(Sym.GV, i);
// Keep track on the symbol index into the symbol table // Keep track on the symbol index into the symbol table
Sym.SymTabIdx = i; Sym.SymTabIdx = i;

View File

@ -211,6 +211,11 @@ namespace llvm {
unsigned getGlobalELFVisibility(const GlobalValue *GV); unsigned getGlobalELFVisibility(const GlobalValue *GV);
unsigned getElfSectionFlags(unsigned Flags); unsigned getElfSectionFlags(unsigned Flags);
// setGlobalSymLookup - Set global value 'GV' with 'Index' in the lookup map
void setGlobalSymLookup(const GlobalValue *GV, unsigned Index) {
GblSymLookup[GV] = Index;
}
// As we complete the ELF file, we need to update fields in the ELF header // As we complete the ELF file, we need to update fields in the ELF header
// (e.g. the location of the section table). These members keep track of // (e.g. the location of the section table). These members keep track of
// the offset in ELFHeader of these various pieces to update and other // the offset in ELFHeader of these various pieces to update and other

View File

@ -64,7 +64,9 @@ long int X86ELFWriterInfo::getDefaultAddendForRelTy(unsigned RelTy) const {
if (is64Bit) { if (is64Bit) {
switch(RelTy) { switch(RelTy) {
case R_X86_64_PC32: return -4; case R_X86_64_PC32: return -4;
case R_X86_64_32: return 0; case R_X86_64_32:
case R_X86_64_64:
return 0;
default: default:
llvm_unreachable("unknown x86_64 relocation type"); llvm_unreachable("unknown x86_64 relocation type");
} }