From: Chris Lattner Date: Sat, 16 Jul 2005 08:01:13 +0000 (+0000) Subject: Major refactor of the ELFWriter code. Instead of building up one big X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=5f48ff7d1f27891f129ff09f1bbd0fced8c41f5a;p=oota-llvm.git 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22453 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/ELFWriter.h b/include/llvm/CodeGen/ELFWriter.h index b2b00efa627..9211047f4af 100644 --- a/include/llvm/CodeGen/ELFWriter.h +++ b/include/llvm/CodeGen/ELFWriter.h @@ -15,6 +15,7 @@ #define LLVM_CODEGEN_ELFWRITER_H #include "llvm/CodeGen/MachineFunctionPass.h" +#include namespace llvm { class GlobalVariable; @@ -35,6 +36,8 @@ namespace llvm { ~ELFWriter(); + typedef std::vector DataBuffer; + protected: ELFWriter(std::ostream &O, TargetMachine &TM); @@ -85,14 +88,14 @@ namespace llvm { bool doFinalization(Module &M); private: - // The buffer we are accumulating the file into. Note that this should be + // The buffer we accumulate the file header into. Note that this should be // changed into something much more efficient later (and the bytecode writer // as well!). - std::vector OutputBuffer; + DataBuffer FileHeader; /// ELFSection - This struct contains information about each section that is - /// emitted to the OutputBuffer. This is eventually turned into the section - /// header table at the end of the file. + /// emitted to the file. This is eventually turned into the section header + /// table at the end of the file. struct ELFSection { std::string Name; // Name of the section. unsigned NameIdx; // Index in .shstrtab of name, once emitted. @@ -106,6 +109,14 @@ namespace llvm { unsigned Align; unsigned EntSize; + /// SectionIdx - The number of the section in the Section Table. + /// + unsigned short SectionIdx; + + /// SectionData - The actual data for this section which we are building + /// up for emission to the file. + DataBuffer SectionData; + enum { SHT_NULL = 0, SHT_PROGBITS = 1, SHT_SYMTAB = 2, SHT_STRTAB = 3, SHT_RELA = 4, SHT_HASH = 5, SHT_DYNAMIC = 6, SHT_NOTE = 7, SHT_NOBITS = 8, SHT_REL = 9, SHT_SHLIB = 10, SHT_DYNSYM = 11 }; @@ -123,8 +134,8 @@ namespace llvm { SHF_TLS = 1 << 10,// Section holds thread-local data }; - ELFSection(const char *name = "", unsigned offset = 0) - : Name(name), Type(0), Flags(0), Addr(0), Offset(offset), Size(0), + ELFSection(const std::string &name) + : Name(name), Type(0), Flags(0), Addr(0), Offset(0), Size(0), Link(0), Info(0), Align(0), EntSize(0) { } }; @@ -132,7 +143,24 @@ namespace llvm { /// SectionList - This is the list of sections that we have emitted to the /// file. Once the file has been completely built, the section header table /// is constructed from this info. - std::vector SectionList; + std::list SectionList; + unsigned NumSections; // Always = SectionList.size() + + /// SectionLookup - This is a mapping from section name to section number in + /// the SectionList. + std::map SectionLookup; + + /// getSection - Return the section with the specified name, creating a new + /// section if one does not already exist. + ELFSection &getSection(const std::string &Name) { + ELFSection *&SN = SectionLookup[Name]; + if (SN) return *SN; + + SectionList.push_back(Name); + SN = &SectionList.back(); + SN->SectionIdx = NumSections++; + return *SN; + } /// ELFSym - This struct contains information about each symbol that is /// added to logical symbol table for the module. This is eventually @@ -163,103 +191,109 @@ namespace llvm { }; /// SymbolTable - This is the list of symbols we have emitted to the file. - /// This actually gets rearranged before emission to OutputBuffer (to put - /// the local symbols first in the list). + /// This actually gets rearranged before emission to the file (to put the + /// local symbols first in the list). std::vector SymbolTable; - // As we accumulate the ELF file into OutputBuffer, we occasionally need to - // keep track of locations to update later (e.g. the location of the section - // table in the ELF header. These members keep track of the offset in - // OffsetBuffer of these various pieces to update and other locations in the - // file. + // 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 + // locations in the file. unsigned ELFHeader_e_shoff_Offset; // e_shoff in ELF header. unsigned ELFHeader_e_shstrndx_Offset; // e_shstrndx in ELF header. unsigned ELFHeader_e_shnum_Offset; // e_shnum in ELF header. + // align - Emit padding into the file until the current output position is // aligned to the specified power of two boundary. - void align(unsigned Boundary) { + static void align(DataBuffer &Output, unsigned Boundary) { assert(Boundary && (Boundary & (Boundary-1)) == 0 && "Must align to 2^k boundary"); - while (OutputBuffer.size() & (Boundary-1)) - outbyte(0xAB); + size_t Size = Output.size(); + if (Size & (Boundary-1)) { + // Add padding to get alignment to the correct place. + size_t Pad = Boundary-(Size & (Boundary-1)); + Output.resize(Size+Pad); + } } - void outbyte(unsigned char X) { OutputBuffer.push_back(X); } - void outhalf(unsigned short X) { + static void outbyte(DataBuffer &Output, unsigned char X) { + Output.push_back(X); + } + void outhalf(DataBuffer &Output, unsigned short X) { if (isLittleEndian) { - OutputBuffer.push_back(X&255); - OutputBuffer.push_back(X >> 8); + Output.push_back(X&255); + Output.push_back(X >> 8); } else { - OutputBuffer.push_back(X >> 8); - OutputBuffer.push_back(X&255); + Output.push_back(X >> 8); + Output.push_back(X&255); } } - void outword(unsigned X) { + void outword(DataBuffer &Output, unsigned X) { if (isLittleEndian) { - OutputBuffer.push_back((X >> 0) & 255); - OutputBuffer.push_back((X >> 8) & 255); - OutputBuffer.push_back((X >> 16) & 255); - OutputBuffer.push_back((X >> 24) & 255); + Output.push_back((X >> 0) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 24) & 255); } else { - OutputBuffer.push_back((X >> 24) & 255); - OutputBuffer.push_back((X >> 16) & 255); - OutputBuffer.push_back((X >> 8) & 255); - OutputBuffer.push_back((X >> 0) & 255); + Output.push_back((X >> 24) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 0) & 255); } } - void outxword(uint64_t X) { + void outxword(DataBuffer &Output, uint64_t X) { if (isLittleEndian) { - OutputBuffer.push_back((X >> 0) & 255); - OutputBuffer.push_back((X >> 8) & 255); - OutputBuffer.push_back((X >> 16) & 255); - OutputBuffer.push_back((X >> 24) & 255); - OutputBuffer.push_back((X >> 32) & 255); - OutputBuffer.push_back((X >> 40) & 255); - OutputBuffer.push_back((X >> 48) & 255); - OutputBuffer.push_back((X >> 56) & 255); + Output.push_back((X >> 0) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 24) & 255); + Output.push_back((X >> 32) & 255); + Output.push_back((X >> 40) & 255); + Output.push_back((X >> 48) & 255); + Output.push_back((X >> 56) & 255); } else { - OutputBuffer.push_back((X >> 56) & 255); - OutputBuffer.push_back((X >> 48) & 255); - OutputBuffer.push_back((X >> 40) & 255); - OutputBuffer.push_back((X >> 32) & 255); - OutputBuffer.push_back((X >> 24) & 255); - OutputBuffer.push_back((X >> 16) & 255); - OutputBuffer.push_back((X >> 8) & 255); - OutputBuffer.push_back((X >> 0) & 255); + Output.push_back((X >> 56) & 255); + Output.push_back((X >> 48) & 255); + Output.push_back((X >> 40) & 255); + Output.push_back((X >> 32) & 255); + Output.push_back((X >> 24) & 255); + Output.push_back((X >> 16) & 255); + Output.push_back((X >> 8) & 255); + Output.push_back((X >> 0) & 255); } } - void outaddr32(unsigned X) { - outword(X); + void outaddr32(DataBuffer &Output, unsigned X) { + outword(Output, X); } - void outaddr64(uint64_t X) { - outxword(X); + void outaddr64(DataBuffer &Output, uint64_t X) { + outxword(Output, X); } - void outaddr(uint64_t X) { + void outaddr(DataBuffer &Output, uint64_t X) { if (!is64Bit) - outword((unsigned)X); + outword(Output, (unsigned)X); else - outxword(X); + outxword(Output, X); } // fix functions - Replace an existing entry at an offset. - void fixhalf(unsigned short X, unsigned Offset) { - unsigned char *P = &OutputBuffer[Offset]; + void fixhalf(DataBuffer &Output, unsigned short X, unsigned Offset) { + unsigned char *P = &Output[Offset]; P[0] = (X >> (isLittleEndian ? 0 : 8)) & 255; P[1] = (X >> (isLittleEndian ? 8 : 0)) & 255; } - void fixword(unsigned X, unsigned Offset) { - unsigned char *P = &OutputBuffer[Offset]; + void fixword(DataBuffer &Output, unsigned X, unsigned Offset) { + unsigned char *P = &Output[Offset]; P[0] = (X >> (isLittleEndian ? 0 : 24)) & 255; P[1] = (X >> (isLittleEndian ? 8 : 16)) & 255; P[2] = (X >> (isLittleEndian ? 16 : 8)) & 255; P[3] = (X >> (isLittleEndian ? 24 : 0)) & 255; } - void fixaddr(uint64_t X, unsigned Offset) { + void fixaddr(DataBuffer &Output, uint64_t X, unsigned Offset) { if (!is64Bit) - fixword((unsigned)X, Offset); + fixword(Output, (unsigned)X, Offset); else assert(0 && "Emission of 64-bit data not implemented yet!"); } @@ -271,7 +305,7 @@ namespace llvm { void EmitSymbolTable(); void EmitSectionTableStringTable(); - void EmitSectionTable(); + void OutputSectionsAndSectionTable(); }; } diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index cc8895df09d..c9d1ae4041c 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -49,10 +49,11 @@ namespace llvm { /// functions to the ELF file. class ELFCodeEmitter : public MachineCodeEmitter { ELFWriter &EW; - std::vector &OutputBuffer; + ELFWriter::ELFSection *ES; // Section to write to. + std::vector *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 @@ namespace llvm { 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 @@ namespace llvm { 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 @@ namespace llvm { 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 @@ void ELFCodeEmitter::finishFunction(MachineFunction &F) { 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 @@ ELFWriter::ELFWriter(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { // Create the machine code emitter object for this target. MCE = new ELFCodeEmitter(*this); + NumSections = 0; } ELFWriter::~ELFWriter() { @@ -176,47 +180,47 @@ ELFWriter::~ELFWriter() { 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 &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 + 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 = OutputBuffer.size(); - outaddr(0); // e_shoff - outword(e_flags); // e_flags = whatever the target wants + ELFHeader_e_shoff_Offset = FH.size(); + outaddr(FH, 0); // e_shoff + outword(FH, 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 + 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 = OutputBuffer.size(); - outhalf(0); // e_shnum = # of section header ents - ELFHeader_e_shstrndx_Offset = OutputBuffer.size(); - outhalf(0); // e_shstrndx = Section # of '.shstrtab' + 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 @@ void ELFWriter::EmitGlobal(GlobalVariable *GV, ELFSection &DataSection, } // 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 @@ 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. 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 @@ bool ELFWriter::doFinalization(Module &M) { // 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().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 @@ void ELFWriter::EmitSymbolTable() { // 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 @@ void ELFWriter::EmitSymbolTable() { 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 @@ void ELFWriter::EmitSymbolTable() { /// 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::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); +/// 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::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 (which we emit - // next), update the e_shoff address in the ELF header. - fixaddr(OutputBuffer.size(), ELFHeader_e_shoff_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); - // 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. + // 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().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()); }