f785676f2a
all of the features in the current working draft of the upcoming C++ standard, provisionally named C++1y. The code generator's performance is greatly increased, and the loop auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The PowerPC backend has made several major improvements to code generation quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ backends have all seen major feature work. Release notes for llvm and clang can be found here: <http://llvm.org/releases/3.4/docs/ReleaseNotes.html> <http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html> MFC after: 1 month
930 lines
31 KiB
C++
930 lines
31 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/MCWinCOFFObjectWriter.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/MC/MCAsmLayout.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/MC/MCSection.h"
|
|
#include "llvm/MC/MCSectionCOFF.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/MC/MCValue.h"
|
|
#include "llvm/Support/COFF.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/TimeValue.h"
|
|
#include <cstdio>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
typedef 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 SmallVector<AuxSymbol, 1> AuxiliarySymbols;
|
|
|
|
name Name;
|
|
int Index;
|
|
AuxiliarySymbols Aux;
|
|
COFFSymbol *Other;
|
|
COFFSection *Section;
|
|
int Relocations;
|
|
|
|
MCSymbolData const *MCData;
|
|
|
|
COFFSymbol(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(StringRef name);
|
|
static size_t size();
|
|
};
|
|
|
|
// This class holds the COFF string table.
|
|
class StringTable {
|
|
typedef StringMap<size_t> map;
|
|
map Map;
|
|
|
|
void update_length();
|
|
public:
|
|
std::vector<char> Data;
|
|
|
|
StringTable();
|
|
size_t size() const;
|
|
size_t insert(StringRef String);
|
|
};
|
|
|
|
class WinCOFFObjectWriter : public MCObjectWriter {
|
|
public:
|
|
|
|
typedef std::vector<COFFSymbol*> symbols;
|
|
typedef std::vector<COFFSection*> sections;
|
|
|
|
typedef DenseMap<MCSymbol const *, COFFSymbol *> symbol_map;
|
|
typedef DenseMap<MCSection const *, COFFSection *> section_map;
|
|
|
|
llvm::OwningPtr<MCWinCOFFObjectTargetWriter> TargetObjectWriter;
|
|
|
|
// Root level file contents.
|
|
COFF::header Header;
|
|
sections Sections;
|
|
symbols Symbols;
|
|
StringTable Strings;
|
|
|
|
// Maps used during object file creation.
|
|
section_map SectionMap;
|
|
symbol_map SymbolMap;
|
|
|
|
WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, raw_ostream &OS);
|
|
virtual ~WinCOFFObjectWriter();
|
|
|
|
COFFSymbol *createSymbol(StringRef Name);
|
|
COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol * Symbol);
|
|
COFFSection *createSection(StringRef Name);
|
|
|
|
template <typename object_t, typename list_t>
|
|
object_t *createCOFFEntity(StringRef Name, list_t &List);
|
|
|
|
void DefineSection(MCSectionData const &SectionData);
|
|
void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler,
|
|
const MCAsmLayout &Layout);
|
|
|
|
void MakeSymbolReal(COFFSymbol &S, size_t Index);
|
|
void MakeSectionReal(COFFSection &S, size_t Number);
|
|
|
|
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, const MCAsmLayout &Layout);
|
|
|
|
void RecordRelocation(const MCAssembler &Asm,
|
|
const MCAsmLayout &Layout,
|
|
const MCFragment *Fragment,
|
|
const MCFixup &Fixup,
|
|
MCValue Target,
|
|
uint64_t &FixedValue);
|
|
|
|
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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Symbol class implementation
|
|
|
|
COFFSymbol::COFFSymbol(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(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);
|
|
update_length();
|
|
}
|
|
|
|
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(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(MCWinCOFFObjectTargetWriter *MOTW,
|
|
raw_ostream &OS)
|
|
: MCObjectWriter(OS, true)
|
|
, TargetObjectWriter(MOTW) {
|
|
memset(&Header, 0, sizeof(Header));
|
|
|
|
Header.Machine = TargetObjectWriter->getMachine();
|
|
}
|
|
|
|
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(StringRef Name) {
|
|
return createCOFFEntity<COFFSymbol>(Name, Symbols);
|
|
}
|
|
|
|
COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol * Symbol){
|
|
symbol_map::iterator i = SymbolMap.find(Symbol);
|
|
if (i != SymbolMap.end())
|
|
return i->second;
|
|
COFFSymbol *RetSymbol
|
|
= createCOFFEntity<COFFSymbol>(Symbol->getName(), Symbols);
|
|
SymbolMap[Symbol] = RetSymbol;
|
|
return RetSymbol;
|
|
}
|
|
|
|
COFFSection *WinCOFFObjectWriter::createSection(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(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) {
|
|
assert(SectionData.getSection().getVariant() == MCSection::SV_COFF
|
|
&& "Got non COFF section in the COFF backend!");
|
|
// 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.getSection()] = 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,
|
|
const MCAsmLayout &Layout) {
|
|
MCSymbol const &Symbol = SymbolData.getSymbol();
|
|
COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol);
|
|
SymbolMap[&Symbol] = coff_symbol;
|
|
|
|
if (SymbolData.getFlags() & COFF::SF_WeakExternal) {
|
|
coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
|
|
|
|
if (Symbol.isVariable()) {
|
|
const MCSymbolRefExpr *SymRef =
|
|
dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue());
|
|
|
|
if (!SymRef)
|
|
report_fatal_error("Weak externals may only alias symbols");
|
|
|
|
coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol());
|
|
} else {
|
|
std::string WeakName = std::string(".weak.")
|
|
+ Symbol.getName().str()
|
|
+ ".default";
|
|
COFFSymbol *WeakDefault = createSymbol(WeakName);
|
|
WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
|
|
WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL;
|
|
WeakDefault->Data.Type = 0;
|
|
WeakDefault->Data.Value = 0;
|
|
coff_symbol->Other = WeakDefault;
|
|
}
|
|
|
|
// 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;
|
|
|
|
coff_symbol->MCData = &SymbolData;
|
|
} else {
|
|
const MCSymbolData &ResSymData =
|
|
Assembler.getSymbolData(Symbol.AliasedSymbol());
|
|
|
|
if (Symbol.isVariable()) {
|
|
int64_t Addr;
|
|
if (Symbol.getVariableValue()->EvaluateAsAbsolute(Addr, Layout))
|
|
coff_symbol->Data.Value = Addr;
|
|
}
|
|
|
|
coff_symbol->Data.Type = (ResSymData.getFlags() & 0x0000FFFF) >> 0;
|
|
coff_symbol->Data.StorageClass = (ResSymData.getFlags() & 0x00FF0000) >> 16;
|
|
|
|
// If no storage class was specified in the streamer, define it here.
|
|
if (coff_symbol->Data.StorageClass == 0) {
|
|
bool external = ResSymData.isExternal() || (ResSymData.Fragment == NULL);
|
|
|
|
coff_symbol->Data.StorageClass =
|
|
external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC;
|
|
}
|
|
|
|
if (Symbol.isAbsolute() || Symbol.AliasedSymbol().isVariable())
|
|
coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
|
|
else if (ResSymData.Fragment != NULL)
|
|
coff_symbol->Section =
|
|
SectionMap[&ResSymData.Fragment->getParent()->getSection()];
|
|
|
|
coff_symbol->MCData = &ResSymData;
|
|
}
|
|
}
|
|
|
|
/// 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) {
|
|
const unsigned Max6DecimalSize = 999999;
|
|
const unsigned Max7DecimalSize = 9999999;
|
|
uint64_t StringTableEntry = Strings.insert(S.Name.c_str());
|
|
|
|
if (StringTableEntry <= Max6DecimalSize) {
|
|
std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry));
|
|
} else if (StringTableEntry <= Max7DecimalSize) {
|
|
// With seven digits, we have to skip the terminating null. Because
|
|
// sprintf always appends it, we use a larger temporary buffer.
|
|
char buffer[9] = { };
|
|
std::sprintf(buffer, "/%d", unsigned(StringTableEntry));
|
|
std::memcpy(S.Header.Name, buffer, 8);
|
|
} else {
|
|
report_fatal_error("COFF string table is greater than 9,999,999 bytes.");
|
|
}
|
|
} 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::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.isExternal() || !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,
|
|
const MCAsmLayout &Layout) {
|
|
// "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, Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 &Symbol = Target.getSymA()->getSymbol();
|
|
const MCSymbol &A = Symbol.AliasedSymbol();
|
|
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->getSection()) != SectionMap.end() &&
|
|
"Section must already have been defined in ExecutePostLayoutBinding!");
|
|
assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() &&
|
|
"Symbol must already have been defined in ExecutePostLayoutBinding!");
|
|
|
|
COFFSection *coff_section = SectionMap[&SectionData->getSection()];
|
|
COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()];
|
|
const MCSymbolRefExpr *SymA = Target.getSymA();
|
|
const MCSymbolRefExpr *SymB = Target.getSymB();
|
|
const bool CrossSection = SymB &&
|
|
&SymA->getSymbol().getSection() != &SymB->getSymbol().getSection();
|
|
|
|
if (Target.getSymB()) {
|
|
const MCSymbol *B = &Target.getSymB()->getSymbol();
|
|
MCSymbolData &B_SD = Asm.getSymbolData(*B);
|
|
|
|
// Offset of the symbol in the section
|
|
int64_t a = Layout.getSymbolOffset(&B_SD);
|
|
|
|
// Ofeset of the relocation in the section
|
|
int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
|
|
|
|
FixedValue = b - a;
|
|
// 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.
|
|
if (!CrossSection)
|
|
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() || CrossSection) {
|
|
Reloc.Symb = coff_symbol->Section->Symbol;
|
|
FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment)
|
|
+ coff_symbol->MCData->getOffset();
|
|
} else
|
|
Reloc.Symb = coff_symbol;
|
|
|
|
++Reloc.Symb->Relocations;
|
|
|
|
Reloc.Data.VirtualAddress += Fixup.getOffset();
|
|
Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup,
|
|
CrossSection);
|
|
|
|
// FIXME: Can anyone explain what this does other than adjust for the size
|
|
// of the offset?
|
|
if (Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32 ||
|
|
Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32)
|
|
FixedValue += 4;
|
|
|
|
coff_section->Relocations.push_back(Reloc);
|
|
}
|
|
|
|
void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,
|
|
const MCAsmLayout &Layout) {
|
|
// Assign symbol and section indexes and offsets.
|
|
Header.NumberOfSections = 0;
|
|
|
|
DenseMap<COFFSection *, uint16_t> SectionIndices;
|
|
for (sections::iterator i = Sections.begin(),
|
|
e = Sections.end(); i != e; i++) {
|
|
if (Layout.getSectionAddressSize((*i)->MCData) > 0) {
|
|
size_t Number = ++Header.NumberOfSections;
|
|
SectionIndices[*i] = Number;
|
|
MakeSectionReal(**i, Number);
|
|
} 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;
|
|
}
|
|
}
|
|
|
|
// Fixup associative COMDAT sections.
|
|
for (sections::iterator i = Sections.begin(),
|
|
e = Sections.end(); i != e; i++) {
|
|
if ((*i)->Symbol->Aux[0].Aux.SectionDefinition.Selection !=
|
|
COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
|
|
continue;
|
|
|
|
const MCSectionCOFF &MCSec = static_cast<const MCSectionCOFF &>(
|
|
(*i)->MCData->getSection());
|
|
|
|
COFFSection *Assoc = SectionMap.lookup(MCSec.getAssocSection());
|
|
if (!Assoc) {
|
|
report_fatal_error(Twine("Missing associated COMDAT section ") +
|
|
MCSec.getAssocSection()->getSectionName() +
|
|
" for section " + MCSec.getSectionName());
|
|
}
|
|
|
|
// Skip this section if the associated section is unused.
|
|
if (Assoc->Number == -1)
|
|
continue;
|
|
|
|
(*i)->Symbol->Aux[0].Aux.SectionDefinition.Number = SectionIndices[Assoc];
|
|
}
|
|
|
|
|
|
// 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->getSection()];
|
|
|
|
if (Sec->Number == -1)
|
|
continue;
|
|
|
|
Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i);
|
|
|
|
if (IsPhysicalSection(Sec)) {
|
|
Sec->Header.PointerToRawData = offset;
|
|
|
|
offset += Sec->Header.SizeOfRawData;
|
|
}
|
|
|
|
if (Sec->Relocations.size() > 0) {
|
|
bool RelocationsOverflow = Sec->Relocations.size() >= 0xffff;
|
|
|
|
if (RelocationsOverflow) {
|
|
// Signal overflow by setting NumberOfSections to max value. Actual
|
|
// size is found in reloc #0. Microsoft tools understand this.
|
|
Sec->Header.NumberOfRelocations = 0xffff;
|
|
} else {
|
|
Sec->Header.NumberOfRelocations = Sec->Relocations.size();
|
|
}
|
|
Sec->Header.PointerToRelocations = offset;
|
|
|
|
if (RelocationsOverflow) {
|
|
// Reloc #0 will contain actual count, so make room for it.
|
|
offset += COFF::RelocationSize;
|
|
}
|
|
|
|
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) {
|
|
if ((*i)->Relocations.size() >= 0xffff) {
|
|
(*i)->Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
|
|
}
|
|
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);
|
|
}
|
|
|
|
if ((*i)->Relocations.size() > 0) {
|
|
assert(OS.tell() == (*i)->Header.PointerToRelocations &&
|
|
"Section::PointerToRelocations is insane!");
|
|
|
|
if ((*i)->Relocations.size() >= 0xffff) {
|
|
// In case of overflow, write actual relocation count as first
|
|
// relocation. Including the synthetic reloc itself (+ 1).
|
|
COFF::relocation r;
|
|
r.VirtualAddress = (*i)->Relocations.size() + 1;
|
|
r.SymbolTableIndex = 0;
|
|
r.Type = 0;
|
|
WriteRelocation(r);
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) :
|
|
Machine(Machine_) {
|
|
}
|
|
|
|
// Pin the vtable to this file.
|
|
void MCWinCOFFObjectTargetWriter::anchor() {}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// WinCOFFObjectWriter factory function
|
|
|
|
namespace llvm {
|
|
MCObjectWriter *createWinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW,
|
|
raw_ostream &OS) {
|
|
return new WinCOFFObjectWriter(MOTW, OS);
|
|
}
|
|
}
|