mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 06:00:28 +00:00
MC: Split MCObjectWriter out of MCAssembler.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98949 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
bdd9281f35
commit
53b2338a1d
@ -26,6 +26,7 @@ class MCAssembler;
|
||||
class MCContext;
|
||||
class MCExpr;
|
||||
class MCFragment;
|
||||
class MCObjectWriter;
|
||||
class MCSection;
|
||||
class MCSectionData;
|
||||
class MCSymbol;
|
||||
@ -618,6 +619,23 @@ private:
|
||||
unsigned SubsectionsViaSymbols : 1;
|
||||
|
||||
private:
|
||||
/// Evaluate a fixup to a relocatable expression and the value which should be
|
||||
/// placed into the fixup.
|
||||
///
|
||||
/// \param Layout The layout to use for evaluation.
|
||||
/// \param Fixup The fixup to evaluate.
|
||||
/// \param DF The fragment the fixup is inside.
|
||||
/// \param Target [out] On return, the relocatable expression the fixup
|
||||
/// evaluates to.
|
||||
/// \param Value [out] On return, the value of the fixup as currently layed
|
||||
/// out.
|
||||
/// \return Whether the fixup value was fully resolved. This is true if the
|
||||
/// \arg Value result is fixed, otherwise the value may change due to
|
||||
/// relocation.
|
||||
bool EvaluateFixup(const MCAsmLayout &Layout,
|
||||
MCAsmFixup &Fixup, MCDataFragment *DF,
|
||||
MCValue &Target, uint64_t &Value) const;
|
||||
|
||||
/// Check whether a fixup can be satisfied, or whether it needs to be relaxed
|
||||
/// (increased in size, in order to hold its value correctly).
|
||||
bool FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF);
|
||||
@ -631,7 +649,6 @@ private:
|
||||
/// were adjusted.
|
||||
bool LayoutOnce();
|
||||
|
||||
// FIXME: Make protected once we factor out object writer classes.
|
||||
public:
|
||||
/// Find the symbol which defines the atom containing given address, inside
|
||||
/// the given section, or null if there is no such symbol.
|
||||
@ -652,22 +669,10 @@ public:
|
||||
/// defining a separate atom.
|
||||
bool isSymbolLinkerVisible(const MCSymbolData *SD) const;
|
||||
|
||||
/// Evaluate a fixup to a relocatable expression and the value which should be
|
||||
/// placed into the fixup.
|
||||
///
|
||||
/// \param Layout The layout to use for evaluation.
|
||||
/// \param Fixup The fixup to evaluate.
|
||||
/// \param DF The fragment the fixup is inside.
|
||||
/// \param Target [out] On return, the relocatable expression the fixup
|
||||
/// evaluates to.
|
||||
/// \param Value [out] On return, the value of the fixup as currently layed
|
||||
/// out.
|
||||
/// \return Whether the fixup value was fully resolved. This is true if the
|
||||
/// \arg Value result is fixed, otherwise the value may change due to
|
||||
/// relocation.
|
||||
bool EvaluateFixup(const MCAsmLayout &Layout,
|
||||
MCAsmFixup &Fixup, MCDataFragment *DF,
|
||||
MCValue &Target, uint64_t &Value) const;
|
||||
/// Emit the section contents using the given object writer.
|
||||
//
|
||||
// FIXME: Should MCAssembler always have a reference to the object writer?
|
||||
void WriteSectionData(const MCSectionData *Section, MCObjectWriter *OW) const;
|
||||
|
||||
public:
|
||||
/// Construct a new assembler instance.
|
||||
|
162
include/llvm/MC/MCObjectWriter.h
Normal file
162
include/llvm/MC/MCObjectWriter.h
Normal file
@ -0,0 +1,162 @@
|
||||
//===-- llvm/MC/MCObjectWriter.h - Object File Writer Interface -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_MC_MCOBJECTWRITER_H
|
||||
#define LLVM_MC_MCOBJECTWRITER_H
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class MCAsmFixup;
|
||||
class MCAssembler;
|
||||
class MCDataFragment;
|
||||
class MCValue;
|
||||
class raw_ostream;
|
||||
|
||||
/// MCObjectWriter - Defines the object file and target independent interfaces
|
||||
/// used by the assembler backend to write native file format object files.
|
||||
///
|
||||
/// The object writer contains a few callbacks used by the assembler to allow
|
||||
/// the object writer to modify the assembler data structures at appropriate
|
||||
/// points. Once assembly is complete, the object writer is given the
|
||||
/// MCAssembler instance, which contains all the symbol and section data which
|
||||
/// should be emitted as part of WriteObject().
|
||||
///
|
||||
/// The object writer also contains a number of helper methods for writing
|
||||
/// binary data to the output stream.
|
||||
class MCObjectWriter {
|
||||
MCObjectWriter(const MCObjectWriter &); // DO NOT IMPLEMENT
|
||||
void operator=(const MCObjectWriter &); // DO NOT IMPLEMENT
|
||||
|
||||
protected:
|
||||
raw_ostream &OS;
|
||||
|
||||
unsigned IsLittleEndian : 1;
|
||||
|
||||
protected: // Can only create subclasses.
|
||||
MCObjectWriter(raw_ostream &_OS, bool _IsLittleEndian)
|
||||
: OS(_OS), IsLittleEndian(_IsLittleEndian) {}
|
||||
|
||||
public:
|
||||
virtual ~MCObjectWriter();
|
||||
|
||||
bool isLittleEndian() { return IsLittleEndian; }
|
||||
|
||||
raw_ostream &getStream() { return OS; }
|
||||
|
||||
/// @name High-Level API
|
||||
/// @{
|
||||
|
||||
/// Perform any late binding of symbols (for example, to assign symbol indices
|
||||
/// for use when generating relocations).
|
||||
///
|
||||
/// This routine is called by the assembler after layout and relaxation is
|
||||
/// complete.
|
||||
virtual void ExecutePostLayoutBinding(MCAssembler &Asm) = 0;
|
||||
|
||||
/// Record a relocation entry.
|
||||
///
|
||||
/// This routine is called by the assembler after layout and relaxation, and
|
||||
/// post layout binding. The implementation is responsible for storing
|
||||
/// information about the relocation so that it can be emitted during
|
||||
/// WriteObject().
|
||||
virtual void RecordRelocation(const MCAssembler &Asm,
|
||||
const MCDataFragment &Fragment,
|
||||
const MCAsmFixup &Fixup, MCValue Target,
|
||||
uint64_t &FixedValue) = 0;
|
||||
|
||||
/// Write the object file.
|
||||
///
|
||||
/// This routine is called by the assembler after layout and relaxation is
|
||||
/// complete, fixups have been evaluate and applied, and relocations
|
||||
/// generated.
|
||||
virtual void WriteObject(const MCAssembler &Asm) = 0;
|
||||
|
||||
/// @}
|
||||
/// @name Binary Output
|
||||
/// @{
|
||||
|
||||
void Write8(uint8_t Value) {
|
||||
OS << char(Value);
|
||||
}
|
||||
|
||||
void WriteLE16(uint16_t Value) {
|
||||
Write8(uint8_t(Value >> 0));
|
||||
Write8(uint8_t(Value >> 8));
|
||||
}
|
||||
|
||||
void WriteLE32(uint32_t Value) {
|
||||
WriteLE16(uint16_t(Value >> 0));
|
||||
WriteLE16(uint16_t(Value >> 16));
|
||||
}
|
||||
|
||||
void WriteLE64(uint64_t Value) {
|
||||
WriteLE32(uint32_t(Value >> 0));
|
||||
WriteLE32(uint32_t(Value >> 32));
|
||||
}
|
||||
|
||||
void WriteBE16(uint16_t Value) {
|
||||
Write8(uint8_t(Value >> 8));
|
||||
Write8(uint8_t(Value >> 0));
|
||||
}
|
||||
|
||||
void WriteBE32(uint32_t Value) {
|
||||
WriteBE16(uint16_t(Value >> 16));
|
||||
WriteBE16(uint16_t(Value >> 0));
|
||||
}
|
||||
|
||||
void WriteBE64(uint64_t Value) {
|
||||
WriteBE32(uint32_t(Value >> 32));
|
||||
WriteBE32(uint32_t(Value >> 0));
|
||||
}
|
||||
|
||||
void Write16(uint16_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE16(Value);
|
||||
else
|
||||
WriteBE16(Value);
|
||||
}
|
||||
|
||||
void Write32(uint32_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE32(Value);
|
||||
else
|
||||
WriteBE32(Value);
|
||||
}
|
||||
|
||||
void Write64(uint64_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE64(Value);
|
||||
else
|
||||
WriteBE64(Value);
|
||||
}
|
||||
|
||||
void WriteZeros(unsigned N) {
|
||||
const char Zeros[16] = { 0 };
|
||||
|
||||
for (unsigned i = 0, e = N / 16; i != e; ++i)
|
||||
OS << StringRef(Zeros, 16);
|
||||
|
||||
OS << StringRef(Zeros, N % 16);
|
||||
}
|
||||
|
||||
void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) {
|
||||
OS << Str;
|
||||
if (ZeroFillSize)
|
||||
WriteZeros(ZeroFillSize - Str.size());
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -12,6 +12,7 @@ add_llvm_library(LLVMMC
|
||||
MCInstPrinter.cpp
|
||||
MCMachOStreamer.cpp
|
||||
MCNullStreamer.cpp
|
||||
MCObjectWriter.cpp
|
||||
MCSection.cpp
|
||||
MCSectionELF.cpp
|
||||
MCSectionMachO.cpp
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCAsmLayout.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
@ -42,10 +43,6 @@ STATISTIC(EmittedFragments, "Number of emitted assembler fragments");
|
||||
// object file, which may truncate it. We should detect that truncation where
|
||||
// invalid and report errors back.
|
||||
|
||||
class MCObjectWriter;
|
||||
static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
|
||||
MCObjectWriter *MOW);
|
||||
|
||||
/// isVirtualSection - Check if this is a section which does not actually exist
|
||||
/// in the object file.
|
||||
static bool isVirtualSection(const MCSection &Section) {
|
||||
@ -78,105 +75,6 @@ static bool isFixupKindPCRel(unsigned Kind) {
|
||||
}
|
||||
}
|
||||
|
||||
class MCObjectWriter {
|
||||
MCObjectWriter(const MCObjectWriter &); // DO NOT IMPLEMENT
|
||||
void operator=(const MCObjectWriter &); // DO NOT IMPLEMENT
|
||||
|
||||
protected:
|
||||
raw_ostream &OS;
|
||||
|
||||
unsigned IsLittleEndian : 1;
|
||||
|
||||
protected: // Can only create subclasses.
|
||||
MCObjectWriter(raw_ostream &_OS, bool _IsLittleEndian)
|
||||
: OS(_OS), IsLittleEndian(_IsLittleEndian) {}
|
||||
virtual ~MCObjectWriter();
|
||||
|
||||
public:
|
||||
|
||||
bool isLittleEndian() { return IsLittleEndian; }
|
||||
|
||||
raw_ostream &getStream() { return OS; }
|
||||
|
||||
/// @name Binary Output Methods
|
||||
/// @{
|
||||
|
||||
void Write8(uint8_t Value) {
|
||||
OS << char(Value);
|
||||
}
|
||||
|
||||
void WriteLE16(uint16_t Value) {
|
||||
Write8(uint8_t(Value >> 0));
|
||||
Write8(uint8_t(Value >> 8));
|
||||
}
|
||||
|
||||
void WriteLE32(uint32_t Value) {
|
||||
WriteLE16(uint16_t(Value >> 0));
|
||||
WriteLE16(uint16_t(Value >> 16));
|
||||
}
|
||||
|
||||
void WriteLE64(uint64_t Value) {
|
||||
WriteLE32(uint32_t(Value >> 0));
|
||||
WriteLE32(uint32_t(Value >> 32));
|
||||
}
|
||||
|
||||
void WriteBE16(uint16_t Value) {
|
||||
Write8(uint8_t(Value >> 8));
|
||||
Write8(uint8_t(Value >> 0));
|
||||
}
|
||||
|
||||
void WriteBE32(uint32_t Value) {
|
||||
WriteBE16(uint16_t(Value >> 16));
|
||||
WriteBE16(uint16_t(Value >> 0));
|
||||
}
|
||||
|
||||
void WriteBE64(uint64_t Value) {
|
||||
WriteBE32(uint32_t(Value >> 32));
|
||||
WriteBE32(uint32_t(Value >> 0));
|
||||
}
|
||||
|
||||
void Write16(uint16_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE16(Value);
|
||||
else
|
||||
WriteBE16(Value);
|
||||
}
|
||||
|
||||
void Write32(uint32_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE32(Value);
|
||||
else
|
||||
WriteBE32(Value);
|
||||
}
|
||||
|
||||
void Write64(uint64_t Value) {
|
||||
if (IsLittleEndian)
|
||||
WriteLE64(Value);
|
||||
else
|
||||
WriteBE64(Value);
|
||||
}
|
||||
|
||||
void WriteZeros(unsigned N) {
|
||||
const char Zeros[16] = { 0 };
|
||||
|
||||
for (unsigned i = 0, e = N / 16; i != e; ++i)
|
||||
OS << StringRef(Zeros, 16);
|
||||
|
||||
OS << StringRef(Zeros, N % 16);
|
||||
}
|
||||
|
||||
void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) {
|
||||
OS << Str;
|
||||
if (ZeroFillSize)
|
||||
WriteZeros(ZeroFillSize - Str.size());
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
MCObjectWriter::~MCObjectWriter() {
|
||||
}
|
||||
|
||||
class MachObjectWriter : public MCObjectWriter {
|
||||
// See <mach-o/loader.h>.
|
||||
enum {
|
||||
@ -362,8 +260,9 @@ public:
|
||||
assert(OS.tell() - Start == SegmentLoadCommandSize);
|
||||
}
|
||||
|
||||
void WriteSection(const MCSectionData &SD, uint64_t FileOffset,
|
||||
uint64_t RelocationsStart, unsigned NumRelocations) {
|
||||
void WriteSection(const MCAssembler &Asm, const MCSectionData &SD,
|
||||
uint64_t FileOffset, uint64_t RelocationsStart,
|
||||
unsigned NumRelocations) {
|
||||
// The offset is unused for virtual sections.
|
||||
if (isVirtualSection(SD.getSection())) {
|
||||
assert(SD.getFileSize() == 0 && "Invalid file size!");
|
||||
@ -527,7 +426,8 @@ public:
|
||||
Write32(Address);
|
||||
}
|
||||
|
||||
void RecordScatteredRelocation(MCAssembler &Asm, MCFragment &Fragment,
|
||||
void RecordScatteredRelocation(const MCAssembler &Asm,
|
||||
const MCFragment &Fragment,
|
||||
const MCAsmFixup &Fixup, MCValue Target,
|
||||
uint64_t &FixedValue) {
|
||||
uint32_t Address = Fragment.getOffset() + Fixup.Offset;
|
||||
@ -584,7 +484,8 @@ public:
|
||||
Relocations[Fragment.getParent()].push_back(MRE);
|
||||
}
|
||||
|
||||
void RecordRelocation(MCAssembler &Asm, MCDataFragment &Fragment,
|
||||
virtual void RecordRelocation(const MCAssembler &Asm,
|
||||
const MCDataFragment &Fragment,
|
||||
const MCAsmFixup &Fixup, MCValue Target,
|
||||
uint64_t &FixedValue) {
|
||||
unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
|
||||
@ -629,7 +530,7 @@ public:
|
||||
//
|
||||
// FIXME: O(N)
|
||||
Index = 1;
|
||||
MCAssembler::iterator it = Asm.begin(), ie = Asm.end();
|
||||
MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
|
||||
for (; it != ie; ++it, ++Index)
|
||||
if (&*it == SD->getFragment()->getParent())
|
||||
break;
|
||||
@ -807,7 +708,7 @@ public:
|
||||
StringTable += '\x00';
|
||||
}
|
||||
|
||||
void ExecutePostLayoutBinding(MCAssembler &Asm) {
|
||||
virtual void ExecutePostLayoutBinding(MCAssembler &Asm) {
|
||||
// Create symbol data for any indirect symbols.
|
||||
BindIndirectSymbols(Asm);
|
||||
|
||||
@ -816,7 +717,7 @@ public:
|
||||
UndefinedSymbolData);
|
||||
}
|
||||
|
||||
void WriteObject(const MCAssembler &Asm) {
|
||||
virtual void WriteObject(const MCAssembler &Asm) {
|
||||
unsigned NumSections = Asm.size();
|
||||
|
||||
// The section data starts after the header, the segment load command (and
|
||||
@ -916,7 +817,7 @@ public:
|
||||
// Write the actual section data.
|
||||
for (MCAssembler::const_iterator it = Asm.begin(),
|
||||
ie = Asm.end(); it != ie; ++it)
|
||||
WriteFileData(OS, *it, this);
|
||||
Asm.WriteSectionData(it, this);
|
||||
|
||||
// Write the extra padding.
|
||||
WriteZeros(SectionDataPadding);
|
||||
@ -1357,10 +1258,9 @@ static uint64_t WriteNopData(uint64_t Count, MCObjectWriter *OW) {
|
||||
return Count;
|
||||
}
|
||||
|
||||
/// WriteFileData - Write the \arg F data to the output file.
|
||||
static void WriteFileData(raw_ostream &OS, const MCFragment &F,
|
||||
MCObjectWriter *OW) {
|
||||
uint64_t Start = OS.tell();
|
||||
/// WriteFragmentData - Write the \arg F data to the output file.
|
||||
static void WriteFragmentData(const MCFragment &F, MCObjectWriter *OW) {
|
||||
uint64_t Start = OW->getStream().tell();
|
||||
(void) Start;
|
||||
|
||||
++EmittedFragments;
|
||||
@ -1402,7 +1302,7 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
|
||||
}
|
||||
|
||||
case MCFragment::FT_Data: {
|
||||
OS << cast<MCDataFragment>(F).getContents().str();
|
||||
OW->WriteBytes(cast<MCDataFragment>(F).getContents().str());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1436,30 +1336,29 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
|
||||
}
|
||||
}
|
||||
|
||||
assert(OS.tell() - Start == F.getFileSize());
|
||||
assert(OW->getStream().tell() - Start == F.getFileSize());
|
||||
}
|
||||
|
||||
/// WriteFileData - Write the \arg SD data to the output file.
|
||||
static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
|
||||
MCObjectWriter *OW) {
|
||||
void MCAssembler::WriteSectionData(const MCSectionData *SD,
|
||||
MCObjectWriter *OW) const {
|
||||
// Ignore virtual sections.
|
||||
if (isVirtualSection(SD.getSection())) {
|
||||
assert(SD.getFileSize() == 0);
|
||||
if (isVirtualSection(SD->getSection())) {
|
||||
assert(SD->getFileSize() == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t Start = OS.tell();
|
||||
uint64_t Start = OW->getStream().tell();
|
||||
(void) Start;
|
||||
|
||||
for (MCSectionData::const_iterator it = SD.begin(),
|
||||
ie = SD.end(); it != ie; ++it)
|
||||
WriteFileData(OS, *it, OW);
|
||||
for (MCSectionData::const_iterator it = SD->begin(),
|
||||
ie = SD->end(); it != ie; ++it)
|
||||
WriteFragmentData(*it, OW);
|
||||
|
||||
// Add section padding.
|
||||
assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!");
|
||||
OW->WriteZeros(SD.getFileSize() - SD.getSize());
|
||||
assert(SD->getFileSize() >= SD->getSize() && "Invalid section sizes!");
|
||||
OW->WriteZeros(SD->getFileSize() - SD->getSize());
|
||||
|
||||
assert(OS.tell() - Start == SD.getFileSize());
|
||||
assert(OW->getStream().tell() - Start == SD->getFileSize());
|
||||
}
|
||||
|
||||
void MCAssembler::Finish() {
|
||||
|
15
lib/MC/MCObjectWriter.cpp
Normal file
15
lib/MC/MCObjectWriter.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
//===- lib/MC/MCObjetWriter.cpp - MCObjetWriter implementation ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
MCObjectWriter::~MCObjectWriter() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user