110 lines
4.7 KiB
C++
110 lines
4.7 KiB
C++
//===-- W65816ELFObjectWriter.cpp - W65816 ELF Writer ---------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// W65816 ELF object writer. Emits objects with e_machine = EM_W65816
|
|
// (0xFF16, vendor-private slot) and a small set of R_W65816_* relocation
|
|
// types decoded by link816 and the AsmPrinter test path.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/W65816FixupKinds.h"
|
|
#include "MCTargetDesc/W65816MCTargetDesc.h"
|
|
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
#include "llvm/MC/MCELFObjectWriter.h"
|
|
#include "llvm/MC/MCFixup.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/MC/MCValue.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
using namespace llvm;
|
|
|
|
// R_W65816_* relocation numbers. These are protocol constants shared
|
|
// with link816 / omfEmit / llvm-objdump; do not renumber. If new types
|
|
// are added, mirror them in src/link816/link816.cpp's relocWidth() and
|
|
// the cRELOC pipeline.
|
|
namespace R_W65816 {
|
|
enum : unsigned {
|
|
R_IMM8 = 1,
|
|
R_IMM16 = 2,
|
|
R_IMM24 = 3,
|
|
R_PCREL8 = 4,
|
|
R_PCREL16 = 5,
|
|
R_BANK16 = 6,
|
|
R_DATA32 = 7,
|
|
R_PCREL32 = 8,
|
|
};
|
|
} // namespace R_W65816
|
|
|
|
namespace {
|
|
|
|
class W65816ELFObjectWriter : public MCELFObjectTargetWriter {
|
|
public:
|
|
// EM_W65816 = 0xFF16 — vendor-private slot in the 0xFF00-0xFFFF range
|
|
// reserved by the ELF spec for non-IANA experimental targets. See
|
|
// docs/USAGE.md "ELF e_machine value" section and the EM_W65816 comment
|
|
// in llvm/include/llvm/BinaryFormat/ELF.h. Using a non-zero EM_ value
|
|
// is what lets llvm-dwarfdump and other generic ELF consumers stop
|
|
// warning on our output.
|
|
explicit W65816ELFObjectWriter(uint8_t OSABI)
|
|
: MCELFObjectTargetWriter(/*Is64Bit=*/false, OSABI, ELF::EM_W65816,
|
|
/*HasRelocationAddend=*/true) {}
|
|
|
|
~W65816ELFObjectWriter() override = default;
|
|
|
|
protected:
|
|
unsigned getRelocType(const MCFixup &Fixup, const MCValue &,
|
|
bool IsPCRel) const override {
|
|
// R_W65816_* relocation numbers. The (EM_W65816, R_W65816_*) pair is
|
|
// unique, so the small integer constants below can stay stable across
|
|
// releases. link816 / omfEmit / llvm-objdump all decode them.
|
|
//
|
|
// Generic FK_Data_* fixups are also accepted — the asm parser creates
|
|
// them for things like `.word foo` and the JMP/JML address operand
|
|
// when no target-specific fixup kind is hinted. Map them to the
|
|
// matching size-based reloc; PC-relative variants pick the *_pcrel
|
|
// forms. Without this, every hand-written .s reference to an extern
|
|
// symbol came through `getRelocType` as a default-value (UB) reloc
|
|
// type — observed as type 249 — and broke link816.py.
|
|
auto Kind = Fixup.getKind();
|
|
switch (Kind) {
|
|
case W65816::fixup_8: return R_W65816::R_IMM8;
|
|
case W65816::fixup_16: return R_W65816::R_IMM16;
|
|
case W65816::fixup_24: return R_W65816::R_IMM24;
|
|
case W65816::fixup_8_pcrel: return R_W65816::R_PCREL8;
|
|
case W65816::fixup_16_pcrel: return R_W65816::R_PCREL16;
|
|
case W65816::fixup_bank16: return R_W65816::R_BANK16;
|
|
case W65816::fixup_32: return R_W65816::R_DATA32;
|
|
case W65816::fixup_32_pcrel: return R_W65816::R_PCREL32;
|
|
case FK_Data_1: return IsPCRel ? R_W65816::R_PCREL8 : R_W65816::R_IMM8;
|
|
case FK_Data_2: return IsPCRel ? R_W65816::R_PCREL16 : R_W65816::R_IMM16;
|
|
// FK_Data_4 is emitted by DWARF (.debug_info / .debug_line /
|
|
// .debug_frame section-relative addresses), .eh_frame,
|
|
// .debug_loclists, and user `.long` directives. Dispatch by
|
|
// IsPCRel: in-section diffs that the assembler can't resolve
|
|
// locally come through as PC-relative (per
|
|
// ELFObjectWriter::recordRelocation:1329-1349), everything else
|
|
// is absolute. Previously this returned IMM24 (3 bytes),
|
|
// silently truncating the 4-byte slot — corrupting any DWARF
|
|
// address with a non-zero high byte AND off-by-one'ing the
|
|
// .debug_line decoder because the 4th byte of the slot landed
|
|
// on whatever followed it (most often the size byte of the
|
|
// next line-program header → unit_length = 0).
|
|
case FK_Data_4: return IsPCRel ? R_W65816::R_PCREL32 : R_W65816::R_DATA32;
|
|
default:
|
|
llvm_unreachable("W65816: unknown fixup kind");
|
|
}
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
std::unique_ptr<MCObjectTargetWriter>
|
|
llvm::createW65816ELFObjectWriter(uint8_t OSABI) {
|
|
return std::make_unique<W65816ELFObjectWriter>(OSABI);
|
|
}
|