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:
Daniel Dunbar 2010-03-19 09:28:59 +00:00
parent bdd9281f35
commit 53b2338a1d
5 changed files with 230 additions and 148 deletions

View File

@ -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.

View 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

View File

@ -12,6 +12,7 @@ add_llvm_library(LLVMMC
MCInstPrinter.cpp
MCMachOStreamer.cpp
MCNullStreamer.cpp
MCObjectWriter.cpp
MCSection.cpp
MCSectionELF.cpp
MCSectionMachO.cpp

View File

@ -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
View 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() {
}