Simple ELF32/64 binary files can now be emitted for x86 and x86_64 without

relocation sections.

llvm-svn: 73038
This commit is contained in:
Bruno Cardoso Lopes 2009-06-07 21:22:38 +00:00
parent 0880e9f58d
commit e577492a17
6 changed files with 174 additions and 60 deletions

View File

@ -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) {

View File

@ -21,6 +21,7 @@
#ifndef CODEGEN_ELF_H
#define CODEGEN_ELF_H
#include "llvm/CodeGen/MachineRelocation.h"
#include "llvm/Support/DataTypes.h"
#include <cstring>
@ -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<unsigned char> 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<MachineRelocation> 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) {}

View File

@ -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;
}

View File

@ -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<MachineRelocation> 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<uintptr_t> 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 {

View File

@ -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 <list>
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<unsigned char> &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(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.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
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
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 : 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.Link = StrTab.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.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<ELFSection>::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();
}

View File

@ -14,6 +14,7 @@
#ifndef ELFWRITER_H
#define ELFWRITER_H
#include "llvm/ADT/SetVector.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "ELF.h"
#include <list>
@ -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<ELFSym> 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<GlobalValue*> 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();
};