#include "ELFWriter.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/DerivedTypes.h"
#include "llvm/CodeGen/FileWriters.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetELFWriterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/OutputBuffer.h"
#include "llvm/Support/Streams.h"
#include "llvm/Support/raw_ostream.h"
#include <list>
using namespace llvm;
char ELFWriter::ID = 0;
MachineCodeEmitter *llvm::AddELFWriter(PassManagerBase &PM,
raw_ostream &O,
TargetMachine &TM) {
ELFWriter *EW = new ELFWriter(O, TM);
PM.add(EW);
return &EW->getMachineCodeEmitter();
}
namespace llvm {
class ELFCodeEmitter : public MachineCodeEmitter {
ELFWriter &EW;
TargetMachine &TM;
ELFWriter::ELFSection *ES; std::vector<unsigned char> *OutBuffer;
size_t FnStart;
public:
explicit ELFCodeEmitter(ELFWriter &ew) : EW(ew), TM(EW.TM), OutBuffer(0) {}
void startFunction(MachineFunction &F);
bool finishFunction(MachineFunction &F);
void addRelocation(const MachineRelocation &MR) {
assert(0 && "relo not handled yet!");
}
virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) {
}
virtual uintptr_t getConstantPoolEntryAddress(unsigned Index) const {
assert(0 && "CP not implementated yet!");
return 0;
}
virtual uintptr_t getJumpTableEntryAddress(unsigned Index) const {
assert(0 && "JT not implementated yet!");
return 0;
}
virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const {
assert(0 && "JT not implementated yet!");
return 0;
}
virtual uintptr_t getLabelAddress(uint64_t Label) const {
assert(0 && "Label address not implementated yet!");
abort();
return 0;
}
virtual void emitLabel(uint64_t LabelID) {
assert(0 && "emit Label not implementated yet!");
abort();
}
virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) { }
void startGVStub(const GlobalValue* F, unsigned StubSize,
unsigned Alignment = 1) {
assert(0 && "JIT specific function called!");
abort();
}
void startGVStub(const GlobalValue* F, void *Buffer, unsigned StubSize) {
assert(0 && "JIT specific function called!");
abort();
}
void *finishGVStub(const GlobalValue *F) {
assert(0 && "JIT specific function called!");
abort();
return 0;
}
};
}
void ELFCodeEmitter::startFunction(MachineFunction &F) {
unsigned Align = 16; ES = &EW.getSection(".text", ELFWriter::ELFSection::SHT_PROGBITS,
ELFWriter::ELFSection::SHF_EXECINSTR |
ELFWriter::ELFSection::SHF_ALLOC);
OutBuffer = &ES->SectionData;
cerr << "FIXME: This code needs to be updated for changes in the "
<< "CodeEmitter interfaces. In particular, this should set "
<< "BufferBegin/BufferEnd/CurBufferPtr, not deal with OutBuffer!";
abort();
if (ES->Align < Align) ES->Align = Align;
OutputBuffer OB(*OutBuffer,
TM.getTargetData()->getPointerSizeInBits() == 64,
TM.getTargetData()->isLittleEndian());
OB.align(Align);
FnStart = OutBuffer->size();
}
bool ELFCodeEmitter::finishFunction(MachineFunction &F) {
ELFWriter::ELFSym FnSym(F.getFunction());
switch (F.getFunction()->getLinkage()) {
default:
assert(0 && "Unknown linkage type!");
case GlobalValue::ExternalLinkage:
FnSym.SetBind(ELFWriter::ELFSym::STB_GLOBAL);
break;
case GlobalValue::LinkOnceAnyLinkage:
case GlobalValue::LinkOnceODRLinkage:
case GlobalValue::WeakAnyLinkage:
case GlobalValue::WeakODRLinkage:
FnSym.SetBind(ELFWriter::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);
break;
}
ES->Size = OutBuffer->size();
FnSym.SetType(ELFWriter::ELFSym::STT_FUNC);
FnSym.SectionIdx = ES->SectionIdx;
FnSym.Value = FnStart; FnSym.Size = OutBuffer->size()-FnStart;
EW.SymbolTable.push_back(FnSym);
return false;
}
ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm)
: MachineFunctionPass(&ID), O(o), TM(tm) {
e_flags = 0;
is64Bit = TM.getTargetData()->getPointerSizeInBits() == 64;
isLittleEndian = TM.getTargetData()->isLittleEndian();
MCE = new ELFCodeEmitter(*this);
NumSections = 0;
}
ELFWriter::~ELFWriter() {
delete MCE;
}
bool ELFWriter::doInitialization(Module &M) {
Mang = new Mangler(M);
std::vector<unsigned char> &FH = FileHeader;
OutputBuffer FHOut(FH, is64Bit, isLittleEndian);
FHOut.outbyte(0x7F); FHOut.outbyte('E'); FHOut.outbyte('L'); FHOut.outbyte('F'); FHOut.outbyte(is64Bit ? 2 : 1); FHOut.outbyte(isLittleEndian ? 1 : 2); FHOut.outbyte(1); FH.resize(16);
FHOut.outhalf(1); FHOut.outhalf(TM.getELFWriterInfo()->getEMachine()); FHOut.outword(1); FHOut.outaddr(0); FHOut.outaddr(0);
ELFHeader_e_shoff_Offset = FH.size();
FHOut.outaddr(0); FHOut.outword(e_flags);
FHOut.outhalf(is64Bit ? 64 : 52); FHOut.outhalf(0); FHOut.outhalf(0); FHOut.outhalf(is64Bit ? 64 : 40);
ELFHeader_e_shnum_Offset = FH.size();
FHOut.outhalf(0); ELFHeader_e_shstrndx_Offset = FH.size();
FHOut.outhalf(0);
getSection("", 0, 0);
SymbolTable.push_back(ELFSym(0));
return false;
}
void ELFWriter::EmitGlobal(GlobalVariable *GV) {
if (!GV->hasInitializer()) {
ELFSym ExternalSym(GV);
ExternalSym.SetBind(ELFSym::STB_GLOBAL);
ExternalSym.SetType(ELFSym::STT_NOTYPE);
ExternalSym.SectionIdx = ELFSection::SHN_UNDEF;
SymbolTable.push_back(ExternalSym);
return;
}
unsigned Align = TM.getTargetData()->getPreferredAlignment(GV);
unsigned Size =
TM.getTargetData()->getTypePaddedSize(GV->getType()->getElementType());
if (GV->getInitializer()->isNullValue()) {
if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() ||
GV->hasCommonLinkage()) {
ELFSym CommonSym(GV);
CommonSym.Value = Align;
CommonSym.Size = Size;
CommonSym.SetBind(ELFSym::STB_GLOBAL);
CommonSym.SetType(ELFSym::STT_OBJECT);
CommonSym.SectionIdx = ELFSection::SHN_COMMON;
SymbolTable.push_back(CommonSym);
return;
}
ELFSection &BSSSection = getBSSSection();
BSSSection.Align = std::max(BSSSection.Align, Align);
if (Align)
BSSSection.Size = (BSSSection.Size + Align - 1) & ~(Align-1);
ELFSym BSSSym(GV);
BSSSym.Value = BSSSection.Size;
BSSSym.Size = Size;
BSSSym.SetType(ELFSym::STT_OBJECT);
switch (GV->getLinkage()) {
default: assert(0 && "Unexpected linkage type!");
case GlobalValue::AppendingLinkage: case GlobalValue::ExternalLinkage:
BSSSym.SetBind(ELFSym::STB_GLOBAL);
break;
case GlobalValue::InternalLinkage:
BSSSym.SetBind(ELFSym::STB_LOCAL);
break;
}
BSSSym.SectionIdx = BSSSection.SectionIdx;
if (!GV->hasPrivateLinkage())
SymbolTable.push_back(BSSSym);
BSSSection.Size += Size;
return;
}
}
bool ELFWriter::runOnMachineFunction(MachineFunction &MF) {
return false;
}
bool ELFWriter::doFinalization(Module &M) {
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I)
EmitGlobal(I);
EmitSymbolTable();
EmitSectionTableStringTable();
OutputSectionsAndSectionTable();
SectionList.clear();
NumSections = 0;
delete Mang; Mang = 0;
return false;
}
void ELFWriter::EmitSymbolTable() {
if (SymbolTable.size() == 1) return;
unsigned FirstNonLocalSymbol = 1;
ELFSection &StrTab = getSection(".strtab", ELFSection::SHT_STRTAB, 0);
StrTab.Align = 1;
DataBuffer &StrTabBuf = StrTab.SectionData;
OutputBuffer StrTabOut(StrTabBuf, is64Bit, isLittleEndian);
StrTabOut.outbyte(0);
SymbolTable[0].NameIdx = 0;
unsigned Index = 1;
for (unsigned i = 1, e = SymbolTable.size(); i != e; ++i) {
std::string Name = Mang->getValueName(SymbolTable[i].GV);
if (Name.empty()) {
SymbolTable[i].NameIdx = 0;
} else {
SymbolTable[i].NameIdx = Index;
StrTabBuf.insert(StrTabBuf.end(), Name.begin(), Name.end());
StrTabBuf.push_back(0);
Index += Name.size()+1;
}
}
assert(Index == StrTabBuf.size());
StrTab.Size = Index;
ELFSection &SymTab = getSection(".symtab", ELFSection::SHT_SYMTAB, 0);
SymTab.Align = is64Bit ? 8 : 4;
SymTab.Link = SymTab.SectionIdx; SymTab.Info = FirstNonLocalSymbol; SymTab.EntSize = 16; DataBuffer &SymTabBuf = SymTab.SectionData;
OutputBuffer SymTabOut(SymTabBuf, is64Bit, isLittleEndian);
if (!is64Bit) { for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) {
ELFSym &Sym = SymbolTable[i];
SymTabOut.outword(Sym.NameIdx);
SymTabOut.outaddr32(Sym.Value);
SymTabOut.outword(Sym.Size);
SymTabOut.outbyte(Sym.Info);
SymTabOut.outbyte(Sym.Other);
SymTabOut.outhalf(Sym.SectionIdx);
}
} else {
for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) {
ELFSym &Sym = SymbolTable[i];
SymTabOut.outword(Sym.NameIdx);
SymTabOut.outbyte(Sym.Info);
SymTabOut.outbyte(Sym.Other);
SymTabOut.outhalf(Sym.SectionIdx);
SymTabOut.outaddr64(Sym.Value);
SymTabOut.outxword(Sym.Size);
}
}
SymTab.Size = SymTabBuf.size();
}
void ELFWriter::EmitSectionTableStringTable() {
ELFSection &SHStrTab = getSection(".shstrtab", ELFSection::SHT_STRTAB, 0);
OutputBuffer FHOut(FileHeader, is64Bit, isLittleEndian);
FHOut.fixhalf(SHStrTab.SectionIdx, ELFHeader_e_shstrndx_Offset);
unsigned Index = 0;
DataBuffer &Buf = SHStrTab.SectionData;
for (std::list<ELFSection>::iterator I = SectionList.begin(),
E = SectionList.end(); I != E; ++I) {
I->NameIdx = Index;
Buf.insert(Buf.end(), I->Name.begin(), I->Name.end());
Buf.push_back(0);
Index += I->Name.size()+1;
}
assert(Index == Buf.size());
SHStrTab.Size = Index;
}
void ELFWriter::OutputSectionsAndSectionTable() {
size_t FileOff = FileHeader.size();
for (std::list<ELFSection>::iterator I = SectionList.begin(),
E = SectionList.end(); I != E; ++I) {
if (I->Align)
FileOff = (FileOff+I->Align-1) & ~(I->Align-1);
I->Offset = FileOff;
FileOff += I->SectionData.size();
}
unsigned TableAlign = is64Bit ? 8 : 4;
FileOff = (FileOff+TableAlign-1) & ~(TableAlign-1);
OutputBuffer FHOut(FileHeader, is64Bit, isLittleEndian);
FHOut.fixhalf(NumSections, ELFHeader_e_shnum_Offset);
FHOut.fixaddr(FileOff, ELFHeader_e_shoff_Offset);
O.write((char*)&FileHeader[0], FileHeader.size());
FileOff = FileHeader.size();
DataBuffer().swap(FileHeader);
DataBuffer Table;
OutputBuffer TableOut(Table, is64Bit, isLittleEndian);
while (!SectionList.empty()) {
const ELFSection &S = *SectionList.begin();
if (S.Align)
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();
TableOut.outword(S.NameIdx); TableOut.outword(S.Type); TableOut.outword(S.Flags); TableOut.outaddr(S.Addr); TableOut.outaddr(S.Offset); TableOut.outword(S.Size); TableOut.outword(S.Link); TableOut.outword(S.Info); TableOut.outword(S.Align); TableOut.outword(S.EntSize);
SectionList.pop_front();
}
for (size_t NewFileOff = (FileOff+TableAlign-1) & ~(TableAlign-1);
FileOff != NewFileOff; ++FileOff)
O << (char)0xAB;
O.write((char*)&Table[0], Table.size());
}