diff --git a/include/llvm/Target/TargetELFWriterInfo.h b/include/llvm/Target/TargetELFWriterInfo.h index 548cc077a94..e266a71f8c8 100644 --- a/include/llvm/Target/TargetELFWriterInfo.h +++ b/include/llvm/Target/TargetELFWriterInfo.h @@ -25,9 +25,23 @@ namespace llvm { // e_machine member of the ELF header. unsigned short EMachine; public: + + // Machine architectures enum MachineType { - NoMachine, - EM_386 = 3 + EM_NONE = 0, // No machine + EM_M32 = 1, // AT&T WE 32100 + EM_SPARC = 2, // SPARC + EM_386 = 3, // Intel 386 + EM_68K = 4, // Motorola 68000 + EM_88K = 5, // Motorola 88000 + EM_486 = 6, // Intel 486 (deprecated) + EM_860 = 7, // Intel 80860 + EM_MIPS = 8, // MIPS R3000 + EM_PPC = 20, // PowerPC + EM_ARM = 40, // ARM + EM_ALPHA = 41, // DEC Alpha + EM_SPARCV9 = 43, // SPARC V9 + EM_X86_64 = 62 // AMD64 }; explicit TargetELFWriterInfo(MachineType machine) : EMachine(machine) {} diff --git a/lib/CodeGen/ELF.h b/lib/CodeGen/ELF.h new file mode 100644 index 00000000000..bf43622a6fa --- /dev/null +++ b/lib/CodeGen/ELF.h @@ -0,0 +1,186 @@ +//===-- lib/CodeGen/ELF.h - ELF constants and data structures ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains common, non-processor-specific data structures and +// constants for the ELF file format. +// +// The details of the ELF32 bits in this file are largely based on +// the Tool Interface Standard (TIS) Executable and Linking Format +// (ELF) Specification Version 1.2, May 1995. The ELF64 stuff is not +// standardized, as far as I can tell. It was largely based on information +// I found in OpenBSD header files. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_ELF_H +#define CODEGEN_ELF_H + +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { + class GlobalVariable; + + // Identification Indexes + enum { + EI_MAG0 = 0, + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3 + }; + + // File types + enum { + ET_NONE = 0, // No file type + ET_REL = 1, // Relocatable file + ET_EXEC = 2, // Executable file + ET_DYN = 3, // Shared object file + ET_CORE = 4, // Core file + ET_LOPROC = 0xff00, // Beginning of processor-specific codes + ET_HIPROC = 0xffff // Processor-specific + }; + + // Object file classes. + enum { + ELFCLASS32 = 1, // 32-bit object file + ELFCLASS64 = 2 // 64-bit object file + }; + + // Object file byte orderings. + enum { + ELFDATA2LSB = 1, // Little-endian object file + ELFDATA2MSB = 2 // Big-endian object file + }; + + // Versioning + enum { + EV_NONE = 0, + EV_CURRENT = 1 + }; + + /// 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. + struct ELFSection { + + // ELF specific fields + std::string Name; // Name of the section. + unsigned NameIdx; // Index in .shstrtab of name, once emitted. + unsigned Type; + unsigned Flags; + uint64_t Addr; + unsigned Offset; + unsigned Size; + unsigned Link; + unsigned Info; + unsigned Align; + unsigned EntSize; + + // Section Header Flags + enum { + SHF_WRITE = 1 << 0, // Writable + SHF_ALLOC = 1 << 1, // Mapped into the process addr space + SHF_EXECINSTR = 1 << 2, // Executable + SHF_MERGE = 1 << 4, // Might be merged if equal + SHF_STRINGS = 1 << 5, // Contains null-terminated strings + SHF_INFO_LINK = 1 << 6, // 'sh_info' contains SHT index + SHF_LINK_ORDER = 1 << 7, // Preserve order after combining + SHF_OS_NONCONFORMING = 1 << 8, // nonstandard OS support required + SHF_GROUP = 1 << 9, // Section is a member of a group + SHF_TLS = 1 << 10 // Section holds thread-local data + }; + + // Section Types + enum { + SHT_NULL = 0, // No associated section (inactive entry). + SHT_PROGBITS = 1, // Program-defined contents. + SHT_SYMTAB = 2, // Symbol table. + SHT_STRTAB = 3, // String table. + SHT_RELA = 4, // Relocation entries; explicit addends. + SHT_HASH = 5, // Symbol hash table. + SHT_DYNAMIC = 6, // Information for dynamic linking. + SHT_NOTE = 7, // Information about the file. + SHT_NOBITS = 8, // Data occupies no space in the file. + SHT_REL = 9, // Relocation entries; no explicit addends. + SHT_SHLIB = 10, // Reserved. + SHT_DYNSYM = 11, // Symbol table. + SHT_LOPROC = 0x70000000, // Lowest processor architecture-specific type. + SHT_HIPROC = 0x7fffffff, // Highest processor architecture-specific type. + SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. + SHT_HIUSER = 0xffffffff // Highest type reserved for applications. + }; + + // Special section indices. + enum { + SHN_UNDEF = 0, // Undefined, missing, irrelevant, or meaningless + 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_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables + SHN_HIRESERVE = 0xffff // Highest reserved index + }; + + /// 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. + std::vector SectionData; + + 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) {} + }; + + /// ELFSym - This struct contains information about each symbol that is + /// added to logical symbol table for the module. This is eventually + /// turned into a real symbol table in the file. + struct ELFSym { + const GlobalValue *GV; // The global value this corresponds to. + + // ELF specific fields + unsigned NameIdx; // Index in .strtab of name, once emitted. + uint64_t Value; + unsigned Size; + uint8_t Info; + uint8_t Other; + unsigned short SectionIdx; + + enum { + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2 + }; + + enum { + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4 + }; + + ELFSym(const GlobalValue *gv) : GV(gv), Value(0), + Size(0), Info(0), Other(0), + SectionIdx(ELFSection::SHN_UNDEF) {} + + void SetBind(unsigned X) { + assert(X == (X & 0xF) && "Bind value out of range!"); + Info = (Info & 0x0F) | (X << 4); + } + void SetType(unsigned X) { + assert(X == (X & 0xF) && "Type value out of range!"); + Info = (Info & 0xF0) | X; + } + }; + +} // end namespace llvm + +#endif diff --git a/lib/CodeGen/ELFCodeEmitter.cpp b/lib/CodeGen/ELFCodeEmitter.cpp index 9e8accd807e..9af276b4f93 100644 --- a/lib/CodeGen/ELFCodeEmitter.cpp +++ b/lib/CodeGen/ELFCodeEmitter.cpp @@ -71,7 +71,7 @@ void ELFCodeEmitter::startFunction(MachineFunction &MF) { /// finished. bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Add a symbol to represent the function. - ELFWriter::ELFSym FnSym(MF.getFunction()); + ELFSym FnSym(MF.getFunction()); // Figure out the binding (linkage) of the symbol. switch (MF.getFunction()->getLinkage()) { @@ -79,23 +79,23 @@ bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // appending linkage is illegal for functions. assert(0 && "Unknown linkage type!"); case GlobalValue::ExternalLinkage: - FnSym.SetBind(ELFWriter::ELFSym::STB_GLOBAL); + FnSym.SetBind(ELFSym::STB_GLOBAL); break; case GlobalValue::LinkOnceAnyLinkage: case GlobalValue::LinkOnceODRLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: - FnSym.SetBind(ELFWriter::ELFSym::STB_WEAK); + FnSym.SetBind(ELFSym::STB_WEAK); break; case GlobalValue::PrivateLinkage: assert (0 && "PrivateLinkage should not be in the symbol table."); case GlobalValue::InternalLinkage: - FnSym.SetBind(ELFWriter::ELFSym::STB_LOCAL); + FnSym.SetBind(ELFSym::STB_LOCAL); break; } // Set the symbol type as a function - FnSym.SetType(ELFWriter::ELFSym::STT_FUNC); + FnSym.SetType(ELFSym::STT_FUNC); FnSym.SectionIdx = ES->SectionIdx; FnSym.Size = CurBufferPtr-FnStartPtr; diff --git a/lib/CodeGen/ELFCodeEmitter.h b/lib/CodeGen/ELFCodeEmitter.h index 7ea4d71b095..e9ee936a486 100644 --- a/lib/CodeGen/ELFCodeEmitter.h +++ b/lib/CodeGen/ELFCodeEmitter.h @@ -21,7 +21,7 @@ namespace llvm { class ELFCodeEmitter : public MachineCodeEmitter { ELFWriter &EW; TargetMachine &TM; - ELFWriter::ELFSection *ES; // Section to write to. + ELFSection *ES; // Section to write to. uint8_t *FnStartPtr; public: explicit ELFCodeEmitter(ELFWriter &ew) : EW(ew), TM(EW.TM) {} diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index be8edce08d7..24f12a38d41 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -33,6 +33,7 @@ #include "ELFWriter.h" #include "ELFCodeEmitter.h" +#include "ELF.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/DerivedTypes.h" @@ -67,7 +68,8 @@ 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_flags = 0; // e_flags defaults to 0, no flags. + e_machine = TM.getELFWriterInfo()->getEMachine(); is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64; isLittleEndian = TM.getTargetData()->isLittleEndian(); @@ -90,24 +92,39 @@ bool ELFWriter::doInitialization(Module &M) { std::vector &FH = FileHeader; OutputBuffer FHOut(FH, is64Bit, isLittleEndian); - FHOut.outbyte(0x7F); // EI_MAG0 - FHOut.outbyte('E'); // EI_MAG1 - FHOut.outbyte('L'); // EI_MAG2 - FHOut.outbyte('F'); // EI_MAG3 - FHOut.outbyte(is64Bit ? 2 : 1); // EI_CLASS - FHOut.outbyte(isLittleEndian ? 1 : 2); // EI_DATA - FHOut.outbyte(1); // EI_VERSION - FH.resize(16); // EI_PAD up to 16 bytes. + unsigned ElfClass = is64Bit ? ELFCLASS64 : ELFCLASS32; + unsigned ElfEndian = isLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; - // This should change for shared objects. - FHOut.outhalf(1); // e_type = ET_REL - FHOut.outhalf(TM.getELFWriterInfo()->getEMachine()); // target-defined - FHOut.outword(1); // e_version = 1 - FHOut.outaddr(0); // e_entry = 0 -> no entry point in .o file - FHOut.outaddr(0); // e_phoff = 0 -> no program header for .o + // ELF Header + // ---------- + // Fields e_shnum e_shstrndx are only known after all section have + // been emitted. They locations in the ouput buffer are recorded so + // to be patched up later. + // + // Note + // ---- + // FHOut.outaddr method behaves differently for ELF32 and ELF64 writing + // 4 bytes in the former and 8 in the last for *_off and *_addr elf types - ELFHeader_e_shoff_Offset = FH.size(); - FHOut.outaddr(0); // e_shoff + FHOut.outbyte(0x7f); // e_ident[EI_MAG0] + FHOut.outbyte('E'); // e_ident[EI_MAG1] + 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] + + 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 + + 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.outhalf(is64Bit ? 64 : 52); // e_ehsize = ELF header size @@ -115,14 +132,16 @@ bool ELFWriter::doInitialization(Module &M) { FHOut.outhalf(0); // e_phnum = # prog header entries = 0 FHOut.outhalf(is64Bit ? 64 : 40); // e_shentsize = sect hdr entry size + // e_shnum = # of section header ents + ELFHdr_e_shnum_Offset = FH.size(); + FHOut.outhalf(0); - ELFHeader_e_shnum_Offset = FH.size(); - FHOut.outhalf(0); // e_shnum = # of section header ents - ELFHeader_e_shstrndx_Offset = FH.size(); - FHOut.outhalf(0); // e_shstrndx = Section # of '.shstrtab' + // e_shstrndx = Section # of '.shstrtab' + ELFHdr_e_shstrndx_Offset = FH.size(); + FHOut.outhalf(0); // Add the null section, which is required to be first in the file. - getSection("", 0, 0); + getSection("", ELFSection::SHT_NULL, 0); // Start up the symbol table. The first entry in the symtab is the null // entry. @@ -334,7 +353,7 @@ void ELFWriter::EmitSectionTableStringTable() { // Now that we know which section number is the .shstrtab section, update the // e_shstrndx entry in the ELF header. OutputBuffer FHOut(FileHeader, is64Bit, isLittleEndian); - FHOut.fixhalf(SHStrTab.SectionIdx, ELFHeader_e_shstrndx_Offset); + FHOut.fixhalf(SHStrTab.SectionIdx, ELFHdr_e_shstrndx_Offset); // Set the NameIdx of each section in the string table and emit the bytes for // the string table. @@ -386,11 +405,11 @@ void ELFWriter::OutputSectionsAndSectionTable() { // Now that we know where all of the sections will be emitted, set the e_shnum // entry in the ELF header. OutputBuffer FHOut(FileHeader, is64Bit, isLittleEndian); - FHOut.fixhalf(NumSections, ELFHeader_e_shnum_Offset); + FHOut.fixhalf(NumSections, ELFHdr_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. - FHOut.fixaddr(FileOff, ELFHeader_e_shoff_Offset); + FHOut.fixaddr(FileOff, ELFHdr_e_shoff_Offset); // Now that we know all of the data in the file header, emit it and all of the // sections! diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index 63d692bda1d..0389185f1db 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -15,6 +15,7 @@ #define ELFWRITER_H #include "llvm/CodeGen/MachineFunctionPass.h" +#include "ELF.h" #include #include @@ -82,10 +83,8 @@ namespace llvm { /// doInitialization - Emit the file header and all of the global variables /// for the module to the ELF file. bool doInitialization(Module &M); - bool runOnMachineFunction(MachineFunction &MF); - /// doFinalization - Now that the module has been completely processed, emit /// the ELF file to 'O'. bool doFinalization(Module &M); @@ -96,53 +95,6 @@ namespace llvm { // as well!). DataBuffer FileHeader; - /// 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. - struct ELFSection { - std::string Name; // Name of the section. - unsigned NameIdx; // Index in .shstrtab of name, once emitted. - unsigned Type; - unsigned Flags; - uint64_t Addr; - unsigned Offset; - unsigned Size; - unsigned Link; - unsigned Info; - 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 }; - enum { SHN_UNDEF = 0, SHN_ABS = 0xFFF1, SHN_COMMON = 0xFFF2 }; - enum { // SHF - ELF Section Header Flags - SHF_WRITE = 1 << 0, // Writable - SHF_ALLOC = 1 << 1, // Mapped into the process addr space - SHF_EXECINSTR = 1 << 2, // Executable - SHF_MERGE = 1 << 4, // Might be merged if equal - SHF_STRINGS = 1 << 5, // Contains null-terminated strings - SHF_INFO_LINK = 1 << 6, // 'sh_info' contains SHT index - SHF_LINK_ORDER = 1 << 7, // Preserve order after combining - SHF_OS_NONCONFORMING = 1 << 8, // nonstandard OS support required - SHF_GROUP = 1 << 9, // Section is a member of a group - SHF_TLS = 1 << 10 // Section holds thread-local data - }; - - 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) { - } - }; - /// 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. @@ -165,13 +117,13 @@ namespace llvm { SN->SectionIdx = NumSections++; SN->Type = Type; SN->Flags = Flags; + SN->Link = ELFSection::SHN_UNDEF; return *SN; } ELFSection &getTextSection() { - return getSection(".text", ELFWriter::ELFSection::SHT_PROGBITS, - ELFWriter::ELFSection::SHF_EXECINSTR | - ELFWriter::ELFSection::SHF_ALLOC); + return getSection(".text", ELFSection::SHT_PROGBITS, + ELFSection::SHF_EXECINSTR | ELFSection::SHF_ALLOC); } ELFSection &getDataSection() { @@ -183,34 +135,6 @@ namespace llvm { ELFSection::SHF_WRITE | ELFSection::SHF_ALLOC); } - /// ELFSym - This struct contains information about each symbol that is - /// added to logical symbol table for the module. This is eventually - /// turned into a real symbol table in the file. - struct ELFSym { - const GlobalValue *GV; // The global value this corresponds to. - unsigned NameIdx; // Index in .strtab of name, once emitted. - uint64_t Value; - unsigned Size; - unsigned char Info; - unsigned char Other; - unsigned short SectionIdx; - - enum { STB_LOCAL = 0, STB_GLOBAL = 1, STB_WEAK = 2 }; - enum { STT_NOTYPE = 0, STT_OBJECT = 1, STT_FUNC = 2, STT_SECTION = 3, - STT_FILE = 4 }; - ELFSym(const GlobalValue *gv) : GV(gv), Value(0), Size(0), Info(0), - Other(0), SectionIdx(0) {} - - void SetBind(unsigned X) { - assert(X == (X & 0xF) && "Bind value out of range!"); - Info = (Info & 0x0F) | (X << 4); - } - void SetType(unsigned X) { - assert(X == (X & 0xF) && "Type value out of range!"); - Info = (Info & 0xF0) | X; - } - }; - /// SymbolTable - This is the list of symbols we have emitted to the file. /// This actually gets rearranged before emission to the file (to put the /// local symbols first in the list). @@ -220,9 +144,9 @@ namespace llvm { // (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. + unsigned ELFHdr_e_shoff_Offset; // e_shoff in ELF header. + unsigned ELFHdr_e_shstrndx_Offset; // e_shstrndx in ELF header. + unsigned ELFHdr_e_shnum_Offset; // e_shnum in ELF header. private: void EmitGlobal(GlobalVariable *GV);