mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 18:29:46 +00:00
One is that AArch64 has additional restrictions on when local relocations can be used. We have to take those into consideration when deciding to put a L symbol in the symbol table or not. The other is that ld64 requires the relocations to cstring to use linker visible symbols on AArch64. Thanks to Michael Zolotukhin for testing this! Remove doesSectionRequireSymbols. In an assembly expression like bar: .long L0 + 1 the intended semantics is that bar will contain a pointer one byte past L0. In sections that are merged by content (strings, 4 byte constants, etc), a single position in the section doesn't give the linker enough information. For example, it would not be able to tell a relocation must point to the end of a string, since that would look just like the start of the next. The solution used in ELF to use relocation with symbols if there is a non-zero addend. In MachO before this patch we would just keep all symbols in some sections. This would miss some cases (only cstrings on x86_64 were implemented) and was inefficient since most relocations have an addend of 0 and can be represented without the symbol. This patch implements the non-zero addend logic for MachO too. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225644 91177308-0d34-0410-b5e6-96231b3b80d8
199 lines
5.8 KiB
C++
199 lines
5.8 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/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 &) LLVM_DELETED_FUNCTION;
|
|
void operator=(const MCObjectWriter &) LLVM_DELETED_FUNCTION;
|
|
|
|
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();
|
|
|
|
/// 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 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) {
|
|
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(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
|