[llvm-commits] CVS: llvm/lib/CodeGen/ELFWriter.cpp

Chris Lattner lattner at cs.uiuc.edu
Sat Jul 16 01:01:24 PDT 2005



Changes in directory llvm/lib/CodeGen:

ELFWriter.cpp updated: 1.9 -> 1.10
---
Log message:

Major refactor of the ELFWriter code.  Instead of building up one big
vector that represents the .o file at once, build up a vector for each
section of the .o file.  This is needed because the .o file writer needs
to be able to switch between sections as it emits them (e.g. switch
between the .text section and the .rel section when emitting code).

This patch has no functionality change.


---
Diffs of the changes:  (+173 -149)

 ELFWriter.cpp |  322 +++++++++++++++++++++++++++++++---------------------------
 1 files changed, 173 insertions(+), 149 deletions(-)


Index: llvm/lib/CodeGen/ELFWriter.cpp
diff -u llvm/lib/CodeGen/ELFWriter.cpp:1.9 llvm/lib/CodeGen/ELFWriter.cpp:1.10
--- llvm/lib/CodeGen/ELFWriter.cpp:1.9	Tue Jul 12 01:57:52 2005
+++ llvm/lib/CodeGen/ELFWriter.cpp	Sat Jul 16 03:01:13 2005
@@ -49,10 +49,11 @@
   /// functions to the ELF file.
   class ELFCodeEmitter : public MachineCodeEmitter {
     ELFWriter &EW;
-    std::vector<unsigned char> &OutputBuffer;
+    ELFWriter::ELFSection *ES;  // Section to write to.
+    std::vector<unsigned char> *OutBuffer;
     size_t FnStart;
   public:
-    ELFCodeEmitter(ELFWriter &ew) : EW(ew), OutputBuffer(EW.OutputBuffer) {}
+    ELFCodeEmitter(ELFWriter &ew) : EW(ew), OutBuffer(0) {}
 
     void startFunction(MachineFunction &F);
     void finishFunction(MachineFunction &F);
@@ -62,7 +63,7 @@
       assert(0 && "unimp");
     }
     virtual void emitByte(unsigned char B) {
-      OutputBuffer.push_back(B);
+      OutBuffer->push_back(B);
     }
     virtual void emitWordAt(unsigned W, unsigned *Ptr) {
       assert(0 && "ni");
@@ -71,10 +72,10 @@
       assert(0 && "ni");
     }
     virtual uint64_t getCurrentPCValue() {
-      return OutputBuffer.size();
+      return OutBuffer->size();
     }
     virtual uint64_t getCurrentPCOffset() {
-      return OutputBuffer.size()-FnStart;
+      return OutBuffer->size()-FnStart;
     }
     void addRelocation(const MachineRelocation &MR) {
       assert(0 && "relo not handled yet!");
@@ -102,21 +103,22 @@
 void ELFCodeEmitter::startFunction(MachineFunction &F) {
   // Align the output buffer to the appropriate alignment.
   unsigned Align = 16;   // FIXME: GENERICIZE!!
-  ELFWriter::ELFSection &TextSection = EW.SectionList.back();
+  // Get the ELF Section that this function belongs in.
+  ES = &EW.getSection(".text");
+  ES->Type  = ELFWriter::ELFSection::SHT_PROGBITS;
+  ES->Flags = ELFWriter::ELFSection::SHF_EXECINSTR |
+              ELFWriter::ELFSection::SHF_ALLOC;
+  OutBuffer = &ES->SectionData;
   
   // Upgrade the section alignment if required.
-  if (TextSection.Align < Align) TextSection.Align = Align;
+  if (ES->Align < Align) ES->Align = Align;
   
   // Add padding zeros to the end of the buffer to make sure that the
   // function will start on the correct byte alignment within the section.
-  size_t SectionOff = OutputBuffer.size()-TextSection.Offset;
-  if (SectionOff & (Align-1)) {
-    // Add padding to get alignment to the correct place.
-    size_t Pad = Align-(SectionOff & (Align-1));
-    OutputBuffer.resize(OutputBuffer.size()+Pad);
-  }
+  size_t SectionOff = OutBuffer->size();
+  ELFWriter::align(*OutBuffer, Align);
   
-  FnStart = OutputBuffer.size();
+  FnStart = OutBuffer->size();
 }
 
 /// finishFunction - This callback is invoked after the function is completely
@@ -141,12 +143,13 @@
     FnSym.SetBind(ELFWriter::ELFSym::STB_LOCAL);
     break;
   }
-  
+
+  ES->Size = OutBuffer->size();
+
   FnSym.SetType(ELFWriter::ELFSym::STT_FUNC);
-  FnSym.SectionIdx = EW.SectionList.size()-1;  // .text section.
-  // Value = Offset from start of .text
-  FnSym.Value = FnStart - EW.SectionList.back().Offset;
-  FnSym.Size = OutputBuffer.size()-FnStart;
+  FnSym.SectionIdx = ES->SectionIdx;
+    FnSym.Value = FnStart;   // Value = Offset from start of Section.
+  FnSym.Size = OutBuffer->size()-FnStart;
   
   // Finally, add it to the symtab.
   EW.SymbolTable.push_back(FnSym);
@@ -165,6 +168,7 @@
 
   // Create the machine code emitter object for this target.
   MCE = new ELFCodeEmitter(*this);
+  NumSections = 0;
 }
 
 ELFWriter::~ELFWriter() {
@@ -176,47 +180,47 @@
 bool ELFWriter::doInitialization(Module &M) {
   Mang = new Mangler(M);
 
-  outbyte(0x7F);                     // EI_MAG0
-  outbyte('E');                      // EI_MAG1
-  outbyte('L');                      // EI_MAG2
-  outbyte('F');                      // EI_MAG3
-  outbyte(is64Bit ? 2 : 1);          // EI_CLASS
-  outbyte(isLittleEndian ? 1 : 2);   // EI_DATA
-  outbyte(1);                        // EI_VERSION
-  for (unsigned i = OutputBuffer.size(); i != 16; ++i)
-    outbyte(0);                      // EI_PAD up to 16 bytes.
+  // Local alias to shortenify coming code.
+  std::vector<unsigned char> &FH = FileHeader;
+    
+  outbyte(FH, 0x7F);                     // EI_MAG0
+  outbyte(FH, 'E');                      // EI_MAG1
+  outbyte(FH, 'L');                      // EI_MAG2
+  outbyte(FH, 'F');                      // EI_MAG3
+  outbyte(FH, is64Bit ? 2 : 1);          // EI_CLASS
+  outbyte(FH, isLittleEndian ? 1 : 2);   // EI_DATA
+  outbyte(FH, 1);                        // EI_VERSION
+  FH.resize(16);                         // EI_PAD up to 16 bytes.
   
   // This should change for shared objects.
-  outhalf(1);                        // e_type = ET_REL
-  outhalf(e_machine);                // e_machine = whatever the target wants
-  outword(1);                        // e_version = 1
-  outaddr(0);                        // e_entry = 0 -> no entry point in .o file
-  outaddr(0);                        // e_phoff = 0 -> no program header for .o
-
-  ELFHeader_e_shoff_Offset = OutputBuffer.size();
-  outaddr(0);                        // e_shoff
-  outword(e_flags);                  // e_flags = whatever the target wants
-
-  outhalf(is64Bit ? 64 : 52);        // e_ehsize = ELF header size
-  outhalf(0);                        // e_phentsize = prog header entry size
-  outhalf(0);                        // e_phnum     = # prog header entries = 0
-  outhalf(is64Bit ? 64 : 40);        // e_shentsize = sect header entry size
-
-  
-  ELFHeader_e_shnum_Offset = OutputBuffer.size();
-  outhalf(0);                        // e_shnum     = # of section header ents
-  ELFHeader_e_shstrndx_Offset = OutputBuffer.size();
-  outhalf(0);                        // e_shstrndx  = Section # of '.shstrtab'
+  outhalf(FH, 1);                 // e_type = ET_REL
+  outhalf(FH, e_machine);         // e_machine = whatever the target wants
+  outword(FH, 1);                 // e_version = 1
+  outaddr(FH, 0);                 // e_entry = 0 -> no entry point in .o file
+  outaddr(FH, 0);                 // e_phoff = 0 -> no program header for .o
+
+  ELFHeader_e_shoff_Offset = FH.size();
+  outaddr(FH, 0);                 // e_shoff
+  outword(FH, e_flags);           // e_flags = whatever the target wants
+
+  outhalf(FH, is64Bit ? 64 : 52); // e_ehsize = ELF header size
+  outhalf(FH, 0);                 // e_phentsize = prog header entry size
+  outhalf(FH, 0);                 // e_phnum     = # prog header entries = 0
+  outhalf(FH, is64Bit ? 64 : 40); // e_shentsize = sect hdr entry size
+
+  
+  ELFHeader_e_shnum_Offset = FH.size();
+  outhalf(FH, 0);                 // e_shnum     = # of section header ents
+  ELFHeader_e_shstrndx_Offset = FH.size();
+  outhalf(FH, 0);                 // e_shstrndx  = Section # of '.shstrtab'
 
-  // Add the null section.
-  SectionList.push_back(ELFSection());
+  // Add the null section, which is required to be first in the file.
+  getSection("");
 
   // Start up the symbol table.  The first entry in the symtab is the null
   // entry.
   SymbolTable.push_back(ELFSym(0));
 
-  SectionList.push_back(ELFSection(".text", OutputBuffer.size()));
-
   return false;
 }
 
@@ -286,7 +290,7 @@
     }
 
     // Set the idx of the .bss section
-    BSSSym.SectionIdx = &BSSSection-&SectionList[0];
+    BSSSym.SectionIdx = BSSSection.SectionIdx;
     SymbolTable.push_back(BSSSym);
 
     // Reserve space in the .bss section for this symbol.
@@ -310,40 +314,19 @@
 /// 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.  If it contains nothing, do
-  // not emit it.
-  uint64_t TextSize = OutputBuffer.size() - SectionList.back().Offset;
-  if (TextSize == 0) {
-    SectionList.pop_back();
-  } else {
-    ELFSection &Text = SectionList.back();
-    Text.Size = TextSize;
-    Text.Type = ELFSection::SHT_PROGBITS;
-    Text.Flags = ELFSection::SHF_EXECINSTR | ELFSection::SHF_ALLOC;
-  }
-
   // Okay, the ELF header and .text sections have been completed, build the
   // .data, .bss, and "common" sections next.
-  SectionList.push_back(ELFSection(".data", OutputBuffer.size()));
-  SectionList.push_back(ELFSection(".bss"));
-  ELFSection &DataSection = *(SectionList.end()-2);
-  ELFSection &BSSSection = SectionList.back();
-  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
-       I != E; ++I)
-    EmitGlobal(I, DataSection, BSSSection);
-
-  // Finish up the data section.
+  ELFSection &DataSection = getSection(".data");
   DataSection.Type  = ELFSection::SHT_PROGBITS;
   DataSection.Flags = ELFSection::SHF_WRITE | ELFSection::SHF_ALLOC;
 
-  // The BSS Section logically starts at the end of the Data Section (adjusted
-  // to the required alignment of the BSSSection).
-  BSSSection.Offset = DataSection.Offset+DataSection.Size;
+  ELFSection &BSSSection = getSection(".bss");
   BSSSection.Type   = ELFSection::SHT_NOBITS; 
   BSSSection.Flags  = ELFSection::SHF_WRITE | ELFSection::SHF_ALLOC;
-  if (BSSSection.Align)
-    BSSSection.Offset = (BSSSection.Offset+BSSSection.Align-1) &
-                        ~(BSSSection.Align-1);
+
+  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
+       I != E; ++I)
+    EmitGlobal(I, DataSection, BSSSection);
 
   // Emit the symbol table now, if non-empty.
   EmitSymbolTable();
@@ -353,14 +336,12 @@
   // Emit the string table for the sections in the ELF file we have.
   EmitSectionTableStringTable();
 
-  // Emit the .o file section table.
-  EmitSectionTable();
+  // Emit the sections to the .o file, and emit the section table for the file.
+  OutputSectionsAndSectionTable();
 
-  // Emit the .o file to the specified stream.
-  O.write((char*)&OutputBuffer[0], OutputBuffer.size());
-
-  // Free the output buffer.
-  std::vector<unsigned char>().swap(OutputBuffer);
+  // We are done with the abstract symbols.
+  SectionList.clear();
+  NumSections = 0;
 
   // Release the name mangler object.
   delete Mang; Mang = 0;
@@ -375,13 +356,14 @@
   // 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();
+  ELFSection &StrTab = getSection(".strtab");
   StrTab.Type = ELFSection::SHT_STRTAB;
   StrTab.Align = 1;
 
+  DataBuffer &StrTabBuf = StrTab.SectionData;
+
   // Set the zero'th symbol to a null byte, as required.
-  outbyte(0);
+  outbyte(StrTabBuf, 0);
   SymbolTable[0].NameIdx = 0;
   unsigned Index = 1;
   for (unsigned i = 1, e = SymbolTable.size(); i != e; ++i) {
@@ -394,53 +376,51 @@
       SymbolTable[i].NameIdx = Index;
 
       // Add the name to the output buffer, including the null terminator.
-      OutputBuffer.insert(OutputBuffer.end(), Name.begin(), Name.end());
+      StrTabBuf.insert(StrTabBuf.end(), Name.begin(), Name.end());
 
       // Add a null terminator.
-      OutputBuffer.push_back(0);
+      StrTabBuf.push_back(0);
 
       // Keep track of the number of bytes emitted to this section.
       Index += Name.size()+1;
     }
   }
-
-  StrTab.Size = OutputBuffer.size()-StrTab.Offset;
+  assert(Index == StrTabBuf.size());
+  StrTab.Size = Index;
 
   // Now that we have emitted the string table and know the offset into the
   // string table of each symbol, emit the symbol table itself.
-  align(is64Bit ? 8 : 4);
-
-  SectionList.push_back(ELFSection(".symtab", OutputBuffer.size()));
-  ELFSection &SymTab = SectionList.back();
+  ELFSection &SymTab = getSection(".symtab");
   SymTab.Type = ELFSection::SHT_SYMTAB;
   SymTab.Align = is64Bit ? 8 : 4;
-  SymTab.Link = SectionList.size()-2;  // Section Index of .strtab.
+  SymTab.Link = SymTab.SectionIdx;     // Section Index of .strtab.
   SymTab.Info = FirstNonLocalSymbol;   // First non-STB_LOCAL symbol.
   SymTab.EntSize = 16; // Size of each symtab entry. FIXME: wrong for ELF64
+  DataBuffer &SymTabBuf = SymTab.SectionData;
 
   if (!is64Bit) {   // 32-bit and 64-bit formats are shuffled a bit.
     for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) {
       ELFSym &Sym = SymbolTable[i];
-      outword(Sym.NameIdx);
-      outaddr32(Sym.Value);
-      outword(Sym.Size);
-      outbyte(Sym.Info);
-      outbyte(Sym.Other);
-      outhalf(Sym.SectionIdx);
+      outword(SymTabBuf, Sym.NameIdx);
+      outaddr32(SymTabBuf, Sym.Value);
+      outword(SymTabBuf, Sym.Size);
+      outbyte(SymTabBuf, Sym.Info);
+      outbyte(SymTabBuf, Sym.Other);
+      outhalf(SymTabBuf, Sym.SectionIdx);
     }
   } else {
     for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) {
       ELFSym &Sym = SymbolTable[i];
-      outword(Sym.NameIdx);
-      outbyte(Sym.Info);
-      outbyte(Sym.Other);
-      outhalf(Sym.SectionIdx);
-      outaddr64(Sym.Value);
-      outxword(Sym.Size);
+      outword(SymTabBuf, Sym.NameIdx);
+      outbyte(SymTabBuf, Sym.Info);
+      outbyte(SymTabBuf, Sym.Other);
+      outhalf(SymTabBuf, Sym.SectionIdx);
+      outaddr64(SymTabBuf, Sym.Value);
+      outxword(SymTabBuf, Sym.Size);
     }
   }
 
-  SymTab.Size = OutputBuffer.size()-SymTab.Offset;
+  SymTab.Size = SymTabBuf.size();
 }
 
 /// EmitSectionTableStringTable - This method adds and emits a section for the
@@ -448,63 +428,107 @@
 /// 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 = ELFSection::SHT_STRTAB;
+  ELFSection &SHStrTab = getSection(".shstrtab");
+  SHStrTab.Type = ELFSection::SHT_STRTAB;
 
   // Now that we know which section number is the .shstrtab section, update the
   // e_shstrndx entry in the ELF header.
-  fixhalf(SectionList.size()-1, ELFHeader_e_shstrndx_Offset);
+  fixhalf(FileHeader, SHStrTab.SectionIdx, ELFHeader_e_shstrndx_Offset);
 
   // Set the NameIdx of each section in the string table and emit the bytes for
   // the string table.
   unsigned Index = 0;
+  DataBuffer &Buf = SHStrTab.SectionData;
 
-  for (unsigned i = 0, e = SectionList.size(); i != e; ++i) {
+  for (std::list<ELFSection>::iterator I = SectionList.begin(),
+         E = SectionList.end(); I != E; ++I) {
     // Set the index into the table.  Note if we have lots of entries with
     // common suffixes, we could memoize them here if we cared.
-    SectionList[i].NameIdx = Index;
+    I->NameIdx = Index;
 
     // Add the name to the output buffer, including the null terminator.
-    OutputBuffer.insert(OutputBuffer.end(), SectionList[i].Name.begin(),
-                        SectionList[i].Name.end());
+    Buf.insert(Buf.end(), I->Name.begin(), I->Name.end());
+
     // Add a null terminator.
-    OutputBuffer.push_back(0);
+    Buf.push_back(0);
 
     // Keep track of the number of bytes emitted to this section.
-    Index += SectionList[i].Name.size()+1;
+    Index += I->Name.size()+1;
   }
 
   // Set the size of .shstrtab now that we know what it is.
-  SectionList.back().Size = Index;
+  assert(Index == Buf.size());
+  SHStrTab.Size = Index;
 }
 
-/// EmitSectionTable - Now that we have emitted the entire contents of the file
-/// (all of the sections), emit the section table which informs the reader where
-/// the boundaries are.
-void ELFWriter::EmitSectionTable() {
-  // Now that all of the sections have been emitted, set the e_shnum entry in
-  // the ELF header.
-  fixhalf(SectionList.size(), ELFHeader_e_shnum_Offset);
-  
-  // Now that we know the offset in the file of the section table (which we emit
-  // next), update the e_shoff address in the ELF header.
-  fixaddr(OutputBuffer.size(), ELFHeader_e_shoff_Offset);
-  
-  // Emit all of the section table entries.
-  for (unsigned i = 0, e = SectionList.size(); i != e; ++i) {
-    const ELFSection &S = SectionList[i];
-    outword(S.NameIdx);  // sh_name - Symbol table name idx
-    outword(S.Type);     // sh_type - Section contents & semantics
-    outword(S.Flags);    // sh_flags - Section flags.
-    outaddr(S.Addr);     // sh_addr - The mem address this section appears in.
-    outaddr(S.Offset);   // sh_offset - The offset from the start of the file.
-    outword(S.Size);     // sh_size - The section size.
-    outword(S.Link);     // sh_link - Section header table index link.
-    outword(S.Info);     // sh_info - Auxillary information.
-    outword(S.Align);    // sh_addralign - Alignment of section.
-    outword(S.EntSize);  // sh_entsize - Size of each entry in the section.
+/// OutputSectionsAndSectionTable - Now that we have constructed the file header
+/// and all of the sections, emit these to the ostream destination and emit the
+/// SectionTable.
+void ELFWriter::OutputSectionsAndSectionTable() {
+  // Pass #1: Compute the file offset for each section.
+  size_t FileOff = FileHeader.size();   // File header first.
+
+  // Emit all of the section data in order.
+  for (std::list<ELFSection>::iterator I = SectionList.begin(),
+         E = SectionList.end(); I != E; ++I) {
+    // Align FileOff to whatever the alignment restrictions of the section are.
+    if (I->Align)
+      FileOff = (FileOff+I->Align-1) & ~(I->Align-1);
+    I->Offset = FileOff;
+    FileOff += I->SectionData.size();
+  }
+
+  // Align Section Header.
+  unsigned TableAlign = is64Bit ? 8 : 4;
+  FileOff = (FileOff+TableAlign-1) & ~(TableAlign-1);
+
+  // Now that we know where all of the sections will be emitted, set the e_shnum
+  // entry in the ELF header.
+  fixhalf(FileHeader, NumSections, ELFHeader_e_shnum_Offset);
+  
+  // Now that we know the offset in the file of the section table, update the
+  // e_shoff address in the ELF header.
+  fixaddr(FileHeader, FileOff, ELFHeader_e_shoff_Offset);
+  
+  // Now that we know all of the data in the file header, emit it and all of the
+  // sections!
+  O.write((char*)&FileHeader[0], FileHeader.size());
+  FileOff = FileHeader.size();
+  DataBuffer().swap(FileHeader);
+
+  DataBuffer Table;
+
+  // Emit all of the section data and build the section table itself.
+  while (!SectionList.empty()) {
+    const ELFSection &S = *SectionList.begin();
+
+    // Align FileOff to whatever the alignment restrictions of the section are.
+    if (S.Align)
+      for (size_t NewFileOff = (FileOff+S.Align-1) & ~(S.Align-1);
+           FileOff != NewFileOff; ++FileOff)
+        O.put(0xAB);
+    O.write((char*)&S.SectionData[0], S.SectionData.size());
+    FileOff += S.SectionData.size();
+
+    outword(Table, S.NameIdx);  // sh_name - Symbol table name idx
+    outword(Table, S.Type);     // sh_type - Section contents & semantics
+    outword(Table, S.Flags);    // sh_flags - Section flags.
+    outaddr(Table, S.Addr);     // sh_addr - The mem addr this section is in.
+    outaddr(Table, S.Offset);   // sh_offset - Offset from the file start.
+    outword(Table, S.Size);     // sh_size - The section size.
+    outword(Table, S.Link);     // sh_link - Section header table index link.
+    outword(Table, S.Info);     // sh_info - Auxillary information.
+    outword(Table, S.Align);    // sh_addralign - Alignment of section.
+    outword(Table, S.EntSize);  // sh_entsize - Size of entries in the section.
+
+    SectionList.pop_front();
   }
 
-  // Release the memory allocated for the section list.
-  std::vector<ELFSection>().swap(SectionList);
+  // Align output for the section table.
+  for (size_t NewFileOff = (FileOff+TableAlign-1) & ~(TableAlign-1);
+       FileOff != NewFileOff; ++FileOff)
+    O.put(0xAB);
+  
+  // Emit the section table itself.
+  O.write((char*)&Table[0], Table.size());
 }






More information about the llvm-commits mailing list