The ELF Object Writer class is based on the class
MCELFObjectTargetWriter
and handles the
manipulations of fixups and conversion of fixups to relocs.
Note | |
---|---|
Information about the |
The constructor for this class simply sets up the parent class, passing it the OS ABI version and the value used to identify the ELF file as belonging to that architecture.
Known machines can be found in an enum in
include/llvm/Support/ELF.h
. Should the machine
architecture not be known, a new value should be used that does
not conflict with any other architecture.
For the OpenRISC 1000 architecture, this value is
ELF::EM_OPENRISC
and has the value 92. The
constructor is therefore as follows.
OR1KELFObjectWriter::OR1KELFObjectWriter(uint8_t OSABI) : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, ELF::EM_OPENRISC, /*HasRelocationAddend*/ true) {}
The GetRelocType
function takes a fixup type,
mapping it to a relocation type. As in many cases each fixup represents
a single representation, the basic structure of this function is a
switch statement and setting a variable (Type
) to
the relocation for the given fixup.
In addition to the custom fixups, there are also some built-in fixups
(for 32bit absolute relocation etc.) that also need mapping (these are
called FK_Data_4
, etc. and can be found in
include/llvm/MC/MCFixup.h
.
unsigned OR1KELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const { unsigned Type; unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { default: llvm_unreachable("Invalid fixup kind!"); case OR1K::fixup_OR1K_PCREL32: case FK_PCRel_4: Type = ELF::R_OR1K_32_PCREL; break; ... other fixups note shown .. return Type; }
The object writer is enabled in a similar fashion to the other MC
components, a function
create
is used to create and return a new object writer. This function can be
modified for example to provide support for different object writers
depending on word size and endianness. A simple example from OpenRISC 1000 is
shown below.
arch
ELFObjectWriter
MCObjectWriter *llvm::createOR1KELFObjectWriter(raw_ostream &OS, uint8_t OSABI) { MCELFObjectTargetWriter *MOTW = new OR1KELFObjectWriter(OSABI); return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/ false); }
This function is then used in the previously defined Assembly Backend to set up the object writer when the backend needs it.
MCObjectWriter *OR1KAsmBackend::createObjectWriter(raw_ostream &OS) const { return createOR1KELFObjectWriter(OS, MCELFObjectTargetWriter::getOSABI(OSType)); }
Should the architecture require support for multiple object file types, then the function would be modified so that a different object writer is created depending on the OS requested.
Finally support for streaming out object files is added in the
file, by registering a
arch
MCTargetDesc.cppcreate
function with the target registry.
arch
MCStreamer
In the below example from OpenRISC 1000 , this function checks for if the requested target format is MACH-O or COFF. Neither of these are supported by this implementation, so an error is raised if this is requested.
static MCStreamer *createOR1KMCStreamer(const Target &T, StringRef TT, MCContext &Ctx, MCAsmBackend &MAB, raw_ostream &_OS, MCCodeEmitter *_Emitter, bool RelaxAll, bool NoExecStack) { Triple TheTriple(TT); if (TheTriple.isOSDarwin()) { llvm_unreachable("OR1K does not support Darwin MACH-O format"); } if (TheTriple.isOSWindows()) { llvm_unreachable("OR1K does not support Windows COFF format"); } return createELFStreamer(Ctx, MAB, _OS, _Emitter, RelaxAll, NoExecStack); }
// Register the object streamer TargetRegistry::RegisterMCObjectStreamer(TheOR1KTarget, createOR1KMCStreamer);