diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2009-07-21 06:51:32 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2009-07-21 06:51:32 +0000 |
commit | 68491c12179f963b346aa4cb8e1b924184d79970 (patch) | |
tree | b1c556d30ff436e16f321632a9ac977532824adf /lib | |
parent | 634d61b13500764a506100eb5115b1afe1e427eb (diff) | |
download | external_llvm-68491c12179f963b346aa4cb8e1b924184d79970.zip external_llvm-68491c12179f963b346aa4cb8e1b924184d79970.tar.gz external_llvm-68491c12179f963b346aa4cb8e1b924184d79970.tar.bz2 |
Support adding relocations for data sections, handling the cases where
global declared symbols are initialized with references from other global
symbols.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76540 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/ELFCodeEmitter.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/ELFWriter.cpp | 72 | ||||
-rw-r--r-- | lib/CodeGen/ELFWriter.h | 5 | ||||
-rw-r--r-- | lib/Target/X86/X86ELFWriterInfo.cpp | 4 |
4 files changed, 60 insertions, 25 deletions
diff --git a/lib/CodeGen/ELFCodeEmitter.cpp b/lib/CodeGen/ELFCodeEmitter.cpp index 23210fc..c77334a 100644 --- a/lib/CodeGen/ELFCodeEmitter.cpp +++ b/lib/CodeGen/ELFCodeEmitter.cpp @@ -68,6 +68,10 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { FnSym->SectionIdx = ES->SectionIdx; 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 FnSym->Value = FnStartOff; diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index f04efd5..f4cd94a 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -240,30 +240,31 @@ static bool isELFUndefSym(const GlobalValue *GV) { // 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. -static bool isELFBssSym(const GlobalValue *GV) { - return (!GV->isDeclaration() && - (GV->isNullValue() || isa<UndefValue>(GV)) && - !GV->isWeakForLinker()); +static bool isELFBssSym(const GlobalVariable *GV) { + const Constant *CV = GV->getInitializer(); + return ((CV->isNullValue() || isa<UndefValue>(CV)) && !GV->isWeakForLinker()); } // isELFCommonSym - for an undef or null value, the symbol must go to a // common section if it's weak for linker, otherwise bss. -static bool isELFCommonSym(const GlobalValue *GV) { - return (!GV->isDeclaration() && - (GV->isNullValue() || isa<UndefValue>(GV)) - && GV->isWeakForLinker()); +static bool isELFCommonSym(const GlobalVariable *GV) { + const Constant *CV = GV->getInitializer(); + return ((CV->isNullValue() || isa<UndefValue>(CV)) && GV->isWeakForLinker()); } // isELFDataSym - if the symbol is an initialized but no null constant // it must go to some kind of data section gathered from TAI -static bool isELFDataSym(const GlobalValue *GV) { - return (!GV->isDeclaration() && - !(GV->isNullValue() || isa<UndefValue>(GV))); +static bool isELFDataSym(const Constant *CV) { + return (!(CV->isNullValue() || isa<UndefValue>(CV))); } // EmitGlobal - Choose the right section for global and emit it 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 unsigned SymBind = getGlobalELFBinding(GV); ELFSym *GblSym = new ELFSym(GV); @@ -287,7 +288,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { unsigned Size = TD->getTypeAllocSize(GVar->getInitializer()->getType()); GblSym->Size = Size; - if (isELFCommonSym(GV)) { + if (isELFCommonSym(GVar)) { GblSym->SectionIdx = ELFSection::SHN_COMMON; getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags, 1); @@ -296,7 +297,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { // value contains its alignment. GblSym->Value = Align; - } else if (isELFBssSym(GV)) { + } else if (isELFBssSym(GVar)) { ELFSection &ES = getSection(S->getName(), ELFSection::SHT_NOBITS, SectionFlags); GblSym->SectionIdx = ES.SectionIdx; @@ -336,7 +337,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { SymbolList.push_back(GblSym); } - GblSymLookup[GV] = SymIdx; + setGlobalSymLookup(GV, SymIdx); } 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) EmitGlobalConstant(CP->getOperand(I), GblS); 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; + } + // See AsmPrinter::EmitConstantValueOnly for other ConstantExpr types + llvm_unreachable("Unsupported ConstantExpr type"); } - llvm_unreachable("unknown global constant"); + + llvm_unreachable("Unknown global constant type"); } @@ -431,19 +461,13 @@ bool ELFWriter::doFinalization(Module &M) { // Build and emit data, bss and "common" sections. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) { + I != E; ++I) EmitGlobal(I); - } // Emit all pending globals - // TODO: this should be done only for referenced symbols for (SetVector<GlobalValue*>::const_iterator I = PendingGlobals.begin(), - E = PendingGlobals.end(); I != E; ++I) { - // No need to emit the symbol again - if (GblSymLookup.find(*I) != GblSymLookup.end()) - continue; + E = PendingGlobals.end(); I != E; ++I) EmitGlobal(*I); - } // Emit non-executable stack note if (TAI->getNonexecutableStackDirective()) @@ -731,7 +755,7 @@ void ELFWriter::EmitSymbolTable() { EmitSymbol(SymTab, Sym); // 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 Sym.SymTabIdx = i; diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index 34f8276..6f083b92 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -211,6 +211,11 @@ namespace llvm { unsigned getGlobalELFVisibility(const GlobalValue *GV); 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 // (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 diff --git a/lib/Target/X86/X86ELFWriterInfo.cpp b/lib/Target/X86/X86ELFWriterInfo.cpp index 618cc5b..096c00e 100644 --- a/lib/Target/X86/X86ELFWriterInfo.cpp +++ b/lib/Target/X86/X86ELFWriterInfo.cpp @@ -64,7 +64,9 @@ long int X86ELFWriterInfo::getDefaultAddendForRelTy(unsigned RelTy) const { if (is64Bit) { switch(RelTy) { 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: llvm_unreachable("unknown x86_64 relocation type"); } |