mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-31 12:30:06 +00:00
mean that it has to be ConstantArray of ConstantStruct. We might have ConstantAggregateZero, at either level, so don't crash on that. Also, semi-deprecate the sentinal value. The linker isn't aware of sentinals so we end up with the two lists appended, each with their "sentinals" on them. Different parts of LLVM treated sentinals differently, so make them all just ignore the single entry and continue on with the rest of the list. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@129307 91177308-0d34-0410-b5e6-96231b3b80d8
1106 lines
39 KiB
C++
1106 lines
39 KiB
C++
//===-- ELFWriter.cpp - Target-independent ELF Writer code ----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the target-independent ELF writer. This file writes out
|
|
// the ELF file in the following order:
|
|
//
|
|
// #1. ELF Header
|
|
// #2. '.text' section
|
|
// #3. '.data' section
|
|
// #4. '.bss' section (conceptual position in file)
|
|
// ...
|
|
// #X. '.shstrtab' section
|
|
// #Y. Section Table
|
|
//
|
|
// The entries in the section table are laid out as:
|
|
// #0. Null entry [required]
|
|
// #1. ".text" entry - the program code
|
|
// #2. ".data" entry - global variables with initializers. [ if needed ]
|
|
// #3. ".bss" entry - global variables without initializers. [ if needed ]
|
|
// ...
|
|
// #N. ".shstrtab" entry - String table for the section names.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "elfwriter"
|
|
#include "ELF.h"
|
|
#include "ELFWriter.h"
|
|
#include "ELFCodeEmitter.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/PassManager.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/CodeGen/BinaryObject.h"
|
|
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
|
#include "llvm/CodeGen/ObjectCodeEmitter.h"
|
|
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCSectionELF.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
#include "llvm/Target/Mangler.h"
|
|
#include "llvm/Target/TargetAsmInfo.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Target/TargetELFWriterInfo.h"
|
|
#include "llvm/Target/TargetLowering.h"
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
using namespace llvm;
|
|
|
|
char ELFWriter::ID = 0;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ELFWriter Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm)
|
|
: MachineFunctionPass(ID), O(o), TM(tm),
|
|
OutContext(*new MCContext(*TM.getMCAsmInfo(), new TargetAsmInfo(tm))),
|
|
TLOF(TM.getTargetLowering()->getObjFileLowering()),
|
|
is64Bit(TM.getTargetData()->getPointerSizeInBits() == 64),
|
|
isLittleEndian(TM.getTargetData()->isLittleEndian()),
|
|
ElfHdr(isLittleEndian, is64Bit) {
|
|
|
|
MAI = TM.getMCAsmInfo();
|
|
TEW = TM.getELFWriterInfo();
|
|
|
|
// Create the object code emitter object for this target.
|
|
ElfCE = new ELFCodeEmitter(*this);
|
|
|
|
// Inital number of sections
|
|
NumSections = 0;
|
|
}
|
|
|
|
ELFWriter::~ELFWriter() {
|
|
delete ElfCE;
|
|
delete &OutContext;
|
|
|
|
while(!SymbolList.empty()) {
|
|
delete SymbolList.back();
|
|
SymbolList.pop_back();
|
|
}
|
|
|
|
while(!PrivateSyms.empty()) {
|
|
delete PrivateSyms.back();
|
|
PrivateSyms.pop_back();
|
|
}
|
|
|
|
while(!SectionList.empty()) {
|
|
delete SectionList.back();
|
|
SectionList.pop_back();
|
|
}
|
|
|
|
// Release the name mangler object.
|
|
delete Mang; Mang = 0;
|
|
}
|
|
|
|
// doInitialization - Emit the file header and all of the global variables for
|
|
// the module to the ELF file.
|
|
bool ELFWriter::doInitialization(Module &M) {
|
|
// Initialize TargetLoweringObjectFile.
|
|
const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(OutContext, TM);
|
|
|
|
Mang = new Mangler(OutContext, *TM.getTargetData());
|
|
|
|
// 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
|
|
// ----
|
|
// emitWord method behaves differently for ELF32 and ELF64, writing
|
|
// 4 bytes in the former and 8 in the last for *_off and *_addr elf types
|
|
|
|
ElfHdr.emitByte(0x7f); // e_ident[EI_MAG0]
|
|
ElfHdr.emitByte('E'); // e_ident[EI_MAG1]
|
|
ElfHdr.emitByte('L'); // e_ident[EI_MAG2]
|
|
ElfHdr.emitByte('F'); // e_ident[EI_MAG3]
|
|
|
|
ElfHdr.emitByte(TEW->getEIClass()); // e_ident[EI_CLASS]
|
|
ElfHdr.emitByte(TEW->getEIData()); // e_ident[EI_DATA]
|
|
ElfHdr.emitByte(ELF::EV_CURRENT); // e_ident[EI_VERSION]
|
|
ElfHdr.emitAlignment(16); // e_ident[EI_NIDENT-EI_PAD]
|
|
|
|
ElfHdr.emitWord16(ELF::ET_REL); // e_type
|
|
ElfHdr.emitWord16(TEW->getEMachine()); // e_machine = target
|
|
ElfHdr.emitWord32(ELF::EV_CURRENT); // e_version
|
|
ElfHdr.emitWord(0); // e_entry, no entry point in .o file
|
|
ElfHdr.emitWord(0); // e_phoff, no program header for .o
|
|
ELFHdr_e_shoff_Offset = ElfHdr.size();
|
|
ElfHdr.emitWord(0); // e_shoff = sec hdr table off in bytes
|
|
ElfHdr.emitWord32(TEW->getEFlags()); // e_flags = whatever the target wants
|
|
ElfHdr.emitWord16(TEW->getHdrSize()); // e_ehsize = ELF header size
|
|
ElfHdr.emitWord16(0); // e_phentsize = prog header entry size
|
|
ElfHdr.emitWord16(0); // e_phnum = # prog header entries = 0
|
|
|
|
// e_shentsize = Section header entry size
|
|
ElfHdr.emitWord16(TEW->getSHdrSize());
|
|
|
|
// e_shnum = # of section header ents
|
|
ELFHdr_e_shnum_Offset = ElfHdr.size();
|
|
ElfHdr.emitWord16(0); // Placeholder
|
|
|
|
// e_shstrndx = Section # of '.shstrtab'
|
|
ELFHdr_e_shstrndx_Offset = ElfHdr.size();
|
|
ElfHdr.emitWord16(0); // Placeholder
|
|
|
|
// Add the null section, which is required to be first in the file.
|
|
getNullSection();
|
|
|
|
// The first entry in the symtab is the null symbol and the second
|
|
// is a local symbol containing the module/file name
|
|
SymbolList.push_back(new ELFSym());
|
|
SymbolList.push_back(ELFSym::getFileSym());
|
|
|
|
return false;
|
|
}
|
|
|
|
// AddPendingGlobalSymbol - Add a global to be processed and to
|
|
// the global symbol lookup, use a zero index because the table
|
|
// index will be determined later.
|
|
void ELFWriter::AddPendingGlobalSymbol(const GlobalValue *GV,
|
|
bool AddToLookup /* = false */) {
|
|
PendingGlobals.insert(GV);
|
|
if (AddToLookup)
|
|
GblSymLookup[GV] = 0;
|
|
}
|
|
|
|
// AddPendingExternalSymbol - Add the external to be processed
|
|
// and to the external symbol lookup, use a zero index because
|
|
// the symbol table index will be determined later.
|
|
void ELFWriter::AddPendingExternalSymbol(const char *External) {
|
|
PendingExternals.insert(External);
|
|
ExtSymLookup[External] = 0;
|
|
}
|
|
|
|
ELFSection &ELFWriter::getDataSection() {
|
|
const MCSectionELF *Data = (const MCSectionELF *)TLOF.getDataSection();
|
|
return getSection(Data->getSectionName(), Data->getType(),
|
|
Data->getFlags(), 4);
|
|
}
|
|
|
|
ELFSection &ELFWriter::getBSSSection() {
|
|
const MCSectionELF *BSS = (const MCSectionELF *)TLOF.getBSSSection();
|
|
return getSection(BSS->getSectionName(), BSS->getType(), BSS->getFlags(), 4);
|
|
}
|
|
|
|
// getCtorSection - Get the static constructor section
|
|
ELFSection &ELFWriter::getCtorSection() {
|
|
const MCSectionELF *Ctor = (const MCSectionELF *)TLOF.getStaticCtorSection();
|
|
return getSection(Ctor->getSectionName(), Ctor->getType(), Ctor->getFlags());
|
|
}
|
|
|
|
// getDtorSection - Get the static destructor section
|
|
ELFSection &ELFWriter::getDtorSection() {
|
|
const MCSectionELF *Dtor = (const MCSectionELF *)TLOF.getStaticDtorSection();
|
|
return getSection(Dtor->getSectionName(), Dtor->getType(), Dtor->getFlags());
|
|
}
|
|
|
|
// getTextSection - Get the text section for the specified function
|
|
ELFSection &ELFWriter::getTextSection(const Function *F) {
|
|
const MCSectionELF *Text =
|
|
(const MCSectionELF *)TLOF.SectionForGlobal(F, Mang, TM);
|
|
return getSection(Text->getSectionName(), Text->getType(), Text->getFlags());
|
|
}
|
|
|
|
// getJumpTableSection - Get a read only section for constants when
|
|
// emitting jump tables. TODO: add PIC support
|
|
ELFSection &ELFWriter::getJumpTableSection() {
|
|
const MCSectionELF *JT =
|
|
(const MCSectionELF *)TLOF.getSectionForConstant(SectionKind::getReadOnly());
|
|
return getSection(JT->getSectionName(), JT->getType(), JT->getFlags(),
|
|
TM.getTargetData()->getPointerABIAlignment());
|
|
}
|
|
|
|
// getConstantPoolSection - Get a constant pool section based on the machine
|
|
// constant pool entry type and relocation info.
|
|
ELFSection &ELFWriter::getConstantPoolSection(MachineConstantPoolEntry &CPE) {
|
|
SectionKind Kind;
|
|
switch (CPE.getRelocationInfo()) {
|
|
default: llvm_unreachable("Unknown section kind");
|
|
case 2: Kind = SectionKind::getReadOnlyWithRel(); break;
|
|
case 1:
|
|
Kind = SectionKind::getReadOnlyWithRelLocal();
|
|
break;
|
|
case 0:
|
|
switch (TM.getTargetData()->getTypeAllocSize(CPE.getType())) {
|
|
case 4: Kind = SectionKind::getMergeableConst4(); break;
|
|
case 8: Kind = SectionKind::getMergeableConst8(); break;
|
|
case 16: Kind = SectionKind::getMergeableConst16(); break;
|
|
default: Kind = SectionKind::getMergeableConst(); break;
|
|
}
|
|
}
|
|
|
|
const MCSectionELF *CPSect =
|
|
(const MCSectionELF *)TLOF.getSectionForConstant(Kind);
|
|
return getSection(CPSect->getSectionName(), CPSect->getType(),
|
|
CPSect->getFlags(), CPE.getAlignment());
|
|
}
|
|
|
|
// getRelocSection - Return the relocation section of section 'S'. 'RelA'
|
|
// is true if the relocation section contains entries with addends.
|
|
ELFSection &ELFWriter::getRelocSection(ELFSection &S) {
|
|
unsigned SectionType = TEW->hasRelocationAddend() ?
|
|
ELF::SHT_RELA : ELF::SHT_REL;
|
|
|
|
std::string SectionName(".rel");
|
|
if (TEW->hasRelocationAddend())
|
|
SectionName.append("a");
|
|
SectionName.append(S.getName());
|
|
|
|
return getSection(SectionName, SectionType, 0, TEW->getPrefELFAlignment());
|
|
}
|
|
|
|
// getGlobalELFVisibility - Returns the ELF specific visibility type
|
|
unsigned ELFWriter::getGlobalELFVisibility(const GlobalValue *GV) {
|
|
switch (GV->getVisibility()) {
|
|
default:
|
|
llvm_unreachable("unknown visibility type");
|
|
case GlobalValue::DefaultVisibility:
|
|
return ELF::STV_DEFAULT;
|
|
case GlobalValue::HiddenVisibility:
|
|
return ELF::STV_HIDDEN;
|
|
case GlobalValue::ProtectedVisibility:
|
|
return ELF::STV_PROTECTED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// getGlobalELFBinding - Returns the ELF specific binding type
|
|
unsigned ELFWriter::getGlobalELFBinding(const GlobalValue *GV) {
|
|
if (GV->hasInternalLinkage())
|
|
return ELF::STB_LOCAL;
|
|
|
|
if (GV->isWeakForLinker() && !GV->hasCommonLinkage())
|
|
return ELF::STB_WEAK;
|
|
|
|
return ELF::STB_GLOBAL;
|
|
}
|
|
|
|
// getGlobalELFType - Returns the ELF specific type for a global
|
|
unsigned ELFWriter::getGlobalELFType(const GlobalValue *GV) {
|
|
if (GV->isDeclaration())
|
|
return ELF::STT_NOTYPE;
|
|
|
|
if (isa<Function>(GV))
|
|
return ELF::STT_FUNC;
|
|
|
|
return ELF::STT_OBJECT;
|
|
}
|
|
|
|
// IsELFUndefSym - True if the global value must be marked as a symbol
|
|
// which points to a SHN_UNDEF section. This means that the symbol has
|
|
// no definition on the module.
|
|
static bool IsELFUndefSym(const GlobalValue *GV) {
|
|
return GV->isDeclaration() || (isa<Function>(GV));
|
|
}
|
|
|
|
// AddToSymbolList - Update the symbol lookup and If the symbol is
|
|
// private add it to PrivateSyms list, otherwise to SymbolList.
|
|
void ELFWriter::AddToSymbolList(ELFSym *GblSym) {
|
|
assert(GblSym->isGlobalValue() && "Symbol must be a global value");
|
|
|
|
const GlobalValue *GV = GblSym->getGlobalValue();
|
|
if (GV->hasPrivateLinkage()) {
|
|
// For a private symbols, keep track of the index inside
|
|
// the private list since it will never go to the symbol
|
|
// table and won't be patched up later.
|
|
PrivateSyms.push_back(GblSym);
|
|
GblSymLookup[GV] = PrivateSyms.size()-1;
|
|
} else {
|
|
// Non private symbol are left with zero indices until
|
|
// they are patched up during the symbol table emition
|
|
// (where the indicies are created).
|
|
SymbolList.push_back(GblSym);
|
|
GblSymLookup[GV] = 0;
|
|
}
|
|
}
|
|
|
|
/// HasCommonSymbols - True if this section holds common symbols, this is
|
|
/// indicated on the ELF object file by a symbol with SHN_COMMON section
|
|
/// header index.
|
|
static bool HasCommonSymbols(const MCSectionELF &S) {
|
|
// FIXME: this is wrong, a common symbol can be in .data for example.
|
|
if (StringRef(S.getSectionName()).startswith(".gnu.linkonce."))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// EmitGlobal - Choose the right section for global and emit it
|
|
void ELFWriter::EmitGlobal(const GlobalValue *GV) {
|
|
|
|
// Check if the referenced symbol is already emitted
|
|
if (GblSymLookup.find(GV) != GblSymLookup.end())
|
|
return;
|
|
|
|
// Handle ELF Bind, Visibility and Type for the current symbol
|
|
unsigned SymBind = getGlobalELFBinding(GV);
|
|
unsigned SymType = getGlobalELFType(GV);
|
|
bool IsUndefSym = IsELFUndefSym(GV);
|
|
|
|
ELFSym *GblSym = IsUndefSym ? ELFSym::getUndefGV(GV, SymBind)
|
|
: ELFSym::getGV(GV, SymBind, SymType, getGlobalELFVisibility(GV));
|
|
|
|
if (!IsUndefSym) {
|
|
assert(isa<GlobalVariable>(GV) && "GV not a global variable!");
|
|
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
|
|
|
|
// Handle special llvm globals
|
|
if (EmitSpecialLLVMGlobal(GVar))
|
|
return;
|
|
|
|
// Get the ELF section where this global belongs from TLOF
|
|
const MCSectionELF *S =
|
|
(const MCSectionELF *)TLOF.SectionForGlobal(GV, Mang, TM);
|
|
ELFSection &ES =
|
|
getSection(S->getSectionName(), S->getType(), S->getFlags());
|
|
SectionKind Kind = S->getKind();
|
|
|
|
// The symbol align should update the section alignment if needed
|
|
const TargetData *TD = TM.getTargetData();
|
|
unsigned Align = TD->getPreferredAlignment(GVar);
|
|
unsigned Size = TD->getTypeAllocSize(GVar->getInitializer()->getType());
|
|
GblSym->Size = Size;
|
|
|
|
if (HasCommonSymbols(*S)) { // Symbol must go to a common section
|
|
GblSym->SectionIdx = ELF::SHN_COMMON;
|
|
|
|
// A new linkonce section is created for each global in the
|
|
// common section, the default alignment is 1 and the symbol
|
|
// value contains its alignment.
|
|
ES.Align = 1;
|
|
GblSym->Value = Align;
|
|
|
|
} else if (Kind.isBSS() || Kind.isThreadBSS()) { // Symbol goes to BSS.
|
|
GblSym->SectionIdx = ES.SectionIdx;
|
|
|
|
// Update the size with alignment and the next object can
|
|
// start in the right offset in the section
|
|
if (Align) ES.Size = (ES.Size + Align-1) & ~(Align-1);
|
|
ES.Align = std::max(ES.Align, Align);
|
|
|
|
// GblSym->Value should contain the virtual offset inside the section.
|
|
// Virtual because the BSS space is not allocated on ELF objects
|
|
GblSym->Value = ES.Size;
|
|
ES.Size += Size;
|
|
|
|
} else { // The symbol must go to some kind of data section
|
|
GblSym->SectionIdx = ES.SectionIdx;
|
|
|
|
// GblSym->Value should contain the symbol offset inside the section,
|
|
// and all symbols should start on their required alignment boundary
|
|
ES.Align = std::max(ES.Align, Align);
|
|
ES.emitAlignment(Align);
|
|
GblSym->Value = ES.size();
|
|
|
|
// Emit the global to the data section 'ES'
|
|
EmitGlobalConstant(GVar->getInitializer(), ES);
|
|
}
|
|
}
|
|
|
|
AddToSymbolList(GblSym);
|
|
}
|
|
|
|
void ELFWriter::EmitGlobalConstantStruct(const ConstantStruct *CVS,
|
|
ELFSection &GblS) {
|
|
|
|
// Print the fields in successive locations. Pad to align if needed!
|
|
const TargetData *TD = TM.getTargetData();
|
|
unsigned Size = TD->getTypeAllocSize(CVS->getType());
|
|
const StructLayout *cvsLayout = TD->getStructLayout(CVS->getType());
|
|
uint64_t sizeSoFar = 0;
|
|
for (unsigned i = 0, e = CVS->getNumOperands(); i != e; ++i) {
|
|
const Constant* field = CVS->getOperand(i);
|
|
|
|
// Check if padding is needed and insert one or more 0s.
|
|
uint64_t fieldSize = TD->getTypeAllocSize(field->getType());
|
|
uint64_t padSize = ((i == e-1 ? Size : cvsLayout->getElementOffset(i+1))
|
|
- cvsLayout->getElementOffset(i)) - fieldSize;
|
|
sizeSoFar += fieldSize + padSize;
|
|
|
|
// Now print the actual field value.
|
|
EmitGlobalConstant(field, GblS);
|
|
|
|
// Insert padding - this may include padding to increase the size of the
|
|
// current field up to the ABI size (if the struct is not packed) as well
|
|
// as padding to ensure that the next field starts at the right offset.
|
|
GblS.emitZeros(padSize);
|
|
}
|
|
assert(sizeSoFar == cvsLayout->getSizeInBytes() &&
|
|
"Layout of constant struct may be incorrect!");
|
|
}
|
|
|
|
void ELFWriter::EmitGlobalConstant(const Constant *CV, ELFSection &GblS) {
|
|
const TargetData *TD = TM.getTargetData();
|
|
unsigned Size = TD->getTypeAllocSize(CV->getType());
|
|
|
|
if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) {
|
|
for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i)
|
|
EmitGlobalConstant(CVA->getOperand(i), GblS);
|
|
return;
|
|
} else if (isa<ConstantAggregateZero>(CV)) {
|
|
GblS.emitZeros(Size);
|
|
return;
|
|
} else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) {
|
|
EmitGlobalConstantStruct(CVS, GblS);
|
|
return;
|
|
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
|
|
APInt Val = CFP->getValueAPF().bitcastToAPInt();
|
|
if (CFP->getType()->isDoubleTy())
|
|
GblS.emitWord64(Val.getZExtValue());
|
|
else if (CFP->getType()->isFloatTy())
|
|
GblS.emitWord32(Val.getZExtValue());
|
|
else if (CFP->getType()->isX86_FP80Ty()) {
|
|
unsigned PadSize = TD->getTypeAllocSize(CFP->getType())-
|
|
TD->getTypeStoreSize(CFP->getType());
|
|
GblS.emitWordFP80(Val.getRawData(), PadSize);
|
|
} else if (CFP->getType()->isPPC_FP128Ty())
|
|
llvm_unreachable("PPC_FP128Ty global emission not implemented");
|
|
return;
|
|
} else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
|
|
if (Size == 1)
|
|
GblS.emitByte(CI->getZExtValue());
|
|
else if (Size == 2)
|
|
GblS.emitWord16(CI->getZExtValue());
|
|
else if (Size == 4)
|
|
GblS.emitWord32(CI->getZExtValue());
|
|
else
|
|
EmitGlobalConstantLargeInt(CI, GblS);
|
|
return;
|
|
} else if (const ConstantVector *CP = dyn_cast<ConstantVector>(CV)) {
|
|
const VectorType *PTy = CP->getType();
|
|
for (unsigned I = 0, E = PTy->getNumElements(); I < E; ++I)
|
|
EmitGlobalConstant(CP->getOperand(I), GblS);
|
|
return;
|
|
} else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
|
|
// Resolve a constant expression which returns a (Constant, Offset)
|
|
// pair. If 'Res.first' is a GlobalValue, emit a relocation with
|
|
// the offset 'Res.second', otherwise emit a global constant like
|
|
// it is always done for not contant expression types.
|
|
CstExprResTy Res = ResolveConstantExpr(CE);
|
|
const Constant *Op = Res.first;
|
|
|
|
if (isa<GlobalValue>(Op))
|
|
EmitGlobalDataRelocation(cast<const GlobalValue>(Op),
|
|
TD->getTypeAllocSize(Op->getType()),
|
|
GblS, Res.second);
|
|
else
|
|
EmitGlobalConstant(Op, GblS);
|
|
|
|
return;
|
|
} else if (CV->getType()->getTypeID() == Type::PointerTyID) {
|
|
// Fill the data entry with zeros or emit a relocation entry
|
|
if (isa<ConstantPointerNull>(CV))
|
|
GblS.emitZeros(Size);
|
|
else
|
|
EmitGlobalDataRelocation(cast<const GlobalValue>(CV),
|
|
Size, GblS);
|
|
return;
|
|
} else if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
|
|
// This is a constant address for a global variable or function and
|
|
// therefore must be referenced using a relocation entry.
|
|
EmitGlobalDataRelocation(GV, Size, GblS);
|
|
return;
|
|
}
|
|
|
|
std::string msg;
|
|
raw_string_ostream ErrorMsg(msg);
|
|
ErrorMsg << "Constant unimp for type: " << *CV->getType();
|
|
report_fatal_error(ErrorMsg.str());
|
|
}
|
|
|
|
// ResolveConstantExpr - Resolve the constant expression until it stop
|
|
// yielding other constant expressions.
|
|
CstExprResTy ELFWriter::ResolveConstantExpr(const Constant *CV) {
|
|
const TargetData *TD = TM.getTargetData();
|
|
|
|
// There ins't constant expression inside others anymore
|
|
if (!isa<ConstantExpr>(CV))
|
|
return std::make_pair(CV, 0);
|
|
|
|
const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV);
|
|
switch (CE->getOpcode()) {
|
|
case Instruction::BitCast:
|
|
return ResolveConstantExpr(CE->getOperand(0));
|
|
|
|
case Instruction::GetElementPtr: {
|
|
const Constant *ptrVal = CE->getOperand(0);
|
|
SmallVector<Value*, 8> idxVec(CE->op_begin()+1, CE->op_end());
|
|
int64_t Offset = TD->getIndexedOffset(ptrVal->getType(), &idxVec[0],
|
|
idxVec.size());
|
|
return std::make_pair(ptrVal, Offset);
|
|
}
|
|
case Instruction::IntToPtr: {
|
|
Constant *Op = CE->getOperand(0);
|
|
Op = ConstantExpr::getIntegerCast(Op, TD->getIntPtrType(CV->getContext()),
|
|
false/*ZExt*/);
|
|
return ResolveConstantExpr(Op);
|
|
}
|
|
case Instruction::PtrToInt: {
|
|
Constant *Op = CE->getOperand(0);
|
|
const Type *Ty = CE->getType();
|
|
|
|
// We can emit the pointer value into this slot if the slot is an
|
|
// integer slot greater or equal to the size of the pointer.
|
|
if (TD->getTypeAllocSize(Ty) == TD->getTypeAllocSize(Op->getType()))
|
|
return ResolveConstantExpr(Op);
|
|
|
|
llvm_unreachable("Integer size less then pointer size");
|
|
}
|
|
case Instruction::Add:
|
|
case Instruction::Sub: {
|
|
// Only handle cases where there's a constant expression with GlobalValue
|
|
// as first operand and ConstantInt as second, which are the cases we can
|
|
// solve direclty using a relocation entry. GlobalValue=Op0, CstInt=Op1
|
|
// 1) Instruction::Add => (global) + CstInt
|
|
// 2) Instruction::Sub => (global) + -CstInt
|
|
const Constant *Op0 = CE->getOperand(0);
|
|
const Constant *Op1 = CE->getOperand(1);
|
|
assert(isa<ConstantInt>(Op1) && "Op1 must be a ConstantInt");
|
|
|
|
CstExprResTy Res = ResolveConstantExpr(Op0);
|
|
assert(isa<GlobalValue>(Res.first) && "Op0 must be a GlobalValue");
|
|
|
|
const APInt &RHS = cast<ConstantInt>(Op1)->getValue();
|
|
switch (CE->getOpcode()) {
|
|
case Instruction::Add:
|
|
return std::make_pair(Res.first, RHS.getSExtValue());
|
|
case Instruction::Sub:
|
|
return std::make_pair(Res.first, (-RHS).getSExtValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
report_fatal_error(CE->getOpcodeName() +
|
|
StringRef(": Unsupported ConstantExpr type"));
|
|
|
|
return std::make_pair(CV, 0); // silence warning
|
|
}
|
|
|
|
void ELFWriter::EmitGlobalDataRelocation(const GlobalValue *GV, unsigned Size,
|
|
ELFSection &GblS, int64_t Offset) {
|
|
// Create the relocation entry for the global value
|
|
MachineRelocation MR =
|
|
MachineRelocation::getGV(GblS.getCurrentPCOffset(),
|
|
TEW->getAbsoluteLabelMachineRelTy(),
|
|
const_cast<GlobalValue*>(GV),
|
|
Offset);
|
|
|
|
// Fill the data entry with zeros
|
|
GblS.emitZeros(Size);
|
|
|
|
// Add the relocation entry for the current data section
|
|
GblS.addRelocation(MR);
|
|
}
|
|
|
|
void ELFWriter::EmitGlobalConstantLargeInt(const ConstantInt *CI,
|
|
ELFSection &S) {
|
|
const TargetData *TD = TM.getTargetData();
|
|
unsigned BitWidth = CI->getBitWidth();
|
|
assert(isPowerOf2_32(BitWidth) &&
|
|
"Non-power-of-2-sized integers not handled!");
|
|
|
|
const uint64_t *RawData = CI->getValue().getRawData();
|
|
uint64_t Val = 0;
|
|
for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) {
|
|
Val = (TD->isBigEndian()) ? RawData[e - i - 1] : RawData[i];
|
|
S.emitWord64(Val);
|
|
}
|
|
}
|
|
|
|
/// EmitSpecialLLVMGlobal - Check to see if the specified global is a
|
|
/// special global used by LLVM. If so, emit it and return true, otherwise
|
|
/// do nothing and return false.
|
|
bool ELFWriter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) {
|
|
if (GV->getName() == "llvm.used")
|
|
llvm_unreachable("not implemented yet");
|
|
|
|
// Ignore debug and non-emitted data. This handles llvm.compiler.used.
|
|
if (GV->getSection() == "llvm.metadata" ||
|
|
GV->hasAvailableExternallyLinkage())
|
|
return true;
|
|
|
|
if (!GV->hasAppendingLinkage()) return false;
|
|
|
|
assert(GV->hasInitializer() && "Not a special LLVM global!");
|
|
|
|
const TargetData *TD = TM.getTargetData();
|
|
unsigned Align = TD->getPointerPrefAlignment();
|
|
if (GV->getName() == "llvm.global_ctors") {
|
|
ELFSection &Ctor = getCtorSection();
|
|
Ctor.emitAlignment(Align);
|
|
EmitXXStructorList(GV->getInitializer(), Ctor);
|
|
return true;
|
|
}
|
|
|
|
if (GV->getName() == "llvm.global_dtors") {
|
|
ELFSection &Dtor = getDtorSection();
|
|
Dtor.emitAlignment(Align);
|
|
EmitXXStructorList(GV->getInitializer(), Dtor);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// EmitXXStructorList - Emit the ctor or dtor list. This just emits out the
|
|
/// function pointers, ignoring the init priority.
|
|
void ELFWriter::EmitXXStructorList(Constant *List, ELFSection &Xtor) {
|
|
// Should be an array of '{ i32, void ()* }' structs. The first value is the
|
|
// init priority, which we ignore.
|
|
if (List->isNullValue()) return;
|
|
ConstantArray *InitList = cast<ConstantArray>(List);
|
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
|
if (InitList->getOperand(i)->isNullValue())
|
|
continue;
|
|
ConstantStruct *CS = cast<ConstantStruct>(InitList->getOperand(i));
|
|
|
|
if (CS->getOperand(1)->isNullValue())
|
|
continue;
|
|
|
|
// Emit the function pointer.
|
|
EmitGlobalConstant(CS->getOperand(1), Xtor);
|
|
}
|
|
}
|
|
|
|
bool ELFWriter::runOnMachineFunction(MachineFunction &MF) {
|
|
// Nothing to do here, this is all done through the ElfCE object above.
|
|
return false;
|
|
}
|
|
|
|
/// doFinalization - Now that the module has been completely processed, emit
|
|
/// the ELF file to 'O'.
|
|
bool ELFWriter::doFinalization(Module &M) {
|
|
// Emit .data section placeholder
|
|
getDataSection();
|
|
|
|
// Emit .bss section placeholder
|
|
getBSSSection();
|
|
|
|
// Build and emit data, bss and "common" sections.
|
|
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I)
|
|
EmitGlobal(I);
|
|
|
|
// Emit all pending globals
|
|
for (PendingGblsIter I = PendingGlobals.begin(), E = PendingGlobals.end();
|
|
I != E; ++I)
|
|
EmitGlobal(*I);
|
|
|
|
// Emit all pending externals
|
|
for (PendingExtsIter I = PendingExternals.begin(), E = PendingExternals.end();
|
|
I != E; ++I)
|
|
SymbolList.push_back(ELFSym::getExtSym(*I));
|
|
|
|
// Emit a symbol for each section created until now, skip null section
|
|
for (unsigned i = 1, e = SectionList.size(); i < e; ++i) {
|
|
ELFSection &ES = *SectionList[i];
|
|
ELFSym *SectionSym = ELFSym::getSectionSym();
|
|
SectionSym->SectionIdx = ES.SectionIdx;
|
|
SymbolList.push_back(SectionSym);
|
|
ES.Sym = SymbolList.back();
|
|
}
|
|
|
|
// Emit string table
|
|
EmitStringTable(M.getModuleIdentifier());
|
|
|
|
// Emit the symbol table now, if non-empty.
|
|
EmitSymbolTable();
|
|
|
|
// Emit the relocation sections.
|
|
EmitRelocations();
|
|
|
|
// Emit the sections string table.
|
|
EmitSectionTableStringTable();
|
|
|
|
// Dump the sections and section table to the .o file.
|
|
OutputSectionsAndSectionTable();
|
|
|
|
return false;
|
|
}
|
|
|
|
// RelocateField - Patch relocatable field with 'Offset' in 'BO'
|
|
// using a 'Value' of known 'Size'
|
|
void ELFWriter::RelocateField(BinaryObject &BO, uint32_t Offset,
|
|
int64_t Value, unsigned Size) {
|
|
if (Size == 32)
|
|
BO.fixWord32(Value, Offset);
|
|
else if (Size == 64)
|
|
BO.fixWord64(Value, Offset);
|
|
else
|
|
llvm_unreachable("don't know howto patch relocatable field");
|
|
}
|
|
|
|
/// EmitRelocations - Emit relocations
|
|
void ELFWriter::EmitRelocations() {
|
|
|
|
// True if the target uses the relocation entry to hold the addend,
|
|
// otherwise the addend is written directly to the relocatable field.
|
|
bool HasRelA = TEW->hasRelocationAddend();
|
|
|
|
// Create Relocation sections for each section which needs it.
|
|
for (unsigned i=0, e=SectionList.size(); i != e; ++i) {
|
|
ELFSection &S = *SectionList[i];
|
|
|
|
// This section does not have relocations
|
|
if (!S.hasRelocations()) continue;
|
|
ELFSection &RelSec = getRelocSection(S);
|
|
|
|
// 'Link' - Section hdr idx of the associated symbol table
|
|
// 'Info' - Section hdr idx of the section to which the relocation applies
|
|
ELFSection &SymTab = getSymbolTableSection();
|
|
RelSec.Link = SymTab.SectionIdx;
|
|
RelSec.Info = S.SectionIdx;
|
|
RelSec.EntSize = TEW->getRelocationEntrySize();
|
|
|
|
// Get the relocations from Section
|
|
std::vector<MachineRelocation> Relos = S.getRelocations();
|
|
for (std::vector<MachineRelocation>::iterator MRI = Relos.begin(),
|
|
MRE = Relos.end(); MRI != MRE; ++MRI) {
|
|
MachineRelocation &MR = *MRI;
|
|
|
|
// Relocatable field offset from the section start
|
|
unsigned RelOffset = MR.getMachineCodeOffset();
|
|
|
|
// Symbol index in the symbol table
|
|
unsigned SymIdx = 0;
|
|
|
|
// Target specific relocation field type and size
|
|
unsigned RelType = TEW->getRelocationType(MR.getRelocationType());
|
|
unsigned RelTySize = TEW->getRelocationTySize(RelType);
|
|
int64_t Addend = 0;
|
|
|
|
// There are several machine relocations types, and each one of
|
|
// them needs a different approach to retrieve the symbol table index.
|
|
if (MR.isGlobalValue()) {
|
|
const GlobalValue *G = MR.getGlobalValue();
|
|
int64_t GlobalOffset = MR.getConstantVal();
|
|
SymIdx = GblSymLookup[G];
|
|
if (G->hasPrivateLinkage()) {
|
|
// If the target uses a section offset in the relocation:
|
|
// SymIdx + Addend = section sym for global + section offset
|
|
unsigned SectionIdx = PrivateSyms[SymIdx]->SectionIdx;
|
|
Addend = PrivateSyms[SymIdx]->Value + GlobalOffset;
|
|
SymIdx = SectionList[SectionIdx]->getSymbolTableIndex();
|
|
} else {
|
|
Addend = TEW->getDefaultAddendForRelTy(RelType, GlobalOffset);
|
|
}
|
|
} else if (MR.isExternalSymbol()) {
|
|
const char *ExtSym = MR.getExternalSymbol();
|
|
SymIdx = ExtSymLookup[ExtSym];
|
|
Addend = TEW->getDefaultAddendForRelTy(RelType);
|
|
} else {
|
|
// Get the symbol index for the section symbol
|
|
unsigned SectionIdx = MR.getConstantVal();
|
|
SymIdx = SectionList[SectionIdx]->getSymbolTableIndex();
|
|
|
|
// The symbol offset inside the section
|
|
int64_t SymOffset = (int64_t)MR.getResultPointer();
|
|
|
|
// For pc relative relocations where symbols are defined in the same
|
|
// section they are referenced, ignore the relocation entry and patch
|
|
// the relocatable field with the symbol offset directly.
|
|
if (S.SectionIdx == SectionIdx && TEW->isPCRelativeRel(RelType)) {
|
|
int64_t Value = TEW->computeRelocation(SymOffset, RelOffset, RelType);
|
|
RelocateField(S, RelOffset, Value, RelTySize);
|
|
continue;
|
|
}
|
|
|
|
Addend = TEW->getDefaultAddendForRelTy(RelType, SymOffset);
|
|
}
|
|
|
|
// The target without addend on the relocation symbol must be
|
|
// patched in the relocation place itself to contain the addend
|
|
// otherwise write zeros to make sure there is no garbage there
|
|
RelocateField(S, RelOffset, HasRelA ? 0 : Addend, RelTySize);
|
|
|
|
// Get the relocation entry and emit to the relocation section
|
|
ELFRelocation Rel(RelOffset, SymIdx, RelType, HasRelA, Addend);
|
|
EmitRelocation(RelSec, Rel, HasRelA);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// EmitRelocation - Write relocation 'Rel' to the relocation section 'Rel'
|
|
void ELFWriter::EmitRelocation(BinaryObject &RelSec, ELFRelocation &Rel,
|
|
bool HasRelA) {
|
|
RelSec.emitWord(Rel.getOffset());
|
|
RelSec.emitWord(Rel.getInfo(is64Bit));
|
|
if (HasRelA)
|
|
RelSec.emitWord(Rel.getAddend());
|
|
}
|
|
|
|
/// EmitSymbol - Write symbol 'Sym' to the symbol table 'SymbolTable'
|
|
void ELFWriter::EmitSymbol(BinaryObject &SymbolTable, ELFSym &Sym) {
|
|
if (is64Bit) {
|
|
SymbolTable.emitWord32(Sym.NameIdx);
|
|
SymbolTable.emitByte(Sym.Info);
|
|
SymbolTable.emitByte(Sym.Other);
|
|
SymbolTable.emitWord16(Sym.SectionIdx);
|
|
SymbolTable.emitWord64(Sym.Value);
|
|
SymbolTable.emitWord64(Sym.Size);
|
|
} else {
|
|
SymbolTable.emitWord32(Sym.NameIdx);
|
|
SymbolTable.emitWord32(Sym.Value);
|
|
SymbolTable.emitWord32(Sym.Size);
|
|
SymbolTable.emitByte(Sym.Info);
|
|
SymbolTable.emitByte(Sym.Other);
|
|
SymbolTable.emitWord16(Sym.SectionIdx);
|
|
}
|
|
}
|
|
|
|
/// EmitSectionHeader - Write section 'Section' header in 'SHdrTab'
|
|
/// Section Header Table
|
|
void ELFWriter::EmitSectionHeader(BinaryObject &SHdrTab,
|
|
const ELFSection &SHdr) {
|
|
SHdrTab.emitWord32(SHdr.NameIdx);
|
|
SHdrTab.emitWord32(SHdr.Type);
|
|
if (is64Bit) {
|
|
SHdrTab.emitWord64(SHdr.Flags);
|
|
SHdrTab.emitWord(SHdr.Addr);
|
|
SHdrTab.emitWord(SHdr.Offset);
|
|
SHdrTab.emitWord64(SHdr.Size);
|
|
SHdrTab.emitWord32(SHdr.Link);
|
|
SHdrTab.emitWord32(SHdr.Info);
|
|
SHdrTab.emitWord64(SHdr.Align);
|
|
SHdrTab.emitWord64(SHdr.EntSize);
|
|
} else {
|
|
SHdrTab.emitWord32(SHdr.Flags);
|
|
SHdrTab.emitWord(SHdr.Addr);
|
|
SHdrTab.emitWord(SHdr.Offset);
|
|
SHdrTab.emitWord32(SHdr.Size);
|
|
SHdrTab.emitWord32(SHdr.Link);
|
|
SHdrTab.emitWord32(SHdr.Info);
|
|
SHdrTab.emitWord32(SHdr.Align);
|
|
SHdrTab.emitWord32(SHdr.EntSize);
|
|
}
|
|
}
|
|
|
|
/// EmitStringTable - If the current symbol table is non-empty, emit the string
|
|
/// table for it
|
|
void ELFWriter::EmitStringTable(const std::string &ModuleName) {
|
|
if (!SymbolList.size()) return; // Empty symbol table.
|
|
ELFSection &StrTab = getStringTableSection();
|
|
|
|
// Set the zero'th symbol to a null byte, as required.
|
|
StrTab.emitByte(0);
|
|
|
|
// Walk on the symbol list and write symbol names into the string table.
|
|
unsigned Index = 1;
|
|
for (ELFSymIter I=SymbolList.begin(), E=SymbolList.end(); I != E; ++I) {
|
|
ELFSym &Sym = *(*I);
|
|
|
|
std::string Name;
|
|
if (Sym.isGlobalValue()) {
|
|
SmallString<40> NameStr;
|
|
Mang->getNameWithPrefix(NameStr, Sym.getGlobalValue(), false);
|
|
Name.append(NameStr.begin(), NameStr.end());
|
|
} else if (Sym.isExternalSym())
|
|
Name.append(Sym.getExternalSymbol());
|
|
else if (Sym.isFileType())
|
|
Name.append(ModuleName);
|
|
|
|
if (Name.empty()) {
|
|
Sym.NameIdx = 0;
|
|
} else {
|
|
Sym.NameIdx = Index;
|
|
StrTab.emitString(Name);
|
|
|
|
// Keep track of the number of bytes emitted to this section.
|
|
Index += Name.size()+1;
|
|
}
|
|
}
|
|
assert(Index == StrTab.size());
|
|
StrTab.Size = Index;
|
|
}
|
|
|
|
// SortSymbols - On the symbol table local symbols must come before
|
|
// all other symbols with non-local bindings. The return value is
|
|
// the position of the first non local symbol.
|
|
unsigned ELFWriter::SortSymbols() {
|
|
unsigned FirstNonLocalSymbol;
|
|
std::vector<ELFSym*> LocalSyms, OtherSyms;
|
|
|
|
for (ELFSymIter I=SymbolList.begin(), E=SymbolList.end(); I != E; ++I) {
|
|
if ((*I)->isLocalBind())
|
|
LocalSyms.push_back(*I);
|
|
else
|
|
OtherSyms.push_back(*I);
|
|
}
|
|
SymbolList.clear();
|
|
FirstNonLocalSymbol = LocalSyms.size();
|
|
|
|
for (unsigned i = 0; i < FirstNonLocalSymbol; ++i)
|
|
SymbolList.push_back(LocalSyms[i]);
|
|
|
|
for (ELFSymIter I=OtherSyms.begin(), E=OtherSyms.end(); I != E; ++I)
|
|
SymbolList.push_back(*I);
|
|
|
|
LocalSyms.clear();
|
|
OtherSyms.clear();
|
|
|
|
return FirstNonLocalSymbol;
|
|
}
|
|
|
|
/// EmitSymbolTable - Emit the symbol table itself.
|
|
void ELFWriter::EmitSymbolTable() {
|
|
if (!SymbolList.size()) return; // Empty symbol table.
|
|
|
|
// Now that we have emitted the string table and know the offset into the
|
|
// string table of each symbol, emit the symbol table itself.
|
|
ELFSection &SymTab = getSymbolTableSection();
|
|
SymTab.Align = TEW->getPrefELFAlignment();
|
|
|
|
// Section Index of .strtab.
|
|
SymTab.Link = getStringTableSection().SectionIdx;
|
|
|
|
// Size of each symtab entry.
|
|
SymTab.EntSize = TEW->getSymTabEntrySize();
|
|
|
|
// Reorder the symbol table with local symbols first!
|
|
unsigned FirstNonLocalSymbol = SortSymbols();
|
|
|
|
// Emit all the symbols to the symbol table.
|
|
for (unsigned i = 0, e = SymbolList.size(); i < e; ++i) {
|
|
ELFSym &Sym = *SymbolList[i];
|
|
|
|
// Emit symbol to the symbol table
|
|
EmitSymbol(SymTab, Sym);
|
|
|
|
// Record the symbol table index for each symbol
|
|
if (Sym.isGlobalValue())
|
|
GblSymLookup[Sym.getGlobalValue()] = i;
|
|
else if (Sym.isExternalSym())
|
|
ExtSymLookup[Sym.getExternalSymbol()] = i;
|
|
|
|
// Keep track on the symbol index into the symbol table
|
|
Sym.SymTabIdx = i;
|
|
}
|
|
|
|
// One greater than the symbol table index of the last local symbol
|
|
SymTab.Info = FirstNonLocalSymbol;
|
|
SymTab.Size = SymTab.size();
|
|
}
|
|
|
|
/// EmitSectionTableStringTable - This method adds and emits a section for the
|
|
/// ELF Section Table string table: the string table that holds all of the
|
|
/// section names.
|
|
void ELFWriter::EmitSectionTableStringTable() {
|
|
// First step: add the section for the string table to the list of sections:
|
|
ELFSection &SHStrTab = getSectionHeaderStringTableSection();
|
|
|
|
// Now that we know which section number is the .shstrtab section, update the
|
|
// e_shstrndx entry in the ELF header.
|
|
ElfHdr.fixWord16(SHStrTab.SectionIdx, ELFHdr_e_shstrndx_Offset);
|
|
|
|
// Set the NameIdx of each section in the string table and emit the bytes for
|
|
// the string table.
|
|
unsigned Index = 0;
|
|
|
|
for (ELFSectionIter I=SectionList.begin(), E=SectionList.end(); I != E; ++I) {
|
|
ELFSection &S = *(*I);
|
|
// Set the index into the table. Note if we have lots of entries with
|
|
// common suffixes, we could memoize them here if we cared.
|
|
S.NameIdx = Index;
|
|
SHStrTab.emitString(S.getName());
|
|
|
|
// Keep track of the number of bytes emitted to this section.
|
|
Index += S.getName().size()+1;
|
|
}
|
|
|
|
// Set the size of .shstrtab now that we know what it is.
|
|
assert(Index == SHStrTab.size());
|
|
SHStrTab.Size = Index;
|
|
}
|
|
|
|
/// OutputSectionsAndSectionTable - Now that we have constructed the file header
|
|
/// and all of the sections, emit these to the ostream destination and emit the
|
|
/// SectionTable.
|
|
void ELFWriter::OutputSectionsAndSectionTable() {
|
|
// Pass #1: Compute the file offset for each section.
|
|
size_t FileOff = ElfHdr.size(); // File header first.
|
|
|
|
// Adjust alignment of all section if needed, skip the null section.
|
|
for (unsigned i=1, e=SectionList.size(); i < e; ++i) {
|
|
ELFSection &ES = *SectionList[i];
|
|
if (!ES.size()) {
|
|
ES.Offset = FileOff;
|
|
continue;
|
|
}
|
|
|
|
// Update Section size
|
|
if (!ES.Size)
|
|
ES.Size = ES.size();
|
|
|
|
// Align FileOff to whatever the alignment restrictions of the section are.
|
|
if (ES.Align)
|
|
FileOff = (FileOff+ES.Align-1) & ~(ES.Align-1);
|
|
|
|
ES.Offset = FileOff;
|
|
FileOff += ES.Size;
|
|
}
|
|
|
|
// Align Section Header.
|
|
unsigned TableAlign = TEW->getPrefELFAlignment();
|
|
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.
|
|
ElfHdr.fixWord16(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.
|
|
ElfHdr.fixWord(FileOff, ELFHdr_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 *)&ElfHdr.getData()[0], ElfHdr.size());
|
|
FileOff = ElfHdr.size();
|
|
|
|
// Section Header Table blob
|
|
BinaryObject SHdrTable(isLittleEndian, is64Bit);
|
|
|
|
// Emit all of sections to the file and build the section header table.
|
|
for (ELFSectionIter I=SectionList.begin(), E=SectionList.end(); I != E; ++I) {
|
|
ELFSection &S = *(*I);
|
|
DEBUG(dbgs() << "SectionIdx: " << S.SectionIdx << ", Name: " << S.getName()
|
|
<< ", Size: " << S.Size << ", Offset: " << S.Offset
|
|
<< ", SectionData Size: " << S.size() << "\n");
|
|
|
|
// Align FileOff to whatever the alignment restrictions of the section are.
|
|
if (S.size()) {
|
|
if (S.Align) {
|
|
for (size_t NewFileOff = (FileOff+S.Align-1) & ~(S.Align-1);
|
|
FileOff != NewFileOff; ++FileOff)
|
|
O << (char)0xAB;
|
|
}
|
|
O.write((char *)&S.getData()[0], S.Size);
|
|
FileOff += S.Size;
|
|
}
|
|
|
|
EmitSectionHeader(SHdrTable, S);
|
|
}
|
|
|
|
// Align output for the section table.
|
|
for (size_t NewFileOff = (FileOff+TableAlign-1) & ~(TableAlign-1);
|
|
FileOff != NewFileOff; ++FileOff)
|
|
O << (char)0xAB;
|
|
|
|
// Emit the section table itself.
|
|
O.write((char *)&SHdrTable.getData()[0], SHdrTable.size());
|
|
}
|