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
This commit is contained in:
Chris Lattner 2005-07-16 08:01:13 +00:00
parent 5a8441ea3f
commit 5f48ff7d1f
2 changed files with 266 additions and 208 deletions

View File

@ -15,6 +15,7 @@
#define LLVM_CODEGEN_ELFWRITER_H #define LLVM_CODEGEN_ELFWRITER_H
#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunctionPass.h"
#include <list>
namespace llvm { namespace llvm {
class GlobalVariable; class GlobalVariable;
@ -35,6 +36,8 @@ namespace llvm {
~ELFWriter(); ~ELFWriter();
typedef std::vector<unsigned char> DataBuffer;
protected: protected:
ELFWriter(std::ostream &O, TargetMachine &TM); ELFWriter(std::ostream &O, TargetMachine &TM);
@ -85,14 +88,14 @@ namespace llvm {
bool doFinalization(Module &M); bool doFinalization(Module &M);
private: 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 // changed into something much more efficient later (and the bytecode writer
// as well!). // as well!).
std::vector<unsigned char> OutputBuffer; DataBuffer FileHeader;
/// ELFSection - This struct contains information about each section that is /// ELFSection - This struct contains information about each section that is
/// emitted to the OutputBuffer. This is eventually turned into the section /// emitted to the file. This is eventually turned into the section header
/// header table at the end of the file. /// table at the end of the file.
struct ELFSection { struct ELFSection {
std::string Name; // Name of the section. std::string Name; // Name of the section.
unsigned NameIdx; // Index in .shstrtab of name, once emitted. unsigned NameIdx; // Index in .shstrtab of name, once emitted.
@ -106,6 +109,14 @@ namespace llvm {
unsigned Align; unsigned Align;
unsigned EntSize; 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, 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_RELA = 4, SHT_HASH = 5, SHT_DYNAMIC = 6, SHT_NOTE = 7,
SHT_NOBITS = 8, SHT_REL = 9, SHT_SHLIB = 10, SHT_DYNSYM = 11 }; 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 SHF_TLS = 1 << 10,// Section holds thread-local data
}; };
ELFSection(const char *name = "", unsigned offset = 0) ELFSection(const std::string &name)
: Name(name), Type(0), Flags(0), Addr(0), Offset(offset), Size(0), : Name(name), Type(0), Flags(0), Addr(0), Offset(0), Size(0),
Link(0), Info(0), Align(0), EntSize(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 /// 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 /// file. Once the file has been completely built, the section header table
/// is constructed from this info. /// is constructed from this info.
std::vector<ELFSection> SectionList; std::list<ELFSection> SectionList;
unsigned NumSections; // Always = SectionList.size()
/// SectionLookup - This is a mapping from section name to section number in
/// the SectionList.
std::map<std::string, ELFSection*> 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 /// ELFSym - This struct contains information about each symbol that is
/// added to logical symbol table for the module. This is eventually /// 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. /// SymbolTable - This is the list of symbols we have emitted to the file.
/// This actually gets rearranged before emission to OutputBuffer (to put /// This actually gets rearranged before emission to the file (to put the
/// the local symbols first in the list). /// local symbols first in the list).
std::vector<ELFSym> SymbolTable; std::vector<ELFSym> SymbolTable;
// As we accumulate the ELF file into OutputBuffer, we occasionally need to // As we complete the ELF file, we need to update fields in the ELF header
// keep track of locations to update later (e.g. the location of the section // (e.g. the location of the section table). These members keep track of
// table in the ELF header. These members keep track of the offset in // the offset in ELFHeader of these various pieces to update and other
// OffsetBuffer of these various pieces to update and other locations in the // locations in the file.
// file.
unsigned ELFHeader_e_shoff_Offset; // e_shoff in ELF header. unsigned ELFHeader_e_shoff_Offset; // e_shoff in ELF header.
unsigned ELFHeader_e_shstrndx_Offset; // e_shstrndx in ELF header. unsigned ELFHeader_e_shstrndx_Offset; // e_shstrndx in ELF header.
unsigned ELFHeader_e_shnum_Offset; // e_shnum 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 // align - Emit padding into the file until the current output position is
// aligned to the specified power of two boundary. // 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 && assert(Boundary && (Boundary & (Boundary-1)) == 0 &&
"Must align to 2^k boundary"); "Must align to 2^k boundary");
while (OutputBuffer.size() & (Boundary-1)) size_t Size = Output.size();
outbyte(0xAB); 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); } static void outbyte(DataBuffer &Output, unsigned char X) {
void outhalf(unsigned short X) { Output.push_back(X);
}
void outhalf(DataBuffer &Output, unsigned short X) {
if (isLittleEndian) { if (isLittleEndian) {
OutputBuffer.push_back(X&255); Output.push_back(X&255);
OutputBuffer.push_back(X >> 8); Output.push_back(X >> 8);
} else { } else {
OutputBuffer.push_back(X >> 8); Output.push_back(X >> 8);
OutputBuffer.push_back(X&255); Output.push_back(X&255);
} }
} }
void outword(unsigned X) { void outword(DataBuffer &Output, unsigned X) {
if (isLittleEndian) { if (isLittleEndian) {
OutputBuffer.push_back((X >> 0) & 255); Output.push_back((X >> 0) & 255);
OutputBuffer.push_back((X >> 8) & 255); Output.push_back((X >> 8) & 255);
OutputBuffer.push_back((X >> 16) & 255); Output.push_back((X >> 16) & 255);
OutputBuffer.push_back((X >> 24) & 255); Output.push_back((X >> 24) & 255);
} else { } else {
OutputBuffer.push_back((X >> 24) & 255); Output.push_back((X >> 24) & 255);
OutputBuffer.push_back((X >> 16) & 255); Output.push_back((X >> 16) & 255);
OutputBuffer.push_back((X >> 8) & 255); Output.push_back((X >> 8) & 255);
OutputBuffer.push_back((X >> 0) & 255); Output.push_back((X >> 0) & 255);
} }
} }
void outxword(uint64_t X) { void outxword(DataBuffer &Output, uint64_t X) {
if (isLittleEndian) { if (isLittleEndian) {
OutputBuffer.push_back((X >> 0) & 255); Output.push_back((X >> 0) & 255);
OutputBuffer.push_back((X >> 8) & 255); Output.push_back((X >> 8) & 255);
OutputBuffer.push_back((X >> 16) & 255); Output.push_back((X >> 16) & 255);
OutputBuffer.push_back((X >> 24) & 255); Output.push_back((X >> 24) & 255);
OutputBuffer.push_back((X >> 32) & 255); Output.push_back((X >> 32) & 255);
OutputBuffer.push_back((X >> 40) & 255); Output.push_back((X >> 40) & 255);
OutputBuffer.push_back((X >> 48) & 255); Output.push_back((X >> 48) & 255);
OutputBuffer.push_back((X >> 56) & 255); Output.push_back((X >> 56) & 255);
} else { } else {
OutputBuffer.push_back((X >> 56) & 255); Output.push_back((X >> 56) & 255);
OutputBuffer.push_back((X >> 48) & 255); Output.push_back((X >> 48) & 255);
OutputBuffer.push_back((X >> 40) & 255); Output.push_back((X >> 40) & 255);
OutputBuffer.push_back((X >> 32) & 255); Output.push_back((X >> 32) & 255);
OutputBuffer.push_back((X >> 24) & 255); Output.push_back((X >> 24) & 255);
OutputBuffer.push_back((X >> 16) & 255); Output.push_back((X >> 16) & 255);
OutputBuffer.push_back((X >> 8) & 255); Output.push_back((X >> 8) & 255);
OutputBuffer.push_back((X >> 0) & 255); Output.push_back((X >> 0) & 255);
} }
} }
void outaddr32(unsigned X) { void outaddr32(DataBuffer &Output, unsigned X) {
outword(X); outword(Output, X);
} }
void outaddr64(uint64_t X) { void outaddr64(DataBuffer &Output, uint64_t X) {
outxword(X); outxword(Output, X);
} }
void outaddr(uint64_t X) { void outaddr(DataBuffer &Output, uint64_t X) {
if (!is64Bit) if (!is64Bit)
outword((unsigned)X); outword(Output, (unsigned)X);
else else
outxword(X); outxword(Output, X);
} }
// fix functions - Replace an existing entry at an offset. // fix functions - Replace an existing entry at an offset.
void fixhalf(unsigned short X, unsigned Offset) { void fixhalf(DataBuffer &Output, unsigned short X, unsigned Offset) {
unsigned char *P = &OutputBuffer[Offset]; unsigned char *P = &Output[Offset];
P[0] = (X >> (isLittleEndian ? 0 : 8)) & 255; P[0] = (X >> (isLittleEndian ? 0 : 8)) & 255;
P[1] = (X >> (isLittleEndian ? 8 : 0)) & 255; P[1] = (X >> (isLittleEndian ? 8 : 0)) & 255;
} }
void fixword(unsigned X, unsigned Offset) { void fixword(DataBuffer &Output, unsigned X, unsigned Offset) {
unsigned char *P = &OutputBuffer[Offset]; unsigned char *P = &Output[Offset];
P[0] = (X >> (isLittleEndian ? 0 : 24)) & 255; P[0] = (X >> (isLittleEndian ? 0 : 24)) & 255;
P[1] = (X >> (isLittleEndian ? 8 : 16)) & 255; P[1] = (X >> (isLittleEndian ? 8 : 16)) & 255;
P[2] = (X >> (isLittleEndian ? 16 : 8)) & 255; P[2] = (X >> (isLittleEndian ? 16 : 8)) & 255;
P[3] = (X >> (isLittleEndian ? 24 : 0)) & 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) if (!is64Bit)
fixword((unsigned)X, Offset); fixword(Output, (unsigned)X, Offset);
else else
assert(0 && "Emission of 64-bit data not implemented yet!"); assert(0 && "Emission of 64-bit data not implemented yet!");
} }
@ -271,7 +305,7 @@ namespace llvm {
void EmitSymbolTable(); void EmitSymbolTable();
void EmitSectionTableStringTable(); void EmitSectionTableStringTable();
void EmitSectionTable(); void OutputSectionsAndSectionTable();
}; };
} }

View File

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