llvm-project/llvm/lib/MC/MCSFrame.cpp
Sterling-Augustine 2e9944a03e
Generate an .sframe section with a skeleton header (#151223)
This continues the sframe implementation discussed previously.

Of note, this also adds some target dependent functions to the object
file. Additional fields will be needed later. It would be possible to do
all of this inside the sframe implementation itself if it feels a little
messy and specialized, but generally I think that target info goes with
target info.

Another question is if we want a sentinel value for unimplemented sframe
abi arches, or a std::optional. Both work.
2025-08-12 12:57:31 -07:00

99 lines
3.1 KiB
C++

//===- lib/MC/MCSFrame.cpp - MCSFrame implementation ----------------------===//
//
// 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 "llvm/MC/MCSFrame.h"
#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/EndianStream.h"
using namespace llvm;
using namespace sframe;
namespace {
// Emitting these field-by-field, instead of constructing the actual structures
// lets Streamer do target endian-fixups for free.
class SFrameEmitterImpl {
MCObjectStreamer &Streamer;
ABI SFrameABI;
MCSymbol *FDESubSectionStart;
MCSymbol *FRESubSectionStart;
MCSymbol *FRESubSectionEnd;
public:
SFrameEmitterImpl(MCObjectStreamer &Streamer) : Streamer(Streamer) {
assert(Streamer.getContext()
.getObjectFileInfo()
->getSFrameABIArch()
.has_value());
SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();
FDESubSectionStart = Streamer.getContext().createTempSymbol();
FRESubSectionStart = Streamer.getContext().createTempSymbol();
FRESubSectionEnd = Streamer.getContext().createTempSymbol();
}
void emitPreamble() {
Streamer.emitInt16(Magic);
Streamer.emitInt8(static_cast<uint8_t>(Version::V2));
Streamer.emitInt8(0);
}
void emitHeader() {
emitPreamble();
// sfh_abi_arch
Streamer.emitInt8(static_cast<uint8_t>(SFrameABI));
// sfh_cfa_fixed_fp_offset
Streamer.emitInt8(0);
// sfh_cfa_fixed_ra_offset
Streamer.emitInt8(0);
// sfh_auxhdr_len
Streamer.emitInt8(0);
// shf_num_fdes
Streamer.emitInt32(0);
// shf_num_fres
Streamer.emitInt32(0);
// shf_fre_len
Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,
sizeof(int32_t));
// shf_fdeoff. With no sfh_auxhdr, these immediately follow this header.
Streamer.emitInt32(0);
// shf_freoff
Streamer.emitAbsoluteSymbolDiff(FRESubSectionStart, FDESubSectionStart,
sizeof(uint32_t));
}
void emitFDEs() { Streamer.emitLabel(FDESubSectionStart); }
void emitFREs() {
Streamer.emitLabel(FRESubSectionStart);
Streamer.emitLabel(FRESubSectionEnd);
}
};
} // end anonymous namespace
void MCSFrameEmitter::emit(MCObjectStreamer &Streamer) {
MCContext &Context = Streamer.getContext();
SFrameEmitterImpl Emitter(Streamer);
MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
// Not strictly necessary, but gas always aligns to 8, so match that.
Section->ensureMinAlignment(Align(8));
Streamer.switchSection(Section);
MCSymbol *SectionStart = Context.createTempSymbol();
Streamer.emitLabel(SectionStart);
Emitter.emitHeader();
Emitter.emitFDEs();
Emitter.emitFREs();
}