diff --git a/include/llvm/Support/OutputBuffer.h b/include/llvm/Support/OutputBuffer.h index b2077c55143..1adff2d2705 100644 --- a/include/llvm/Support/OutputBuffer.h +++ b/include/llvm/Support/OutputBuffer.h @@ -134,11 +134,22 @@ namespace llvm { P[2] = (X >> (isLittleEndian ? 16 : 8)) & 255; P[3] = (X >> (isLittleEndian ? 24 : 0)) & 255; } + void fixxword(uint64_t X, unsigned Offset) { + unsigned char *P = &Output[Offset]; + P[0] = (X >> (isLittleEndian ? 0 : 56)) & 255; + P[1] = (X >> (isLittleEndian ? 8 : 48)) & 255; + P[2] = (X >> (isLittleEndian ? 16 : 40)) & 255; + P[3] = (X >> (isLittleEndian ? 24 : 32)) & 255; + P[4] = (X >> (isLittleEndian ? 32 : 24)) & 255; + P[5] = (X >> (isLittleEndian ? 40 : 16)) & 255; + P[6] = (X >> (isLittleEndian ? 48 : 8)) & 255; + P[7] = (X >> (isLittleEndian ? 56 : 0)) & 255; + } void fixaddr(uint64_t X, unsigned Offset) { if (!is64Bit) fixword((unsigned)X, Offset); else - assert(0 && "Emission of 64-bit data not implemented yet!"); + fixxword(X, Offset); } unsigned char &operator[](unsigned Index) { diff --git a/lib/CodeGen/ELF.h b/lib/CodeGen/ELF.h index bf43622a6fa..0fa5dd7419e 100644 --- a/lib/CodeGen/ELF.h +++ b/lib/CodeGen/ELF.h @@ -21,6 +21,7 @@ #ifndef CODEGEN_ELF_H #define CODEGEN_ELF_H +#include "llvm/CodeGen/MachineRelocation.h" #include "llvm/Support/DataTypes.h" #include @@ -64,6 +65,36 @@ namespace llvm { EV_CURRENT = 1 }; + struct ELFHeader { + // e_machine - This field is the target specific value to emit as the + // e_machine member of the ELF header. + unsigned short e_machine; + + // e_flags - The machine flags for the target. This defaults to zero. + unsigned e_flags; + + // e_size - Holds the ELF header's size in bytes + unsigned e_ehsize; + + // Endianess and ELF Class (64 or 32 bits) + unsigned ByteOrder; + unsigned ElfClass; + + unsigned getByteOrder() const { return ByteOrder; } + unsigned getElfClass() const { return ElfClass; } + unsigned getSize() const { return e_ehsize; } + unsigned getMachine() const { return e_machine; } + unsigned getFlags() const { return e_flags; } + + ELFHeader(unsigned short machine, unsigned flags, + bool is64Bit, bool isLittleEndian) + : e_machine(machine), e_flags(flags) { + ByteOrder = is64Bit ? ELFCLASS64 : ELFCLASS32; + ElfClass = isLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; + e_ehsize = is64Bit ? 64 : 52; + } + }; + /// ELFSection - This struct contains information about each section that is /// emitted to the file. This is eventually turned into the section header /// table at the end of the file. @@ -118,11 +149,11 @@ namespace llvm { // Special section indices. enum { - SHN_UNDEF = 0, // Undefined, missing, irrelevant, or meaningless + SHN_UNDEF = 0, // Undefined, missing, irrelevant SHN_LORESERVE = 0xff00, // Lowest reserved index SHN_LOPROC = 0xff00, // Lowest processor-specific index SHN_HIPROC = 0xff1f, // Highest processor-specific index - SHN_ABS = 0xfff1, // Symbol has absolute value; does not need relocation + SHN_ABS = 0xfff1, // Symbol has absolute value; no relocation SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables SHN_HIRESERVE = 0xffff // Highest reserved index }; @@ -134,6 +165,15 @@ namespace llvm { /// up for emission to the file. std::vector SectionData; + /// Relocations - The relocations that we have encountered so far in this + /// section that we will need to convert to MachORelocation entries when + /// the file is written. + std::vector Relocations; + + /// Section Header Size + static unsigned getSectionHdrSize(bool is64Bit) + { return is64Bit ? 64 : 40; } + 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) {} @@ -167,7 +207,7 @@ namespace llvm { STT_FILE = 4 }; - ELFSym(const GlobalValue *gv) : GV(gv), Value(0), + ELFSym(const GlobalValue *gv) : GV(gv), NameIdx(0), Value(0), Size(0), Info(0), Other(0), SectionIdx(ELFSection::SHN_UNDEF) {} diff --git a/lib/CodeGen/ELFCodeEmitter.cpp b/lib/CodeGen/ELFCodeEmitter.cpp index 9af276b4f93..c7bd8736bb9 100644 --- a/lib/CodeGen/ELFCodeEmitter.cpp +++ b/lib/CodeGen/ELFCodeEmitter.cpp @@ -73,6 +73,9 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Add a symbol to represent the function. ELFSym FnSym(MF.getFunction()); + // Update Section Size + ES->Size = CurBufferPtr - BufferBegin; + // Figure out the binding (linkage) of the symbol. switch (MF.getFunction()->getLinkage()) { default: @@ -106,8 +109,29 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Finally, add it to the symtab. EW.SymbolTable.push_back(FnSym); - // Update Section Size - ES->Size = CurBufferPtr - BufferBegin; + // Relocations + // ----------- + // If we have emitted any relocations to function-specific objects such as + // basic blocks, constant pools entries, or jump tables, record their + // addresses now so that we can rewrite them with the correct addresses + // later. + for (unsigned i = 0, e = Relocations.size(); i != e; ++i) { + MachineRelocation &MR = Relocations[i]; + intptr_t Addr; + + if (MR.isBasicBlock()) { + Addr = getMachineBasicBlockAddress(MR.getBasicBlock()); + MR.setConstantVal(ES->SectionIdx); + MR.setResultPointer((void*)Addr); + } else if (MR.isGlobalValue()) { + EW.PendingGlobals.insert(MR.getGlobalValue()); + } else { + assert(0 && "Unhandled relocation type"); + } + ES->Relocations.push_back(MR); + } + Relocations.clear(); + return false; } diff --git a/lib/CodeGen/ELFCodeEmitter.h b/lib/CodeGen/ELFCodeEmitter.h index e9ee936a486..c0289daf3e9 100644 --- a/lib/CodeGen/ELFCodeEmitter.h +++ b/lib/CodeGen/ELFCodeEmitter.h @@ -20,8 +20,24 @@ namespace llvm { /// emit the code for functions to the ELF file. class ELFCodeEmitter : public MachineCodeEmitter { ELFWriter &EW; + + /// Target machine description TargetMachine &TM; - ELFSection *ES; // Section to write to. + + /// Section containing code for functions + ELFSection *ES; + + /// Relocations - These are the relocations that the function needs, as + /// emitted. + std::vector Relocations; + + /// MBBLocations - This vector is a mapping from MBB ID's to their address. + /// It is filled in by the StartMachineBasicBlock callback and queried by + /// the getMachineBasicBlockAddress callback. + std::vector MBBLocations; + + /// FnStartPtr - Pointer to the start location of the current function + /// in the buffer uint8_t *FnStartPtr; public: explicit ELFCodeEmitter(ELFWriter &ew) : EW(ew), TM(EW.TM) {} @@ -30,10 +46,19 @@ namespace llvm { bool finishFunction(MachineFunction &F); void addRelocation(const MachineRelocation &MR) { - assert(0 && "relo not handled yet!"); + Relocations.push_back(MR); } virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) { + if (MBBLocations.size() <= (unsigned)MBB->getNumber()) + MBBLocations.resize((MBB->getNumber()+1)*2); + MBBLocations[MBB->getNumber()] = getCurrentPCOffset(); + } + + virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) { + assert(MBBLocations.size() > (unsigned)MBB->getNumber() && + MBBLocations[MBB->getNumber()] && "MBB not emitted!"); + return MBBLocations[MBB->getNumber()]; } virtual uintptr_t getConstantPoolEntryAddress(unsigned Index) const { diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index 24f12a38d41..4bc2681d768 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -31,6 +31,8 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "elfwriter" + #include "ELFWriter.h" #include "ELFCodeEmitter.h" #include "ELF.h" @@ -48,6 +50,7 @@ #include "llvm/Support/OutputBuffer.h" #include "llvm/Support/Streams.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" #include using namespace llvm; @@ -67,13 +70,13 @@ MachineCodeEmitter *llvm::AddELFWriter(PassManagerBase &PM, //===----------------------------------------------------------------------===// ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm) - : MachineFunctionPass(&ID), O(o), TM(tm) { - e_flags = 0; // e_flags defaults to 0, no flags. - e_machine = TM.getELFWriterInfo()->getEMachine(); - + : MachineFunctionPass(&ID), O(o), TM(tm), ElfHdr() { is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; isLittleEndian = TM.getTargetData()->isLittleEndian(); + ElfHdr = new ELFHeader(TM.getELFWriterInfo()->getEMachine(), 0, + is64Bit, isLittleEndian); + // Create the machine code emitter object for this target. MCE = new ELFCodeEmitter(*this); NumSections = 0; @@ -81,6 +84,7 @@ ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm) ELFWriter::~ELFWriter() { delete MCE; + delete ElfHdr; } // doInitialization - Emit the file header and all of the global variables for @@ -92,9 +96,6 @@ bool ELFWriter::doInitialization(Module &M) { std::vector &FH = FileHeader; OutputBuffer FHOut(FH, is64Bit, isLittleEndian); - unsigned ElfClass = is64Bit ? ELFCLASS64 : ELFCLASS32; - unsigned ElfEndian = isLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; - // ELF Header // ---------- // Fields e_shnum e_shstrndx are only known after all section have @@ -111,26 +112,26 @@ bool ELFWriter::doInitialization(Module &M) { FHOut.outbyte('L'); // e_ident[EI_MAG2] FHOut.outbyte('F'); // e_ident[EI_MAG3] - FHOut.outbyte(ElfClass); // e_ident[EI_CLASS] - FHOut.outbyte(ElfEndian); // e_ident[EI_DATA] - FHOut.outbyte(EV_CURRENT); // e_ident[EI_VERSION] + FHOut.outbyte(ElfHdr->getElfClass()); // e_ident[EI_CLASS] + FHOut.outbyte(ElfHdr->getByteOrder()); // e_ident[EI_DATA] + FHOut.outbyte(EV_CURRENT); // e_ident[EI_VERSION] FH.resize(16); // e_ident[EI_NIDENT-EI_PAD] - FHOut.outhalf(ET_REL); // e_type - FHOut.outhalf(e_machine); // e_machine = target - FHOut.outword(EV_CURRENT); // e_version - FHOut.outaddr(0); // e_entry = 0 -> no entry point in .o file - FHOut.outaddr(0); // e_phoff = 0 -> no program header for .o - + FHOut.outhalf(ET_REL); // e_type + FHOut.outhalf(ElfHdr->getMachine()); // e_machine = target + FHOut.outword(EV_CURRENT); // e_version + FHOut.outaddr(0); // e_entry = 0, no entry point in .o file + FHOut.outaddr(0); // e_phoff = 0, no program header for .o ELFHdr_e_shoff_Offset = FH.size(); - FHOut.outaddr(0); // e_shoff = sec hdr table off in bytes - FHOut.outword(e_flags); // e_flags = whatever the target wants + FHOut.outaddr(0); // e_shoff = sec hdr table off in bytes + FHOut.outword(ElfHdr->getFlags()); // e_flags = whatever the target wants + FHOut.outhalf(ElfHdr->getSize()); // e_ehsize = ELF header size + FHOut.outhalf(0); // e_phentsize = prog header entry size + FHOut.outhalf(0); // e_phnum = # prog header entries = 0 - FHOut.outhalf(is64Bit ? 64 : 52); // e_ehsize = ELF header size - FHOut.outhalf(0); // e_phentsize = prog header entry size - FHOut.outhalf(0); // e_phnum = # prog header entries = 0 - FHOut.outhalf(is64Bit ? 64 : 40); // e_shentsize = sect hdr entry size + // e_shentsize = Section header entry size + FHOut.outhalf(ELFSection::getSectionHdrSize(is64Bit)); // e_shnum = # of section header ents ELFHdr_e_shnum_Offset = FH.size(); @@ -251,9 +252,10 @@ bool ELFWriter::doFinalization(Module &M) { // Emit the symbol table now, if non-empty. EmitSymbolTable(); - // FIXME: Emit the relocations now. + // Emit the relocation sections. + EmitRelocations(); - // Emit the string table for the sections in the ELF file we have. + // Emit the string table for the sections in the ELF file. EmitSectionTableStringTable(); // Emit the sections to the .o file, and emit the section table for the file. @@ -268,6 +270,10 @@ bool ELFWriter::doFinalization(Module &M) { return false; } +/// EmitRelocations - Emit relocations +void ELFWriter::EmitRelocations() { +} + /// EmitSymbolTable - If the current symbol table is non-empty, emit the string /// table for it and then the symbol table itself. void ELFWriter::EmitSymbolTable() { @@ -284,7 +290,7 @@ void ELFWriter::EmitSymbolTable() { // Set the zero'th symbol to a null byte, as required. StrTabOut.outbyte(0); - SymbolTable[0].NameIdx = 0; + //SymbolTable[0].NameIdx = 0; unsigned Index = 1; for (unsigned i = 1, e = SymbolTable.size(); i != e; ++i) { // Use the name mangler to uniquify the LLVM symbol. @@ -312,9 +318,9 @@ void ELFWriter::EmitSymbolTable() { // string table of each symbol, emit the symbol table itself. ELFSection &SymTab = getSection(".symtab", ELFSection::SHT_SYMTAB, 0); SymTab.Align = is64Bit ? 8 : 4; - 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 + SymTab.Link = StrTab.SectionIdx; // Section Index of .strtab. + SymTab.Info = FirstNonLocalSymbol; // First non-STB_LOCAL symbol. + SymTab.EntSize = is64Bit ? 24 : 16; // Size of each symtab entry. DataBuffer &SymTabBuf = SymTab.SectionData; OutputBuffer SymTabOut(SymTabBuf, is64Bit, isLittleEndian); @@ -391,11 +397,21 @@ void ELFWriter::OutputSectionsAndSectionTable() { // Emit all of the section data in order. for (std::list::iterator I = SectionList.begin(), E = SectionList.end(); I != E; ++I) { + + // Section idx 0 has 0 offset + if (!I->SectionIdx) + continue; + + // Update Section size + if (!I->Size) + I->Size = I->SectionData.size(); + // 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(); + FileOff += I->Size; } // Align Section Header. @@ -429,19 +445,23 @@ void ELFWriter::OutputSectionsAndSectionTable() { for (size_t NewFileOff = (FileOff+S.Align-1) & ~(S.Align-1); FileOff != NewFileOff; ++FileOff) O << (char)0xAB; - O.write((char*)&S.SectionData[0], S.SectionData.size()); - FileOff += S.SectionData.size(); + O.write((char*)&S.SectionData[0], S.Size); + + DOUT << "SectionIdx: " << S.SectionIdx << ", Name: " << S.Name + << ", Size: " << S.Size << ", Offset: " << S.Offset << "\n"; + + FileOff += S.Size; TableOut.outword(S.NameIdx); // sh_name - Symbol table name idx TableOut.outword(S.Type); // sh_type - Section contents & semantics - TableOut.outword(S.Flags); // sh_flags - Section flags. + TableOut.outaddr(S.Flags); // sh_flags - Section flags. TableOut.outaddr(S.Addr); // sh_addr - The mem addr this section is in. TableOut.outaddr(S.Offset); // sh_offset - Offset from the file start. - TableOut.outword(S.Size); // sh_size - The section size. + TableOut.outaddr(S.Size); // sh_size - The section size. TableOut.outword(S.Link); // sh_link - Section header table index link. TableOut.outword(S.Info); // sh_info - Auxillary information. - TableOut.outword(S.Align); // sh_addralign - Alignment of section. - TableOut.outword(S.EntSize); // sh_entsize - Size of entries in the section + TableOut.outaddr(S.Align); // sh_addralign - Alignment of section. + TableOut.outaddr(S.EntSize); // sh_entsize - Size of entries in the section SectionList.pop_front(); } diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index 0389185f1db..14a44f0240b 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -14,6 +14,7 @@ #ifndef ELFWRITER_H #define ELFWRITER_H +#include "llvm/ADT/SetVector.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "ELF.h" #include @@ -46,35 +47,21 @@ namespace llvm { protected: /// Output stream to send the resultant object file to. - /// raw_ostream &O; /// Target machine description. - /// TargetMachine &TM; /// Mang - The object used to perform name mangling for this module. - /// Mangler *Mang; /// MCE - The MachineCodeEmitter object that we are exposing to emit machine /// code for functions to the .o file. ELFCodeEmitter *MCE; - //===------------------------------------------------------------------===// - // Properties to be set by the derived class ctor, used to configure the - // ELFWriter. - - // e_machine - This field is the target specific value to emit as the - // e_machine member of the ELF header. - unsigned short e_machine; - - // e_flags - The machine flags for the target. This defaults to zero. - unsigned e_flags; - //===------------------------------------------------------------------===// // Properties inferred automatically from the target machine. - // + //===------------------------------------------------------------------===// /// is64Bit/isLittleEndian - This information is inferred from the target /// machine directly, indicating whether to emit a 32- or 64-bit ELF file. @@ -95,6 +82,9 @@ namespace llvm { // as well!). DataBuffer FileHeader; + /// ElfHdr - Hold information about the ELF Header + ELFHeader *ElfHdr; + /// 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. @@ -140,6 +130,11 @@ namespace llvm { /// local symbols first in the list). std::vector SymbolTable; + /// PendingSyms - This is a list of externally defined symbols that we have + /// been asked to emit, but have not seen a reference to. When a reference + /// is seen, the symbol will move from this list to the SymbolTable. + SetVector PendingGlobals; + // 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 @@ -149,9 +144,8 @@ namespace llvm { unsigned ELFHdr_e_shnum_Offset; // e_shnum in ELF header. private: void EmitGlobal(GlobalVariable *GV); - void EmitSymbolTable(); - + void EmitRelocations(); void EmitSectionTableStringTable(); void OutputSectionsAndSectionTable(); };