[llvm] [RISCV] RFC: Add PE/COFF file output support (PR #148045)
Jason Xu via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 10 12:48:51 PDT 2025
https://github.com/JasonBrave created https://github.com/llvm/llvm-project/pull/148045
Adding support for PE file output for RISC-V target, mainly targeted for producing UEFI Applications.
>From 05325c2360e8e2bea9ee9c3dccdda499c57276e2 Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Tue, 8 Jul 2025 22:56:34 -0400
Subject: [PATCH 1/2] Add RISC-V PE32+ Relocation Types
---
llvm/include/llvm/BinaryFormat/COFF.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index f3b5d5e3f23c6..7b428d0e76c67 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -132,7 +132,8 @@ template <typename T> bool isAnyArm64(T Machine) {
}
template <typename T> bool is64Bit(T Machine) {
- return Machine == IMAGE_FILE_MACHINE_AMD64 || isAnyArm64(Machine);
+ return Machine == IMAGE_FILE_MACHINE_AMD64 || isAnyArm64(Machine) ||
+ IMAGE_FILE_MACHINE_RISCV64;
}
enum Characteristics : unsigned {
@@ -726,7 +727,10 @@ enum BaseRelocationType : unsigned {
IMAGE_REL_BASED_HIGHADJ = 4,
IMAGE_REL_BASED_MIPS_JMPADDR = 5,
IMAGE_REL_BASED_ARM_MOV32A = 5,
+ IMAGE_REL_BASED_RISCV_HI20 = 5,
IMAGE_REL_BASED_ARM_MOV32T = 7,
+ IMAGE_REL_BASED_RISCV_LOW12I = 7,
+ IMAGE_REL_BASED_RISCV_LOW12S = 8,
IMAGE_REL_BASED_MIPS_JMPADDR16 = 9,
IMAGE_REL_BASED_DIR64 = 10
};
>From 1bebbb292d43b87ffd9cc0e76d5cbda9a8cd17b3 Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Thu, 10 Jul 2025 15:41:49 -0400
Subject: [PATCH 2/2] Initial adding PE/COFF file output support to RISC-V
target
---
.../Target/RISCV/MCTargetDesc/CMakeLists.txt | 2 +
.../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 29 +++++++++++
.../RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp | 12 +++++
.../RISCV/MCTargetDesc/RISCVMCAsmInfo.h | 8 +++
.../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 18 ++++++-
.../RISCV/MCTargetDesc/RISCVMCTargetDesc.h | 12 +++++
.../MCTargetDesc/RISCVWinCOFFObjectWriter.cpp | 51 +++++++++++++++++++
.../MCTargetDesc/RISCVWinCOFFStreamer.cpp | 33 ++++++++++++
8 files changed, 164 insertions(+), 1 deletion(-)
create mode 100644 llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
create mode 100644 llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
index e68c956f888e4..19f8ab17bf32e 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
@@ -11,6 +11,8 @@ add_llvm_component_library(LLVMRISCVDesc
RISCVMatInt.cpp
RISCVTargetStreamer.cpp
RISCVELFStreamer.cpp
+ RISCVWinCOFFObjectWriter.cpp
+ RISCVWinCOFFStreamer.cpp
LINK_COMPONENTS
MC
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 89a87798d71e4..b10f3e2174f81 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -895,6 +895,30 @@ bool RISCVAsmBackend::shouldInsertFixupForCodeAlign(MCAssembler &Asm,
return true;
}
+namespace {
+
+class WindowsRISCVAsmBackend : public RISCVAsmBackend {
+ bool is64Bit;
+
+public:
+ WindowsRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
+ const MCTargetOptions &Options)
+ : RISCVAsmBackend(
+ STI,
+ MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()),
+ STI.getTargetTriple().isArch64Bit(), Options) {
+ is64Bit = STI.getTargetTriple().isArch64Bit();
+ }
+
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createRISCVWinCOFFObjectWriter(is64Bit);
+ }
+};
+
+} // namespace
+
std::unique_ptr<MCObjectTargetWriter>
RISCVAsmBackend::createObjectTargetWriter() const {
return createRISCVELFObjectWriter(OSABI, Is64Bit);
@@ -905,6 +929,11 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
const Triple &TT = STI.getTargetTriple();
+
+ if (TT.isOSWindows() && TT.isOSBinFormatCOFF()) {
+ return new WindowsRISCVAsmBackend(T, STI, MRI, Options);
+ }
+
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
index 090d331d99cab..8b6b13f239707 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
@@ -57,3 +57,15 @@ void RISCVMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
if (HasSpecifier)
OS << ')';
}
+
+
+void RISCVCOFFMCAsmInfo::anchor() {}
+
+RISCVCOFFMCAsmInfo::RISCVCOFFMCAsmInfo() {
+ HasSingleParameterDotFile = true;
+ WinEHEncodingType = WinEH::EncodingType::Itanium;
+
+ ExceptionsType = ExceptionHandling::WinEH;
+
+ AllowAtInName = true;
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
index 097e94b6117c7..1403f07bb7888 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -13,6 +13,7 @@
#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
+#include "llvm/MC/MCAsmInfoCOFF.h"
#include "llvm/MC/MCAsmInfoELF.h"
#include "llvm/MC/MCFixup.h"
@@ -31,6 +32,13 @@ class RISCVMCAsmInfo : public MCAsmInfoELF {
const MCSpecifierExpr &Expr) const override;
};
+class RISCVCOFFMCAsmInfo : public MCAsmInfoGNUCOFF {
+ void anchor() override;
+
+public:
+ explicit RISCVCOFFMCAsmInfo();
+};
+
namespace RISCV {
using Specifier = uint16_t;
// Specifiers mapping to relocation types below FirstTargetFixupKind are
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index f66c2d5f99cb3..75de3eeb096ba 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -44,6 +44,13 @@
using namespace llvm;
+namespace {
+class RISCVWinCOFFTargetStreamer : public RISCVTargetStreamer {
+public:
+ RISCVWinCOFFTargetStreamer(MCStreamer &S) : RISCVTargetStreamer(S) {}
+};
+} // end namespace
+
static MCInstrInfo *createRISCVMCInstrInfo() {
MCInstrInfo *X = new MCInstrInfo();
InitRISCVMCInstrInfo(X);
@@ -59,7 +66,13 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) {
static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT,
const MCTargetOptions &Options) {
- MCAsmInfo *MAI = new RISCVMCAsmInfo(TT);
+ MCAsmInfo *MAI;
+
+ if(TT.isOSWindows()){
+ MAI = new RISCVCOFFMCAsmInfo();
+ } else {
+ MAI = new RISCVMCAsmInfo(TT);
+ }
unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true);
MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(nullptr, SP, 0);
@@ -110,6 +123,8 @@ static MCInstPrinter *createRISCVMCInstPrinter(const Triple &T,
static MCTargetStreamer *
createRISCVObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
const Triple &TT = STI.getTargetTriple();
+ if(TT.isOSBinFormatCOFF())
+ return new RISCVWinCOFFTargetStreamer(S);
if (TT.isOSBinFormatELF())
return new RISCVTargetELFStreamer(S, STI);
return nullptr;
@@ -344,6 +359,7 @@ LLVMInitializeRISCVTargetMC() {
TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer);
+ TargetRegistry::RegisterCOFFStreamer(*T, createRISCVWinCOFFStreamer);
TargetRegistry::RegisterObjectTargetStreamer(
*T, createRISCVObjectTargetStreamer);
TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
index bdee7ed4f011e..2cfd1abdc12b3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
@@ -13,6 +13,8 @@
#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Support/DataTypes.h"
#include <memory>
@@ -23,7 +25,9 @@ class MCCodeEmitter;
class MCContext;
class MCInstrInfo;
class MCObjectTargetWriter;
+class MCObjectWriter;
class MCRegisterInfo;
+class MCStreamer;
class MCSubtargetInfo;
class Target;
@@ -34,8 +38,16 @@ MCAsmBackend *createRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options);
+MCStreamer *createRISCVWinCOFFStreamer(MCContext &C,
+ std::unique_ptr<MCAsmBackend> &&AB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE);
+
std::unique_ptr<MCObjectTargetWriter> createRISCVELFObjectWriter(uint8_t OSABI,
bool Is64Bit);
+
+std::unique_ptr<MCObjectTargetWriter> createRISCVWinCOFFObjectWriter(bool Is64Bit);
+
} // namespace llvm
// Defines symbolic names for RISC-V registers.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
new file mode 100644
index 0000000000000..207c81cd8c598
--- /dev/null
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
@@ -0,0 +1,51 @@
+//===- RISCVWinCOFFObjectWriter.cpp-----------------------------*- C++ -*-===//
+//
+// 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
+//
+//===---------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVFixupKinds.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class RISCVWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
+public:
+ RISCVWinCOFFObjectWriter(bool Is64Bit);
+
+ unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+ const MCFixup &Fixup, bool IsCrossSection,
+ const MCAsmBackend &MAB) const override;
+};
+
+} // namespace
+
+RISCVWinCOFFObjectWriter::RISCVWinCOFFObjectWriter(bool Is64Bit)
+ : MCWinCOFFObjectTargetWriter(Is64Bit ? COFF::IMAGE_FILE_MACHINE_RISCV64
+ : COFF::IMAGE_FILE_MACHINE_RISCV32) {}
+
+unsigned RISCVWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsCrossSection,
+ const MCAsmBackend &MAB) const {
+ unsigned FixupKind = Fixup.getKind();
+
+ switch (FixupKind) {
+ default:
+ Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");
+ return COFF::IMAGE_REL_BASED_RISCV_HI20; // FIXME
+ }
+}
+
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createRISCVWinCOFFObjectWriter(bool Is64Bit) {
+ return std::make_unique<RISCVWinCOFFObjectWriter>(Is64Bit);
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
new file mode 100644
index 0000000000000..7cc6dea804a83
--- /dev/null
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
@@ -0,0 +1,33 @@
+//===- RISCVWinCOFFStreamer.cpp----------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===---------------------------------------------------------------------===//
+
+#include "RISCVMCTargetDesc.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCWinCOFFStreamer.h"
+
+using namespace llvm;
+
+namespace {
+class RISCVWinCOFFStreamer : public MCWinCOFFStreamer {
+public:
+ RISCVWinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
+ std::unique_ptr<MCCodeEmitter> CE,
+ std::unique_ptr<MCObjectWriter> OW)
+ : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
+};
+} // namespace
+
+MCStreamer *llvm::createRISCVWinCOFFStreamer(
+ MCContext &C, std::unique_ptr<MCAsmBackend> &&AB,
+ std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE) {
+ return new RISCVWinCOFFStreamer(C, std::move(AB), std::move(CE),
+ std::move(OW));
+}
More information about the llvm-commits
mailing list