Skip to content

[RISCV] RFC: Add PE/COFF file output support #148045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/docs/CodeGenerator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ The table below captures a snapshot of object file support in LLVM:
================== ========================================================
Format Supported Targets
================== ========================================================
``COFF`` AArch64, ARM, X86
``COFF`` AArch64, ARM, RISCV, X86
``DXContainer`` DirectX
``ELF`` AArch64, AMDGPU, ARM, AVR, BPF, CSKY, Hexagon, Lanai, LoongArch, M86k, MSP430, MIPS, PowerPC, RISCV, SPARC, SystemZ, VE, X86
``GOFF`` SystemZ
Expand Down
6 changes: 5 additions & 1 deletion llvm/include/llvm/BinaryFormat/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
IMAGE_REL_BASED_RISCV_HI20 = 5,
IMAGE_REL_BASED_RISCV_HIGH20 = 5,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like IMAGE_REL_BASED_RISCV_HI20 already appears in other code according to google.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well they're wrong... https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-types is the canonical location for the specification and is as I wrote

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
};
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
Expand Down Expand Up @@ -125,6 +126,9 @@ static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
return CPUType::ARM64;
case Triple::ArchType::mipsel:
return CPUType::MIPS;
case llvm::Triple::ArchType::riscv32:
case llvm::Triple::ArchType::riscv64:
return CPUType::Unknown;
case Triple::ArchType::UnknownArch:
return CPUType::Unknown;
default:
Expand Down
11 changes: 9 additions & 2 deletions llvm/lib/Object/COFFObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,11 +1115,14 @@ dynamic_reloc_iterator COFFObjectFile::dynamic_reloc_end() const {
}

uint8_t COFFObjectFile::getBytesInAddress() const {
return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this just is64Bit?

getArch() == Triple::riscv64
? 8
: 4;
}

StringRef COFFObjectFile::getFileFormatName() const {
switch(getMachine()) {
switch (getMachine()) {
case COFF::IMAGE_FILE_MACHINE_I386:
return "COFF-i386";
case COFF::IMAGE_FILE_MACHINE_AMD64:
Expand All @@ -1134,6 +1137,10 @@ StringRef COFFObjectFile::getFileFormatName() const {
return "COFF-ARM64X";
case COFF::IMAGE_FILE_MACHINE_R4000:
return "COFF-MIPS";
case COFF::IMAGE_FILE_MACHINE_RISCV32:
return "COFF-RISCV32";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some standard these need to conform to (if so, where is this documented?) or are they whatever we want them to be?

case COFF::IMAGE_FILE_MACHINE_RISCV64:
return "COFF-RISCV64";
default:
return "COFF-<unknown arch>";
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ add_llvm_component_library(LLVMRISCVDesc
RISCVMatInt.cpp
RISCVTargetStreamer.cpp
RISCVELFStreamer.cpp
RISCVWinCOFFObjectWriter.cpp
RISCVWinCOFFStreamer.cpp

LINK_COMPONENTS
MC
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,30 @@ bool RISCVAsmBackend::shouldInsertFixupForCodeAlign(MCAssembler &Asm,
return true;
}

namespace {

class WindowsRISCVAsmBackend : public RISCVAsmBackend {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COFF rather than Windows?... AFAIK there is no Windows for RISC-V in existence anywhere, but PE/COFF is broader than Windows and does exist.

bool is64Bit;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RISCVAsmBackend already has an Is64Bit member you can just read in createObjectTargetWriter


public:
WindowsRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options)
: RISCVAsmBackend(
STI,
MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems dubious

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);
Expand All @@ -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()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no Windows RISC-V systems. Why is this not just isOSBinFormatCOFF like AArch64?

return new WindowsRISCVAsmBackend(T, STI, MRI, Options);
}

uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
}
12 changes: 12 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -31,6 +32,13 @@ class RISCVMCAsmInfo : public MCAsmInfoELF {
const MCSpecifierExpr &Expr) const override;
};

class RISCVCOFFMCAsmInfo : public MCAsmInfoGNUCOFF {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AArch64 calls this AArch64MCAsmInfoGNUCOFF

void anchor() override;

public:
explicit RISCVCOFFMCAsmInfo();
};

namespace RISCV {
using Specifier = uint16_t;
// Specifiers mapping to relocation types below FirstTargetFixupKind are
Expand Down
18 changes: 17 additions & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Comment on lines +71 to +72
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confused between Windows and PE/COFF again, not to mention the obvious formatting problems

} else {
MAI = new RISCVMCAsmInfo(TT);
}

unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true);
MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(nullptr, SP, 0);
Expand Down Expand Up @@ -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);
Comment on lines +126 to +127
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

if (TT.isOSBinFormatELF())
return new RISCVTargetELFStreamer(S, STI);
return nullptr;
Expand Down Expand Up @@ -344,6 +359,7 @@ LLVMInitializeRISCVTargetMC() {
TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer);
TargetRegistry::RegisterCOFFStreamer(*T, createRISCVWinCOFFStreamer);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting?

TargetRegistry::RegisterObjectTargetStreamer(
*T, createRISCVObjectTargetStreamer);
TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis);
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -23,7 +25,9 @@ class MCCodeEmitter;
class MCContext;
class MCInstrInfo;
class MCObjectTargetWriter;
class MCObjectWriter;
class MCRegisterInfo;
class MCStreamer;
class MCSubtargetInfo;
class Target;

Expand All @@ -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.
Expand Down
51 changes: 51 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
33 changes: 33 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
4 changes: 2 additions & 2 deletions llvm/lib/TargetParser/Triple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::aarch64:
case Triple::aarch64_32:
case Triple::arm:
case Triple::riscv32:
case Triple::riscv64:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds both Darwin and Win32 support, but AFAIK UEFI is the only extra case that should be handled?

case Triple::thumb:
case Triple::x86:
case Triple::x86_64:
Expand Down Expand Up @@ -966,8 +968,6 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::r600:
case Triple::renderscript32:
case Triple::renderscript64:
case Triple::riscv32:
case Triple::riscv64:
case Triple::shave:
case Triple::sparc:
case Triple::sparcel:
Expand Down
Loading