llvm-6502/lib/MC/WinCOFFObjectWriter.cpp
Rafael Espindola 8f413fa9c0 On ELF we need to know which symbols are used in relocations to decide if
they should be in the symbol table or not. Instead of "guessing", just compute
the symbol table after the relocations are known.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@115619 91177308-0d34-0410-b5e6-96231b3b80d8
2010-10-05 15:11:03 +00:00

869 lines
28 KiB
C++

//===-- llvm/MC/WinCOFFObjectWriter.cpp -------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains an implementation of a Win32 COFF object file writer.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "WinCOFFObjectWriter"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/System/TimeValue.h"
#include "../Target/X86/X86FixupKinds.h"
#include <cstdio>
using namespace llvm;
namespace {
typedef llvm::SmallString<COFF::NameSize> name;
enum AuxiliaryType {
ATFunctionDefinition,
ATbfAndefSymbol,
ATWeakExternal,
ATFile,
ATSectionDefinition
};
struct AuxSymbol {
AuxiliaryType AuxType;
COFF::Auxiliary Aux;
};
class COFFSymbol;
class COFFSection;
class COFFSymbol {
public:
COFF::symbol Data;
typedef llvm::SmallVector<AuxSymbol, 1> AuxiliarySymbols;
name Name;
int Index;
AuxiliarySymbols Aux;
COFFSymbol *Other;
COFFSection *Section;
int Relocations;
MCSymbolData const *MCData;
COFFSymbol(llvm::StringRef name);
size_t size() const;
void set_name_offset(uint32_t Offset);
bool should_keep() const;
};
// This class contains staging data for a COFF relocation entry.
struct COFFRelocation {
COFF::relocation Data;
COFFSymbol *Symb;
COFFRelocation() : Symb(NULL) {}
static size_t size() { return COFF::RelocationSize; }
};
typedef std::vector<COFFRelocation> relocations;
class COFFSection {
public:
COFF::section Header;
std::string Name;
int Number;
MCSectionData const *MCData;
COFFSymbol *Symbol;
relocations Relocations;
COFFSection(llvm::StringRef name);
static size_t size();
};
// This class holds the COFF string table.
class StringTable {
typedef llvm::StringMap<size_t> map;
map Map;
void update_length();
public:
std::vector<char> Data;
StringTable();
size_t size() const;
size_t insert(llvm::StringRef String);
};
class WinCOFFObjectWriter : public MCObjectWriter {
public:
typedef std::vector<COFFSymbol*> symbols;
typedef std::vector<COFFSection*> sections;
typedef StringMap<COFFSymbol *> name_symbol_map;
typedef StringMap<COFFSection *> name_section_map;
typedef DenseMap<MCSymbolData const *, COFFSymbol *> symbol_map;
typedef DenseMap<MCSectionData const *, COFFSection *> section_map;
// Root level file contents.
bool Is64Bit;
COFF::header Header;
sections Sections;
symbols Symbols;
StringTable Strings;
// Maps used during object file creation.
section_map SectionMap;
symbol_map SymbolMap;
WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit);
~WinCOFFObjectWriter();
COFFSymbol *createSymbol(llvm::StringRef Name);
COFFSection *createSection(llvm::StringRef Name);
template <typename object_t, typename list_t>
object_t *createCOFFEntity(llvm::StringRef Name, list_t &List);
void DefineSection(MCSectionData const &SectionData);
void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler);
void MakeSymbolReal(COFFSymbol &S, size_t Index);
void MakeSectionReal(COFFSection &S, size_t Number);
bool ExportSection(COFFSection const *S);
bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm);
bool IsPhysicalSection(COFFSection *S);
// Entity writing methods.
void WriteFileHeader(const COFF::header &Header);
void WriteSymbol(const COFFSymbol *S);
void WriteAuxiliarySymbols(const COFFSymbol::AuxiliarySymbols &S);
void WriteSectionHeader(const COFF::section &S);
void WriteRelocation(const COFF::relocation &R);
// MCObjectWriter interface implementation.
void ExecutePostLayoutBinding(MCAssembler &Asm);
void RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup,
MCValue Target,
uint64_t &FixedValue);
virtual bool IsFixupFullyResolved(const MCAssembler &Asm,
const MCValue Target,
bool IsPCRel,
const MCFragment *DF) const;
void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout);
};
}
static inline void write_uint32_le(void *Data, uint32_t const &Value) {
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data);
Ptr[0] = (Value & 0x000000FF) >> 0;
Ptr[1] = (Value & 0x0000FF00) >> 8;
Ptr[2] = (Value & 0x00FF0000) >> 16;
Ptr[3] = (Value & 0xFF000000) >> 24;
}
static inline void write_uint16_le(void *Data, uint16_t const &Value) {
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data);
Ptr[0] = (Value & 0x00FF) >> 0;
Ptr[1] = (Value & 0xFF00) >> 8;
}
static inline void write_uint8_le(void *Data, uint8_t const &Value) {
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data);
Ptr[0] = (Value & 0xFF) >> 0;
}
//------------------------------------------------------------------------------
// Symbol class implementation
COFFSymbol::COFFSymbol(llvm::StringRef name)
: Name(name.begin(), name.end())
, Other(NULL)
, Section(NULL)
, Relocations(0)
, MCData(NULL) {
memset(&Data, 0, sizeof(Data));
}
size_t COFFSymbol::size() const {
return COFF::SymbolSize + (Data.NumberOfAuxSymbols * COFF::SymbolSize);
}
// In the case that the name does not fit within 8 bytes, the offset
// into the string table is stored in the last 4 bytes instead, leaving
// the first 4 bytes as 0.
void COFFSymbol::set_name_offset(uint32_t Offset) {
write_uint32_le(Data.Name + 0, 0);
write_uint32_le(Data.Name + 4, Offset);
}
/// logic to decide if the symbol should be reported in the symbol table
bool COFFSymbol::should_keep() const {
// no section means its external, keep it
if (Section == NULL)
return true;
// if it has relocations pointing at it, keep it
if (Relocations > 0) {
assert(Section->Number != -1 && "Sections with relocations must be real!");
return true;
}
// if the section its in is being droped, drop it
if (Section->Number == -1)
return false;
// if it is the section symbol, keep it
if (Section->Symbol == this)
return true;
// if its temporary, drop it
if (MCData && MCData->getSymbol().isTemporary())
return false;
// otherwise, keep it
return true;
}
//------------------------------------------------------------------------------
// Section class implementation
COFFSection::COFFSection(llvm::StringRef name)
: Name(name)
, MCData(NULL)
, Symbol(NULL) {
memset(&Header, 0, sizeof(Header));
}
size_t COFFSection::size() {
return COFF::SectionSize;
}
//------------------------------------------------------------------------------
// StringTable class implementation
/// Write the length of the string table into Data.
/// The length of the string table includes uint32 length header.
void StringTable::update_length() {
write_uint32_le(&Data.front(), Data.size());
}
StringTable::StringTable() {
// The string table data begins with the length of the entire string table
// including the length header. Allocate space for this header.
Data.resize(4);
}
size_t StringTable::size() const {
return Data.size();
}
/// Add String to the table iff it is not already there.
/// @returns the index into the string table where the string is now located.
size_t StringTable::insert(llvm::StringRef String) {
map::iterator i = Map.find(String);
if (i != Map.end())
return i->second;
size_t Offset = Data.size();
// Insert string data into string table.
Data.insert(Data.end(), String.begin(), String.end());
Data.push_back('\0');
// Put a reference to it in the map.
Map[String] = Offset;
// Update the internal length field.
update_length();
return Offset;
}
//------------------------------------------------------------------------------
// WinCOFFObjectWriter class implementation
WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit)
: MCObjectWriter(OS, true)
, Is64Bit(is64Bit) {
memset(&Header, 0, sizeof(Header));
Is64Bit ? Header.Machine = COFF::IMAGE_FILE_MACHINE_AMD64
: Header.Machine = COFF::IMAGE_FILE_MACHINE_I386;
}
WinCOFFObjectWriter::~WinCOFFObjectWriter() {
for (symbols::iterator I = Symbols.begin(), E = Symbols.end(); I != E; ++I)
delete *I;
for (sections::iterator I = Sections.begin(), E = Sections.end(); I != E; ++I)
delete *I;
}
COFFSymbol *WinCOFFObjectWriter::createSymbol(llvm::StringRef Name) {
return createCOFFEntity<COFFSymbol>(Name, Symbols);
}
COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) {
return createCOFFEntity<COFFSection>(Name, Sections);
}
/// A template used to lookup or create a symbol/section, and initialize it if
/// needed.
template <typename object_t, typename list_t>
object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name,
list_t &List) {
object_t *Object = new object_t(Name);
List.push_back(Object);
return Object;
}
/// This function takes a section data object from the assembler
/// and creates the associated COFF section staging object.
void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) {
// FIXME: Not sure how to verify this (at least in a debug build).
MCSectionCOFF const &Sec =
static_cast<MCSectionCOFF const &>(SectionData.getSection());
COFFSection *coff_section = createSection(Sec.getSectionName());
COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName());
coff_section->Symbol = coff_symbol;
coff_symbol->Section = coff_section;
coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
// In this case the auxiliary symbol is a Section Definition.
coff_symbol->Aux.resize(1);
memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0]));
coff_symbol->Aux[0].AuxType = ATSectionDefinition;
coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection();
coff_section->Header.Characteristics = Sec.getCharacteristics();
uint32_t &Characteristics = coff_section->Header.Characteristics;
switch (SectionData.getAlignment()) {
case 1: Characteristics |= COFF::IMAGE_SCN_ALIGN_1BYTES; break;
case 2: Characteristics |= COFF::IMAGE_SCN_ALIGN_2BYTES; break;
case 4: Characteristics |= COFF::IMAGE_SCN_ALIGN_4BYTES; break;
case 8: Characteristics |= COFF::IMAGE_SCN_ALIGN_8BYTES; break;
case 16: Characteristics |= COFF::IMAGE_SCN_ALIGN_16BYTES; break;
case 32: Characteristics |= COFF::IMAGE_SCN_ALIGN_32BYTES; break;
case 64: Characteristics |= COFF::IMAGE_SCN_ALIGN_64BYTES; break;
case 128: Characteristics |= COFF::IMAGE_SCN_ALIGN_128BYTES; break;
case 256: Characteristics |= COFF::IMAGE_SCN_ALIGN_256BYTES; break;
case 512: Characteristics |= COFF::IMAGE_SCN_ALIGN_512BYTES; break;
case 1024: Characteristics |= COFF::IMAGE_SCN_ALIGN_1024BYTES; break;
case 2048: Characteristics |= COFF::IMAGE_SCN_ALIGN_2048BYTES; break;
case 4096: Characteristics |= COFF::IMAGE_SCN_ALIGN_4096BYTES; break;
case 8192: Characteristics |= COFF::IMAGE_SCN_ALIGN_8192BYTES; break;
default:
llvm_unreachable("unsupported section alignment");
}
// Bind internal COFF section to MC section.
coff_section->MCData = &SectionData;
SectionMap[&SectionData] = coff_section;
}
/// This function takes a section data object from the assembler
/// and creates the associated COFF symbol staging object.
void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData,
MCAssembler &Assembler) {
assert(!SymbolData.getSymbol().isVariable()
&& "Cannot define a symbol that is a variable!");
COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName());
coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0;
coff_symbol->Data.StorageClass = (SymbolData.getFlags() & 0x00FF0000) >> 16;
// If no storage class was specified in the streamer, define it here.
if (coff_symbol->Data.StorageClass == 0) {
bool external = SymbolData.isExternal() || (SymbolData.Fragment == NULL);
coff_symbol->Data.StorageClass =
external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC;
}
if (SymbolData.getFlags() & COFF::SF_WeakReference) {
coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
const MCExpr *Value = SymbolData.getSymbol().getVariableValue();
// FIXME: This assert message isn't very good.
assert(Value->getKind() == MCExpr::SymbolRef &&
"Value must be a SymbolRef!");
const MCSymbolRefExpr *SymbolRef =
static_cast<const MCSymbolRefExpr *>(Value);
const MCSymbolData &OtherSymbolData =
Assembler.getSymbolData(SymbolRef->getSymbol());
// FIXME: This assert message isn't very good.
assert(SymbolMap.find(&OtherSymbolData) != SymbolMap.end() &&
"OtherSymbolData must be in the symbol map!");
coff_symbol->Other = SymbolMap[&OtherSymbolData];
// Setup the Weak External auxiliary symbol.
coff_symbol->Aux.resize(1);
memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0]));
coff_symbol->Aux[0].AuxType = ATWeakExternal;
coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0;
coff_symbol->Aux[0].Aux.WeakExternal.Characteristics =
COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY;
}
if (SymbolData.Fragment != NULL)
coff_symbol->Section = SectionMap[SymbolData.Fragment->getParent()];
// Bind internal COFF symbol to MC symbol.
coff_symbol->MCData = &SymbolData;
SymbolMap[&SymbolData] = coff_symbol;
}
/// making a section real involves assigned it a number and putting
/// name into the string table if needed
void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) {
if (S.Name.size() > COFF::NameSize) {
size_t StringTableEntry = Strings.insert(S.Name.c_str());
// FIXME: Why is this number 999999? This number is never mentioned in the
// spec. I'm assuming this is due to the printed value needing to fit into
// the S.Header.Name field. In which case why not 9999999 (7 9's instead of
// 6)? The spec does not state if this entry should be null terminated in
// this case, and thus this seems to be the best way to do it. I think I
// just solved my own FIXME...
if (StringTableEntry > 999999)
report_fatal_error("COFF string table is greater than 999999 bytes.");
std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry));
} else
std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
S.Number = Number;
S.Symbol->Data.SectionNumber = S.Number;
S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number;
}
void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) {
if (S.Name.size() > COFF::NameSize) {
size_t StringTableEntry = Strings.insert(S.Name.c_str());
S.set_name_offset(StringTableEntry);
} else
std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size());
S.Index = Index;
}
bool WinCOFFObjectWriter::ExportSection(COFFSection const *S) {
return !S->MCData->getFragmentList().empty();
}
bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData,
MCAssembler &Asm) {
// This doesn't seem to be right. Strings referred to from the .data section
// need symbols so they can be linked to code in the .text section right?
// return Asm.isSymbolLinkerVisible (&SymbolData);
// For now, all non-variable symbols are exported,
// the linker will sort the rest out for us.
return !SymbolData.getSymbol().isVariable();
}
bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) {
return (S->Header.Characteristics
& COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0;
}
//------------------------------------------------------------------------------
// entity writing methods
void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) {
WriteLE16(Header.Machine);
WriteLE16(Header.NumberOfSections);
WriteLE32(Header.TimeDateStamp);
WriteLE32(Header.PointerToSymbolTable);
WriteLE32(Header.NumberOfSymbols);
WriteLE16(Header.SizeOfOptionalHeader);
WriteLE16(Header.Characteristics);
}
void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol *S) {
WriteBytes(StringRef(S->Data.Name, COFF::NameSize));
WriteLE32(S->Data.Value);
WriteLE16(S->Data.SectionNumber);
WriteLE16(S->Data.Type);
Write8(S->Data.StorageClass);
Write8(S->Data.NumberOfAuxSymbols);
WriteAuxiliarySymbols(S->Aux);
}
void WinCOFFObjectWriter::WriteAuxiliarySymbols(
const COFFSymbol::AuxiliarySymbols &S) {
for(COFFSymbol::AuxiliarySymbols::const_iterator i = S.begin(), e = S.end();
i != e; ++i) {
switch(i->AuxType) {
case ATFunctionDefinition:
WriteLE32(i->Aux.FunctionDefinition.TagIndex);
WriteLE32(i->Aux.FunctionDefinition.TotalSize);
WriteLE32(i->Aux.FunctionDefinition.PointerToLinenumber);
WriteLE32(i->Aux.FunctionDefinition.PointerToNextFunction);
WriteZeros(sizeof(i->Aux.FunctionDefinition.unused));
break;
case ATbfAndefSymbol:
WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused1));
WriteLE16(i->Aux.bfAndefSymbol.Linenumber);
WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused2));
WriteLE32(i->Aux.bfAndefSymbol.PointerToNextFunction);
WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused3));
break;
case ATWeakExternal:
WriteLE32(i->Aux.WeakExternal.TagIndex);
WriteLE32(i->Aux.WeakExternal.Characteristics);
WriteZeros(sizeof(i->Aux.WeakExternal.unused));
break;
case ATFile:
WriteBytes(StringRef(reinterpret_cast<const char *>(i->Aux.File.FileName),
sizeof(i->Aux.File.FileName)));
break;
case ATSectionDefinition:
WriteLE32(i->Aux.SectionDefinition.Length);
WriteLE16(i->Aux.SectionDefinition.NumberOfRelocations);
WriteLE16(i->Aux.SectionDefinition.NumberOfLinenumbers);
WriteLE32(i->Aux.SectionDefinition.CheckSum);
WriteLE16(i->Aux.SectionDefinition.Number);
Write8(i->Aux.SectionDefinition.Selection);
WriteZeros(sizeof(i->Aux.SectionDefinition.unused));
break;
}
}
}
void WinCOFFObjectWriter::WriteSectionHeader(const COFF::section &S) {
WriteBytes(StringRef(S.Name, COFF::NameSize));
WriteLE32(S.VirtualSize);
WriteLE32(S.VirtualAddress);
WriteLE32(S.SizeOfRawData);
WriteLE32(S.PointerToRawData);
WriteLE32(S.PointerToRelocations);
WriteLE32(S.PointerToLineNumbers);
WriteLE16(S.NumberOfRelocations);
WriteLE16(S.NumberOfLineNumbers);
WriteLE32(S.Characteristics);
}
void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) {
WriteLE32(R.VirtualAddress);
WriteLE32(R.SymbolTableIndex);
WriteLE16(R.Type);
}
////////////////////////////////////////////////////////////////////////////////
// MCObjectWriter interface implementations
void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) {
// "Define" each section & symbol. This creates section & symbol
// entries in the staging area.
for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++)
DefineSection(*i);
for (MCAssembler::const_symbol_iterator i = Asm.symbol_begin(),
e = Asm.symbol_end(); i != e; i++) {
if (ExportSymbol(*i, Asm))
DefineSymbol(*i, Asm);
}
}
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup,
MCValue Target,
uint64_t &FixedValue) {
assert(Target.getSymA() != NULL && "Relocation must reference a symbol!");
const MCSymbol *A = &Target.getSymA()->getSymbol();
MCSymbolData &A_SD = Asm.getSymbolData(*A);
MCSectionData const *SectionData = Fragment->getParent();
// Mark this symbol as requiring an entry in the symbol table.
assert(SectionMap.find(SectionData) != SectionMap.end() &&
"Section must already have been defined in ExecutePostLayoutBinding!");
assert(SymbolMap.find(&A_SD) != SymbolMap.end() &&
"Symbol must already have been defined in ExecutePostLayoutBinding!");
COFFSection *coff_section = SectionMap[SectionData];
COFFSymbol *coff_symbol = SymbolMap[&A_SD];
if (Target.getSymB()) {
const MCSymbol *B = &Target.getSymB()->getSymbol();
MCSymbolData &B_SD = Asm.getSymbolData(*B);
FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD);
// In the case where we have SymbA and SymB, we just need to store the delta
// between the two symbols. Update FixedValue to account for the delta, and
// skip recording the relocation.
return;
} else {
FixedValue = Target.getConstant();
}
COFFRelocation Reloc;
Reloc.Data.SymbolTableIndex = 0;
Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment);
// turn relocations for temporary symbols into section relocations
if (coff_symbol->MCData->getSymbol().isTemporary()) {
Reloc.Symb = coff_symbol->Section->Symbol;
FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment);
} else
Reloc.Symb = coff_symbol;
++Reloc.Symb->Relocations;
Reloc.Data.VirtualAddress += Fixup.getOffset();
switch (Fixup.getKind()) {
case X86::reloc_pcrel_4byte:
case X86::reloc_riprel_4byte:
case X86::reloc_riprel_4byte_movq_load:
Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32
: COFF::IMAGE_REL_I386_REL32;
// FIXME: Can anyone explain what this does other than adjust for the size
// of the offset?
FixedValue += 4;
break;
case FK_Data_4:
case X86::reloc_signed_4byte:
Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32
: COFF::IMAGE_REL_I386_DIR32;
break;
case FK_Data_8:
if (Is64Bit)
Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64;
else
llvm_unreachable("unsupported relocation type");
break;
default:
llvm_unreachable("unsupported relocation type");
}
coff_section->Relocations.push_back(Reloc);
}
bool WinCOFFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm,
const MCValue Target,
bool IsPCRel,
const MCFragment *DF) const {
return false;
}
void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// Assign symbol and section indexes and offsets.
Header.NumberOfSections = 0;
for (sections::iterator i = Sections.begin(),
e = Sections.end(); i != e; i++) {
if (Layout.getSectionSize((*i)->MCData) > 0) {
MakeSectionReal(**i, ++Header.NumberOfSections);
} else {
(*i)->Number = -1;
}
}
Header.NumberOfSymbols = 0;
for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) {
COFFSymbol *coff_symbol = *i;
MCSymbolData const *SymbolData = coff_symbol->MCData;
// Update section number & offset for symbols that have them.
if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) {
assert(coff_symbol->Section != NULL);
coff_symbol->Data.SectionNumber = coff_symbol->Section->Number;
coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment)
+ SymbolData->Offset;
}
if (coff_symbol->should_keep()) {
MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++);
// Update auxiliary symbol info.
coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size();
Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols;
} else
coff_symbol->Index = -1;
}
// Fixup weak external references.
for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) {
COFFSymbol *coff_symbol = *i;
if (coff_symbol->Other != NULL) {
assert(coff_symbol->Index != -1);
assert(coff_symbol->Aux.size() == 1 &&
"Symbol must contain one aux symbol!");
assert(coff_symbol->Aux[0].AuxType == ATWeakExternal &&
"Symbol's aux symbol must be a Weak External!");
coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index;
}
}
// Assign file offsets to COFF object file structures.
unsigned offset = 0;
offset += COFF::HeaderSize;
offset += COFF::SectionSize * Header.NumberOfSections;
for (MCAssembler::const_iterator i = Asm.begin(),
e = Asm.end();
i != e; i++) {
COFFSection *Sec = SectionMap[i];
if (Sec->Number == -1)
continue;
Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i);
if (IsPhysicalSection(Sec)) {
Sec->Header.PointerToRawData = offset;
offset += Sec->Header.SizeOfRawData;
}
if (Sec->Relocations.size() > 0) {
Sec->Header.NumberOfRelocations = Sec->Relocations.size();
Sec->Header.PointerToRelocations = offset;
offset += COFF::RelocationSize * Sec->Relocations.size();
for (relocations::iterator cr = Sec->Relocations.begin(),
er = Sec->Relocations.end();
cr != er; ++cr) {
assert((*cr).Symb->Index != -1);
(*cr).Data.SymbolTableIndex = (*cr).Symb->Index;
}
}
assert(Sec->Symbol->Aux.size() == 1
&& "Section's symbol must have one aux!");
AuxSymbol &Aux = Sec->Symbol->Aux[0];
assert(Aux.AuxType == ATSectionDefinition &&
"Section's symbol's aux symbol must be a Section Definition!");
Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData;
Aux.Aux.SectionDefinition.NumberOfRelocations =
Sec->Header.NumberOfRelocations;
Aux.Aux.SectionDefinition.NumberOfLinenumbers =
Sec->Header.NumberOfLineNumbers;
}
Header.PointerToSymbolTable = offset;
Header.TimeDateStamp = sys::TimeValue::now().toEpochTime();
// Write it all to disk...
WriteFileHeader(Header);
{
sections::iterator i, ie;
MCAssembler::const_iterator j, je;
for (i = Sections.begin(), ie = Sections.end(); i != ie; i++)
if ((*i)->Number != -1)
WriteSectionHeader((*i)->Header);
for (i = Sections.begin(), ie = Sections.end(),
j = Asm.begin(), je = Asm.end();
(i != ie) && (j != je); ++i, ++j) {
if ((*i)->Number == -1)
continue;
if ((*i)->Header.PointerToRawData != 0) {
assert(OS.tell() == (*i)->Header.PointerToRawData &&
"Section::PointerToRawData is insane!");
Asm.WriteSectionData(j, Layout, this);
}
if ((*i)->Relocations.size() > 0) {
assert(OS.tell() == (*i)->Header.PointerToRelocations &&
"Section::PointerToRelocations is insane!");
for (relocations::const_iterator k = (*i)->Relocations.begin(),
ke = (*i)->Relocations.end();
k != ke; k++) {
WriteRelocation(k->Data);
}
} else
assert((*i)->Header.PointerToRelocations == 0 &&
"Section::PointerToRelocations is insane!");
}
}
assert(OS.tell() == Header.PointerToSymbolTable &&
"Header::PointerToSymbolTable is insane!");
for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++)
if ((*i)->Index != -1)
WriteSymbol(*i);
OS.write((char const *)&Strings.Data.front(), Strings.Data.size());
}
//------------------------------------------------------------------------------
// WinCOFFObjectWriter factory function
namespace llvm {
MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) {
return new WinCOFFObjectWriter(OS, is64Bit);
}
}