//===-- 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 llvm::createW65816ELFObjectWriter(uint8_t OSABI) { return std::make_unique(OSABI); }