Skip to content

Generate an .sframe section with a skeleton header #151223

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 3 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
9 changes: 9 additions & 0 deletions llvm/include/llvm/MC/MCObjectFileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef LLVM_MC_MCOBJECTFILEINFO_H
#define LLVM_MC_MCOBJECTFILEINFO_H

#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/BinaryFormat/Swift.h"
#include "llvm/MC/MCSection.h"
#include "llvm/Support/Compiler.h"
Expand Down Expand Up @@ -50,6 +51,9 @@ class LLVM_ABI MCObjectFileInfo {
/// Compact unwind encoding indicating that we should emit only an EH frame.
unsigned CompactUnwindDwarfEHFrameOnly = 0;

/// SFrame ABI architecture byte
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
/// SFrame ABI architecture byte
/// SFrame ABI architecture byte.

std::optional<sframe::ABI> SFrameABIArch = {};

/// Section directive for standard text.
MCSection *TextSection = nullptr;

Expand Down Expand Up @@ -174,6 +178,9 @@ class LLVM_ABI MCObjectFileInfo {
/// It is initialized on demand so it can be overwritten (with uniquing).
MCSection *EHFrameSection = nullptr;

/// SFrame section.
MCSection *SFrameSection = nullptr;

/// Section containing metadata on function stack sizes.
MCSection *StackSizesSection = nullptr;

Expand Down Expand Up @@ -266,6 +273,7 @@ class LLVM_ABI MCObjectFileInfo {
return CompactUnwindDwarfEHFrameOnly;
}

std::optional<sframe::ABI> getSFrameABIArch() const { return SFrameABIArch; }
virtual unsigned getTextSectionAlignment() const { return 4; }
MCSection *getTextSection() const { return TextSection; }
MCSection *getDataSection() const { return DataSection; }
Expand Down Expand Up @@ -445,6 +453,7 @@ class LLVM_ABI MCObjectFileInfo {
MCSection *getTOCBaseSection() const { return TOCBaseSection; }

MCSection *getEHFrameSection() const { return EHFrameSection; }
MCSection *getSFrameSection() const { return SFrameSection; }

bool isPositionIndependent() const { return PositionIndependent; }

Expand Down
36 changes: 36 additions & 0 deletions llvm/include/llvm/MC/MCSFrame.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===- MCSFrame.h - Machine Code SFrame support -----------------*- C++ -*-===//
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I think the standard declaration no longer needs the C++ bit, but I could be wrong. See https://llvm.org/docs/CodingStandards.html#file-headers.

//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of MCSFrameEmitter to support emitting
// sframe unwinding info from .cfi_* directives. It relies on FDEs and CIEs
// created for Dwarf frame info, but emits that info in a different format.
//
// See https://sourceware.org/binutils/docs-2.41/sframe-spec.html
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCSFRAME_H
#define LLVM_MC_MCSFRAME_H

#include <cstdint>

#include "llvm/ADT/SmallVector.h"
Comment on lines +19 to +21
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
#include <cstdint>
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallVector.h"
#include <cstdint>


namespace llvm {

class MCObjectStreamer;

class MCSFrameEmitter {
public:
//
// Emits the sframe section.
//
Comment on lines +29 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment feels excessive in size. Should it also be a doxygen comment?

Suggested change
//
// Emits the sframe section.
//
/// Emits the sframe section.

static void Emit(MCObjectStreamer &streamer);
};

} // end namespace llvm
#endif // LLVM_MC_MCSFRAME_H
1 change: 1 addition & 0 deletions llvm/lib/MC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ add_llvm_component_library(LLVMMC
MCSection.cpp
MCSectionMachO.cpp
MCStreamer.cpp
MCSFrame.cpp
MCSPIRVStreamer.cpp
MCSubtargetInfo.cpp
MCSymbol.cpp
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/MC/MCObjectFileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
Expand Down Expand Up @@ -380,6 +381,19 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
unsigned EHSectionType = T.getArch() == Triple::x86_64
? ELF::SHT_X86_64_UNWIND
: ELF::SHT_PROGBITS;
switch (T.getArch()) {
case Triple::x86_64:
SFrameABIArch = sframe::ABI::AMD64EndianLittle;
break;
case Triple::aarch64:
SFrameABIArch = sframe::ABI::AArch64EndianLittle;
break;
case Triple::aarch64_be:
SFrameABIArch = sframe::ABI::AArch64EndianBig;
break;
default:
break;
}

// Solaris requires different flags for .eh_frame to seemingly every other
// platform.
Expand Down Expand Up @@ -537,6 +551,9 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
EHFrameSection =
Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags);

SFrameSection =
Ctx->getELFSection(".sframe", ELF::SHT_GNU_SFRAME, ELF::SHF_ALLOC);

StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0);

PseudoProbeSection = Ctx->getELFSection(".pseudo_probe", DebugSecType, 0);
Expand Down Expand Up @@ -1062,6 +1079,7 @@ void MCObjectFileInfo::initMCObjectFileInfo(MCContext &MCCtx, bool PIC,
CompactUnwindDwarfEHFrameOnly = 0;

EHFrameSection = nullptr; // Created on demand.
SFrameSection = nullptr; // Created on demand.
CompactUnwindSection = nullptr; // Used only by selected targets.
DwarfAccelNamesSection = nullptr; // Used only by selected targets.
DwarfAccelObjCSection = nullptr; // Used only by selected targets.
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/MC/MCObjectStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSFrame.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
Expand All @@ -30,7 +31,7 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context,
: MCStreamer(Context),
Assembler(std::make_unique<MCAssembler>(
Context, std::move(TAB), std::move(Emitter), std::move(OW))),
EmitEHFrame(true), EmitDebugFrame(false) {
EmitEHFrame(true), EmitDebugFrame(false), EmitSFrame(false) {
assert(Assembler->getBackendPtr() && Assembler->getEmitterPtr());
IsObj = true;
setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
Expand Down Expand Up @@ -185,6 +186,10 @@ void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {

if (EmitDebugFrame)
MCDwarfFrameEmitter::Emit(*this, MAB, false);

if (EmitSFrame || (getContext().getTargetOptions() &&
getContext().getTargetOptions()->EmitSFrameUnwind))
MCSFrameEmitter::Emit(*this);
}

void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) {
Expand Down
98 changes: 98 additions & 0 deletions llvm/lib/MC/MCSFrame.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===- 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

If it's not necessary, shouldn't we just report a bug against gas and not do it here?

Section->ensureMinAlignment(Align(8));
Streamer.switchSection(Section);
MCSymbol *SectionStart = Context.createTempSymbol();
Streamer.emitLabel(SectionStart);
Emitter.EmitHeader();
Emitter.EmitFDEs();
Emitter.EmitFREs();
}
26 changes: 26 additions & 0 deletions llvm/test/MC/ELF/cfi-sframe.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// TODO: Add other architectures as they gain sframe support
// REQUIRES: x86-registered-target
// RUN: llvm-mc --assemble --filetype=obj --gsframe -triple x86_64 %s -o %t.o
// RUN: llvm-readelf --sframe %t.o | FileCheck %s

.cfi_sections .sframe

f1:
.cfi_startproc
nop
.cfi_endproc
Comment on lines +9 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: excessive indentation?


// CHECK: SFrame section '.sframe' {
// CHECK-NEXT: Header {
// CHECK-NEXT: Magic: 0xDEE2
// CHECK-NEXT: Version: V2 (0x2)
// CHECK-NEXT: Flags [ (0x0)
// CHECK: ABI: AMD64EndianLittle (0x3)
// CHECK-NEXT: CFA fixed FP offset (unused): 0
// CHECK-NEXT: CFA fixed RA offset: 0
// CHECK-NEXT: Auxiliary header length: 0
// CHECK-NEXT: Num FDEs: 0
// CHECK-NEXT: Num FREs: 0
// CHECK-NEXT: FRE subsection length: 0
// CHECK-NEXT: FDE subsection offset: 0
// CHECK-NEXT: FRE subsection offset: 0