mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-16 11:30:51 +00:00
fb118bd226
Similar to r235222, but for the weak symbol case. In an "ideal" assembler/object format an expression would always refer to the final value and A-B would only be computed from a section in the same comdat as A and B with A and B strong. Unfortunately that is not the case with debug info on ELF, so we need an heuristic. Since we need an heuristic, we may as well use the same one as gas: * call weak_sym : produces a relocation, even if in the same section. * A - weak_sym and weak_sym -A: don't produce a relocation if we can compute it. This fixes pr23272 and changes the fix of pr22815 to match what gas does. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235227 91177308-0d34-0410-b5e6-96231b3b80d8
197 lines
6.1 KiB
C++
197 lines
6.1 KiB
C++
//===-- 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/Support/Compiler.h"
|
|
#include "llvm/Support/DataTypes.h"
|
|
#include "llvm/Support/EndianStream.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
|
|
namespace llvm {
|
|
class MCAsmLayout;
|
|
class MCAssembler;
|
|
class MCFixup;
|
|
class MCFragment;
|
|
class MCSymbolData;
|
|
class MCSymbolRefExpr;
|
|
class MCValue;
|
|
|
|
/// 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 &) = delete;
|
|
void operator=(const MCObjectWriter &) = delete;
|
|
|
|
protected:
|
|
raw_pwrite_stream &OS;
|
|
|
|
unsigned IsLittleEndian : 1;
|
|
|
|
protected: // Can only create subclasses.
|
|
MCObjectWriter(raw_pwrite_stream &OS, bool IsLittleEndian)
|
|
: OS(OS), IsLittleEndian(IsLittleEndian) {}
|
|
|
|
public:
|
|
virtual ~MCObjectWriter();
|
|
|
|
/// lifetime management
|
|
virtual void reset() { }
|
|
|
|
bool isLittleEndian() const { return IsLittleEndian; }
|
|
|
|
raw_ostream &getStream() { return OS; }
|
|
|
|
/// @name High-Level API
|
|
/// @{
|
|
|
|
/// \brief 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;
|
|
|
|
/// \brief 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;
|
|
|
|
/// \brief 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 MCSymbolData &DataA,
|
|
const MCFragment &FB,
|
|
bool InSet,
|
|
bool IsPCRel) const;
|
|
|
|
/// \brief True if this symbol (which is a variable) is weak. This is not
|
|
/// just STB_WEAK, but more generally whether or not we can evaluate
|
|
/// past it.
|
|
virtual bool isWeak(const MCSymbolData &SD) const;
|
|
|
|
/// \brief 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 llvm namespace
|
|
|
|
#endif
|