Add support for emitting the symbol table (and its string table) of the
authorChris Lattner <sabre@nondot.org>
Thu, 7 Jul 2005 07:02:20 +0000 (07:02 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 7 Jul 2005 07:02:20 +0000 (07:02 +0000)
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

index 268e4cc1a63ea185c57b25b73ad15ce9bba21aa9..02cd805cb55549480757034d43648ba8401f0c9d 100644 (file)
 // 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.