65816-llvm-mos/src/llvm/lib/Target/W65816/MCTargetDesc/W65816ELFObjectWriter.cpp
Scott Duensing 09f7405362 Updates
2026-06-03 16:08:42 -05:00

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);
}