| //===- 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/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/Endian.h" |
| #include "llvm/Support/EndianStream.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cassert> |
| #include <cstdint> |
| |
| namespace llvm { |
| |
| class MCAsmLayout; |
| class MCAssembler; |
| class MCFixup; |
| class MCFragment; |
| class MCSymbol; |
| class MCSymbolRefExpr; |
| class MCValue; |
| |
| /// 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 { |
| raw_pwrite_stream *OS; |
| |
| protected: |
| unsigned IsLittleEndian : 1; |
| |
| // Can only create subclasses. |
| MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian) |
| : OS(&OS), IsLittleEndian(IsLittleEndian) {} |
| |
| unsigned getInitialOffset() { |
| return OS->tell(); |
| } |
| |
| public: |
| MCObjectWriter(const MCObjectWriter &) = delete; |
| MCObjectWriter &operator=(const MCObjectWriter &) = delete; |
| virtual ~MCObjectWriter(); |
| |
| /// lifetime management |
| virtual void reset() {} |
| |
| bool isLittleEndian() const { return IsLittleEndian; } |
| |
| raw_pwrite_stream &getStream() { return *OS; } |
| void setStream(raw_pwrite_stream &NewOS) { OS = &NewOS; } |
| |
| /// \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, |
| const MCAsmLayout &Layout) = 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(MCAssembler &Asm, const MCAsmLayout &Layout, |
| const MCFragment *Fragment, |
| const MCFixup &Fixup, MCValue Target, |
| bool &IsPCRel, uint64_t &FixedValue) = 0; |
| |
| /// Check whether the difference (A - B) between two symbol references is |
| /// fully resolved. |
| /// |
| /// Clients are not required to answer precisely and may conservatively return |
| /// false, even when a difference is fully resolved. |
| bool isSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, |
| const MCSymbolRefExpr *A, |
| const MCSymbolRefExpr *B, |
| bool InSet) const; |
| |
| virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, |
| const MCSymbol &A, |
| const MCSymbol &B, |
| bool InSet) const; |
| |
| virtual bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, |
| const MCSymbol &SymA, |
| const MCFragment &FB, |
| bool InSet, |
| bool IsPCRel) const; |
| |
| /// Write the object file. |
| /// |
| /// This routine is called by the assembler after layout and relaxation is |
| /// complete, fixups have been evaluated and applied, and relocations |
| /// generated. |
| virtual void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) = 0; |
| |
| /// @} |
| /// \name Binary Output |
| /// @{ |
| |
| void write8(uint8_t Value) { *OS << char(Value); } |
| |
| void writeLE16(uint16_t Value) { |
| support::endian::Writer<support::little>(*OS).write(Value); |
| } |
| |
| void writeLE32(uint32_t Value) { |
| support::endian::Writer<support::little>(*OS).write(Value); |
| } |
| |
| void writeLE64(uint64_t Value) { |
| support::endian::Writer<support::little>(*OS).write(Value); |
| } |
| |
| void writeBE16(uint16_t Value) { |
| support::endian::Writer<support::big>(*OS).write(Value); |
| } |
| |
| void writeBE32(uint32_t Value) { |
| support::endian::Writer<support::big>(*OS).write(Value); |
| } |
| |
| void writeBE64(uint64_t Value) { |
| support::endian::Writer<support::big>(*OS).write(Value); |
| } |
| |
| 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(const SmallVectorImpl<char> &ByteVec, |
| unsigned ZeroFillSize = 0) { |
| writeBytes(StringRef(ByteVec.data(), ByteVec.size()), ZeroFillSize); |
| } |
| |
| void writeBytes(StringRef Str, unsigned ZeroFillSize = 0) { |
| // TODO: this version may need to go away once all fragment contents are |
| // converted to SmallVector<char, N> |
| assert( |
| (ZeroFillSize == 0 || Str.size() <= ZeroFillSize) && |
| "data size greater than fill size, unexpected large write will occur"); |
| *OS << Str; |
| if (ZeroFillSize) |
| WriteZeros(ZeroFillSize - Str.size()); |
| } |
| |
| /// @} |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_MC_MCOBJECTWRITER_H |