From 80ed8faaea095ec269a06d97f1de1f04474bea66 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Thu, 7 Jul 2005 07:02:20 +0000 Subject: [PATCH] Add support for emitting the symbol table (and its string table) of the module to the ELF file. Test it by adding support for emitting common symbols. This allows us to compile this: %X = weak global int 0 %Y = weak global int 0 %Z = weak global int 0 to an elf file that 'readelf's this: Symbol table '.symtab' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000004 4 OBJECT GLOBAL DEFAULT COM X 2: 00000004 4 OBJECT GLOBAL DEFAULT COM Y 3: 00000004 4 OBJECT GLOBAL DEFAULT COM Z git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22343 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/ELFWriter.cpp | 195 +++++++++++++++++++++++++++++++++------------- 1 file changed, 141 insertions(+), 54 deletions(-) diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index 268e4cc1a63..02cd805cb55 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -11,17 +11,18 @@ // the ELF file in the following order: // // #1. ELF Header -// #2. '.data' section -// #3. '.bss' section +// #2. '.text' section +// #3. '.data' section +// #4. '.bss' section (conceptual position in file) // ... // #X. '.shstrtab' section // #Y. Section Table // // The entries in the section table are laid out as: // #0. Null entry [required] -// #1. ".data" entry - global variables with initializers. [ if needed ] -// #2. ".bss" entry - global variables without initializers. [ if needed ] -// #3. ".text" entry - the program code +// #1. ".text" entry - the program code +// #2. ".data" entry - global variables with initializers. [ if needed ] +// #3. ".bss" entry - global variables without initializers. [ if needed ] // ... // #N. ".shstrtab" entry - String table for the section names. @@ -83,62 +84,50 @@ bool ELFWriter::doInitialization(Module &M) { // Add the null section. SectionList.push_back(ELFSection()); - // Okay, the ELF header has been completed, emit the .data section next. - ELFSection DataSection(".data", OutputBuffer.size()); - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - EmitDATASectionGlobal(I); - - // If the .data section is nonempty, add it to our list. - if ((DataSection.Size = OutputBuffer.size()-DataSection.Offset)) { - DataSection.Align = 4; // FIXME: Compute! - SectionList.push_back(DataSection); - } + // Start up the symbol table. The first entry in the symtab is the null + // entry. + SymbolTable.push_back(ELFSym(0)); - // Okay, emit the .bss section next. - ELFSection BSSSection(".bss", OutputBuffer.size()); - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - EmitBSSSectionGlobal(I); - // If the .bss section is nonempty, add it to our list. - if ((BSSSection.Size = OutputBuffer.size()-BSSSection.Offset)) { - BSSSection.Align = 4; // FIXME: Compute! - SectionList.push_back(BSSSection); - } + // FIXME: Should start the .text section. return false; } -// isCOMM - A global variable should be emitted to the common area if it is zero -// initialized and has linkage that permits it to be merged with other globals. -static bool isCOMM(GlobalVariable *GV) { - return GV->getInitializer()->isNullValue() && - (GV->hasLinkOnceLinkage() || GV->hasInternalLinkage() || - GV->hasWeakLinkage()); -} - -// EmitDATASectionGlobal - Emit a global variable to the .data section if it -// belongs there. -void ELFWriter::EmitDATASectionGlobal(GlobalVariable *GV) { - if (!GV->hasInitializer()) return; - - // Do not emit a symbol here if it should be emitted to the common area. - if (isCOMM(GV)) return; - - EmitGlobal(GV); -} - -void ELFWriter::EmitBSSSectionGlobal(GlobalVariable *GV) { - if (!GV->hasInitializer()) return; - - // FIXME: We don't support BSS yet! - return; +void ELFWriter::EmitGlobal(GlobalVariable *GV, ELFSection &DataSection, + ELFSection &BSSSection) { + // If this is an external global, emit it... + assert(GV->hasInitializer() && "FIXME: unimp"); + + // If this global has a zero initializer, it is part of the .bss or common + // section. + if (GV->getInitializer()->isNullValue()) { + // If this global is part of the common block, add it now. Variables are + // part of the common block if they are zero initialized and allowed to be + // merged with other symbols. + if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage()) { + ELFSym CommonSym(GV); + // Value for common symbols is the alignment required. + const Type *GVType = (const Type*)GV->getType(); + CommonSym.Value = TM.getTargetData().getTypeAlignment(GVType); + CommonSym.Size = TM.getTargetData().getTypeSize(GVType); + CommonSym.SetBind(ELFSym::STB_GLOBAL); + CommonSym.SetType(ELFSym::STT_OBJECT); + // TODO SOMEDAY: add ELF visibility. + CommonSym.SectionIdx = ELFSection::SHN_COMMON; + SymbolTable.push_back(CommonSym); + return; + } + + // FIXME: Implement the .bss section. + return; + } - EmitGlobal(GV); -} + // FIXME: handle .rodata + //assert(!GV->isConstant() && "unimp"); -void ELFWriter::EmitGlobal(GlobalVariable *GV) { + // FIXME: handle .data + //assert(0 && "unimp"); } @@ -149,6 +138,37 @@ bool ELFWriter::runOnMachineFunction(MachineFunction &MF) { /// doFinalization - Now that the module has been completely processed, emit /// the ELF file to 'O'. bool ELFWriter::doFinalization(Module &M) { + // Okay, the .text section has now been finalized. + // FIXME: finalize the .text section. + + // Okay, the ELF header and .text sections have been completed, build the + // .data, .bss, and "common" sections next. + ELFSection DataSection(".data", OutputBuffer.size()); + ELFSection BSSSection (".bss"); + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) + EmitGlobal(I, DataSection, BSSSection); + + // If the .data section is nonempty, add it to our list. + if (DataSection.Size) { + DataSection.Align = 4; // FIXME: Compute! + // FIXME: Set the right flags and stuff. + SectionList.push_back(DataSection); + } + + // If the .bss section is nonempty, add it to our list. + if (BSSSection.Size) { + BSSSection.Offset = OutputBuffer.size(); + BSSSection.Align = 4; // FIXME: Compute! + // FIXME: Set the right flags and stuff. + SectionList.push_back(BSSSection); + } + + // Emit the symbol table now, if non-empty. + EmitSymbolTable(); + + // FIXME: Emit the relocations now. + // Emit the string table for the sections in the ELF file we have. EmitSectionTableStringTable(); @@ -163,13 +183,80 @@ bool ELFWriter::doFinalization(Module &M) { return false; } +/// EmitSymbolTable - If the current symbol table is non-empty, emit the string +/// table for it and then the symbol table itself. +void ELFWriter::EmitSymbolTable() { + if (SymbolTable.size() == 1) return; // Only the null entry. + + // FIXME: compact all local symbols to the start of the symtab. + unsigned FirstNonLocalSymbol = 1; + + SectionList.push_back(ELFSection(".strtab", OutputBuffer.size())); + ELFSection &StrTab = SectionList.back(); + StrTab.Type = ELFSection::SHT_STRTAB; + StrTab.Align = 1; + + // Set the zero'th symbol to a null byte, as required. + outbyte(0); + SymbolTable[0].NameIdx = 0; + unsigned Index = 1; + for (unsigned i = 1, e = SymbolTable.size(); i != e; ++i) { + // FIXME: USE A MANGLER!! + const std::string &Name = SymbolTable[i].GV->getName(); + + if (Name.empty()) { + SymbolTable[i].NameIdx = 0; + } else { + SymbolTable[i].NameIdx = Index; + + // Add the name to the output buffer, including the null terminator. + OutputBuffer.insert(OutputBuffer.end(), Name.begin(), Name.end()); + + // Add a null terminator. + OutputBuffer.push_back(0); + + // Keep track of the number of bytes emitted to this section. + Index += Name.size()+1; + } + } + + StrTab.Size = OutputBuffer.size()-StrTab.Offset; + + // Now that we have emitted the string table and know the offset into the + // string table of each symbol, emit the symbol table itself. + assert(!is64Bit && "Should this be 8 byte aligned for 64-bit?" + " (check .Align below also)"); + align(4); + + SectionList.push_back(ELFSection(".symtab", OutputBuffer.size())); + ELFSection &SymTab = SectionList.back(); + SymTab.Type = ELFSection::SHT_SYMTAB; + SymTab.Align = 4; // FIXME: check for ELF64 + SymTab.Link = SectionList.size()-2; // Section Index of .strtab. + SymTab.Info = FirstNonLocalSymbol; // First non-STB_LOCAL symbol. + SymTab.EntSize = 16; // Size of each symtab entry. FIXME: wrong for ELF64 + + assert(!is64Bit && "check this!"); + for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) { + ELFSym &Sym = SymbolTable[i]; + outword(Sym.NameIdx); + outaddr(Sym.Value); + outword(Sym.Size); + outbyte(Sym.Info); + outbyte(Sym.Other); + outhalf(Sym.SectionIdx); + } + + SymTab.Size = OutputBuffer.size()-SymTab.Offset; +} + /// EmitSectionTableStringTable - This method adds and emits a section for the /// ELF Section Table string table: the string table that holds all of the /// section names. void ELFWriter::EmitSectionTableStringTable() { // First step: add the section for the string table to the list of sections: SectionList.push_back(ELFSection(".shstrtab", OutputBuffer.size())); - SectionList.back().Type = 3; // SHT_STRTAB + SectionList.back().Type = ELFSection::SHT_STRTAB; // Now that we know which section number is the .shstrtab section, update the // e_shstrndx entry in the ELF header. -- 2.11.0