668 lines · cpp
1//===- lib/MC/MCSFrame.cpp - MCSFrame implementation ----------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/MC/MCSFrame.h"10#include "llvm/BinaryFormat/SFrame.h"11#include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"12#include "llvm/DebugInfo/DWARF/LowLevel/DWARFDataExtractorSimple.h"13#include "llvm/MC/MCAsmInfo.h"14#include "llvm/MC/MCContext.h"15#include "llvm/MC/MCObjectFileInfo.h"16#include "llvm/MC/MCObjectStreamer.h"17#include "llvm/MC/MCSection.h"18#include "llvm/MC/MCSymbol.h"19#include "llvm/Support/Endian.h"20#include "llvm/Support/EndianStream.h"21 22using namespace llvm;23using namespace sframe;24 25namespace {26 27// High-level structure to track info needed to emit a28// sframe_frame_row_entry_addrX. On disk these have both a fixed portion of type29// sframe_frame_row_entry_addrX and trailing data of X * S bytes, where X is the30// datum size, and S is 1, 2, or 3 depending on which of CFA, SP, and FP are31// being tracked.32struct SFrameFRE {33 // An FRE describes how to find the registers when the PC is at this34 // Label from function start.35 const MCSymbol *Label = nullptr;36 size_t CFAOffset = 0;37 size_t FPOffset = 0;38 size_t RAOffset = 0;39 FREInfo<endianness::native> Info;40 bool CFARegSet = false;41 42 SFrameFRE(const MCSymbol *Start) : Label(Start) { Info.Info = 0; }43 44 void emitOffset(MCObjectStreamer &S, FREOffset OffsetSize, size_t Offset) {45 switch (OffsetSize) {46 case (FREOffset::B1):47 S.emitInt8(Offset);48 return;49 case (FREOffset::B2):50 S.emitInt16(Offset);51 return;52 case (FREOffset::B4):53 S.emitInt32(Offset);54 return;55 }56 }57 58 void emit(MCObjectStreamer &S, const MCSymbol *FuncBegin,59 MCFragment *FDEFrag) {60 S.emitSFrameCalculateFuncOffset(FuncBegin, Label, FDEFrag, SMLoc());61 62 // fre_cfa_base_reg_id already set during parsing63 64 // fre_offset_count65 unsigned RegsTracked = 1; // always track the cfa.66 if (FPOffset != 0)67 ++RegsTracked;68 if (RAOffset != 0)69 ++RegsTracked;70 Info.setOffsetCount(RegsTracked);71 72 // fre_offset_size73 if (isInt<8>(CFAOffset) && isInt<8>(FPOffset) && isInt<8>(RAOffset))74 Info.setOffsetSize(FREOffset::B1);75 else if (isInt<16>(CFAOffset) && isInt<16>(FPOffset) && isInt<16>(RAOffset))76 Info.setOffsetSize(FREOffset::B2);77 else {78 assert(isInt<32>(CFAOffset) && isInt<32>(FPOffset) &&79 isInt<32>(RAOffset) && "Offset too big for sframe");80 Info.setOffsetSize(FREOffset::B4);81 }82 83 // No support for fre_mangled_ra_p yet.84 Info.setReturnAddressSigned(false);85 86 // sframe_fre_info_word87 S.emitInt8(Info.getFREInfo());88 89 // FRE Offsets90 [[maybe_unused]] unsigned OffsetsEmitted = 1;91 emitOffset(S, Info.getOffsetSize(), CFAOffset);92 if (FPOffset) {93 ++OffsetsEmitted;94 emitOffset(S, Info.getOffsetSize(), FPOffset);95 }96 if (RAOffset) {97 ++OffsetsEmitted;98 emitOffset(S, Info.getOffsetSize(), RAOffset);99 }100 assert(OffsetsEmitted == RegsTracked &&101 "Didn't emit the right number of offsets");102 }103};104 105// High-level structure to track info needed to emit a sframe_func_desc_entry106// and its associated FREs.107struct SFrameFDE {108 // Reference to the original dwarf frame to avoid copying.109 const MCDwarfFrameInfo &DFrame;110 // Label where this FDE's FREs start.111 MCSymbol *FREStart;112 // Frag where this FDE is emitted.113 MCFragment *Frag;114 // Unwinding fres115 SmallVector<SFrameFRE> FREs;116 // .cfi_remember_state stack117 SmallVector<SFrameFRE> SaveState;118 119 SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES)120 : DFrame(DF), FREStart(FRES), Frag(nullptr) {}121 122 void emit(MCObjectStreamer &S, const MCSymbol *FRESubSectionStart) {123 MCContext &C = S.getContext();124 125 // sfde_func_start_address126 const MCExpr *V = C.getAsmInfo()->getExprForFDESymbol(127 &(*DFrame.Begin), C.getObjectFileInfo()->getFDEEncoding(), S);128 S.emitValue(V, sizeof(int32_t));129 130 // sfde_func_size131 S.emitAbsoluteSymbolDiff(DFrame.End, DFrame.Begin, sizeof(uint32_t));132 133 // sfde_func_start_fre_off134 auto *F = S.getCurrentFragment();135 const MCExpr *Diff = MCBinaryExpr::createSub(136 MCSymbolRefExpr::create(FREStart, C),137 MCSymbolRefExpr::create(FRESubSectionStart, C), C);138 139 F->addFixup(MCFixup::create(F->getContents().size(), Diff,140 MCFixup::getDataKindForSize(4)));141 S.emitInt32(0);142 143 // sfde_func_num_fres144 S.emitInt32(FREs.size());145 146 // sfde_func_info word147 148 // All FREs within an FDE share the same sframe::FREType::AddrX. The value149 // of 'X' is determined by the FRE with the largest offset, which is the150 // last. This offset isn't known until relax time, so emit a frag which can151 // calculate that now.152 //153 // At relax time, this FDE frag calculates the proper AddrX value (as well154 // as the rest of the FDE FuncInfo word). Subsequent FRE frags will read it155 // from this frag and emit the proper number of bytes.156 Frag = S.getCurrentFragment();157 S.emitSFrameCalculateFuncOffset(DFrame.Begin, FREs.back().Label, nullptr,158 SMLoc());159 160 // sfde_func_rep_size. Not relevant in non-PCMASK fdes.161 S.emitInt8(0);162 163 // sfde_func_padding2164 S.emitInt16(0);165 }166};167 168// Emitting these field-by-field, instead of constructing the actual structures169// lets Streamer do target endian-fixups for free.170 171class SFrameEmitterImpl {172 MCObjectStreamer &Streamer;173 SmallVector<SFrameFDE> FDEs;174 uint32_t TotalFREs;175 ABI SFrameABI;176 // Target-specific convenience variables to detect when a CFI instruction177 // references these registers. Unlike in dwarf frame descriptions, they never178 // escape into the sframe section itself. TODO: These should be retrieved from179 // the target.180 unsigned SPReg;181 unsigned FPReg;182 unsigned RAReg;183 int8_t FixedRAOffset;184 MCSymbol *FDESubSectionStart;185 MCSymbol *FRESubSectionStart;186 MCSymbol *FRESubSectionEnd;187 188 bool setCFARegister(SFrameFRE &FRE, const MCCFIInstruction &I) {189 if (I.getRegister() == SPReg) {190 FRE.CFARegSet = true;191 FRE.Info.setBaseRegister(BaseReg::SP);192 return true;193 }194 if (I.getRegister() == FPReg) {195 FRE.CFARegSet = true;196 FRE.Info.setBaseRegister(BaseReg::FP);197 return true;198 }199 Streamer.getContext().reportWarning(200 I.getLoc(), "canonical Frame Address not in stack- or frame-pointer. "201 "Omitting SFrame unwind info for this function");202 return false;203 }204 205 bool setCFAOffset(SFrameFRE &FRE, SMLoc Loc, size_t Offset) {206 if (!FRE.CFARegSet) {207 Streamer.getContext().reportWarning(208 Loc, "adjusting CFA offset without a base register. "209 "Omitting SFrame unwind info for this function");210 return false;211 }212 FRE.CFAOffset = Offset;213 return true;214 }215 216 // Technically, the escape data could be anything, but it is commonly a dwarf217 // CFI program. Even then, it could contain an arbitrarily complicated Dwarf218 // expression. Following gnu-gas, look for certain common cases that could219 // invalidate an FDE, emit a warning for those sequences, and don't generate220 // an FDE in those cases. Allow any that are known safe. It is likely that221 // more thorough test cases could refine this code, but it handles the most222 // important ones compatibly with gas.223 // Returns true if the CFI escape sequence is safe for sframes.224 bool isCFIEscapeSafe(SFrameFDE &FDE, const SFrameFRE &FRE,225 const MCCFIInstruction &CFI) {226 const MCAsmInfo *AI = Streamer.getContext().getAsmInfo();227 DWARFDataExtractorSimple data(CFI.getValues(), AI->isLittleEndian(),228 AI->getCodePointerSize());229 230 // Normally, both alignment factors are extracted from the enclosing Dwarf231 // FDE or CIE. We don't have one here. Alignments are used for scaling232 // factors for ops like CFA_def_cfa_offset_sf. But this particular function233 // is only interested in registers.234 dwarf::CFIProgram P(/*CodeAlignmentFactor=*/1,235 /*DataAlignmentFactor=*/1,236 Streamer.getContext().getTargetTriple().getArch());237 uint64_t Offset = 0;238 if (P.parse(data, &Offset, CFI.getValues().size())) {239 // Not a parsable dwarf expression. Assume the worst.240 Streamer.getContext().reportWarning(241 CFI.getLoc(),242 "skipping SFrame FDE; .cfi_escape with unknown effects");243 return false;244 }245 246 // This loop deals with dwarf::CFIProgram::Instructions. Everywhere else247 // this file deals with MCCFIInstructions.248 for (const dwarf::CFIProgram::Instruction &I : P) {249 switch (I.Opcode) {250 case dwarf::DW_CFA_nop:251 break;252 case dwarf::DW_CFA_val_offset: {253 // First argument is a register. Anything that touches CFA, FP, or RA is254 // a problem, but allow others through. As an even more special case,255 // allow SP + 0.256 auto Reg = I.getOperandAsUnsigned(P, 0);257 // The parser should have failed in this case.258 assert(Reg && "DW_CFA_val_offset with no register.");259 bool SPOk = true;260 if (*Reg == SPReg) {261 auto Opnd = I.getOperandAsSigned(P, 1);262 if (!Opnd || *Opnd != 0)263 SPOk = false;264 }265 if (!SPOk || *Reg == RAReg || *Reg == FPReg) {266 StringRef RN = *Reg == SPReg267 ? "SP reg "268 : (*Reg == FPReg ? "FP reg " : "RA reg ");269 Streamer.getContext().reportWarning(270 CFI.getLoc(),271 Twine(272 "skipping SFrame FDE; .cfi_escape DW_CFA_val_offset with ") +273 RN + Twine(*Reg));274 return false;275 }276 } break;277 case dwarf::DW_CFA_expression: {278 // First argument is a register. Anything that touches CFA, FP, or RA is279 // a problem, but allow others through.280 auto Reg = I.getOperandAsUnsigned(P, 0);281 if (!Reg) {282 Streamer.getContext().reportWarning(283 CFI.getLoc(),284 "skipping SFrame FDE; .cfi_escape with unknown effects");285 return false;286 }287 if (*Reg == SPReg || *Reg == RAReg || *Reg == FPReg) {288 StringRef RN = *Reg == SPReg289 ? "SP reg "290 : (*Reg == FPReg ? "FP reg " : "RA reg ");291 Streamer.getContext().reportWarning(292 CFI.getLoc(),293 Twine(294 "skipping SFrame FDE; .cfi_escape DW_CFA_expression with ") +295 RN + Twine(*Reg));296 return false;297 }298 } break;299 case dwarf::DW_CFA_GNU_args_size: {300 auto Size = I.getOperandAsSigned(P, 0);301 // Zero size doesn't affect the cfa.302 if (Size && *Size == 0)303 break;304 if (FRE.Info.getBaseRegister() != BaseReg::FP) {305 Streamer.getContext().reportWarning(306 CFI.getLoc(),307 Twine("skipping SFrame FDE; .cfi_escape DW_CFA_GNU_args_size "308 "with non frame-pointer CFA"));309 return false;310 }311 } break;312 // Cases that gas doesn't specially handle. TODO: Some of these could be313 // analyzed and handled instead of just punting. But these are uncommon,314 // or should be written as normal cfi directives. Some will need fixes to315 // the scaling factor.316 case dwarf::DW_CFA_advance_loc:317 case dwarf::DW_CFA_offset:318 case dwarf::DW_CFA_restore:319 case dwarf::DW_CFA_set_loc:320 case dwarf::DW_CFA_advance_loc1:321 case dwarf::DW_CFA_advance_loc2:322 case dwarf::DW_CFA_advance_loc4:323 case dwarf::DW_CFA_offset_extended:324 case dwarf::DW_CFA_restore_extended:325 case dwarf::DW_CFA_undefined:326 case dwarf::DW_CFA_same_value:327 case dwarf::DW_CFA_register:328 case dwarf::DW_CFA_remember_state:329 case dwarf::DW_CFA_restore_state:330 case dwarf::DW_CFA_def_cfa:331 case dwarf::DW_CFA_def_cfa_register:332 case dwarf::DW_CFA_def_cfa_offset:333 case dwarf::DW_CFA_def_cfa_expression:334 case dwarf::DW_CFA_offset_extended_sf:335 case dwarf::DW_CFA_def_cfa_sf:336 case dwarf::DW_CFA_def_cfa_offset_sf:337 case dwarf::DW_CFA_val_offset_sf:338 case dwarf::DW_CFA_val_expression:339 case dwarf::DW_CFA_MIPS_advance_loc8:340 case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc:341 case dwarf::DW_CFA_AARCH64_negate_ra_state:342 case dwarf::DW_CFA_LLVM_def_aspace_cfa:343 case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf:344 Streamer.getContext().reportWarning(345 CFI.getLoc(), "skipping SFrame FDE; .cfi_escape "346 "CFA expression with unknown side effects");347 return false;348 default:349 // Dwarf expression was only partially valid, and user could have350 // written anything.351 Streamer.getContext().reportWarning(352 CFI.getLoc(),353 "skipping SFrame FDE; .cfi_escape with unknown effects");354 return false;355 }356 }357 return true;358 }359 360 // Add the effects of CFI to the current FDE, creating a new FRE when361 // necessary. Return true if the CFI is representable in the sframe format.362 bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE, const MCCFIInstruction &CFI) {363 switch (CFI.getOperation()) {364 case MCCFIInstruction::OpDefCfaRegister:365 return setCFARegister(FRE, CFI);366 case MCCFIInstruction::OpDefCfa:367 case MCCFIInstruction::OpLLVMDefAspaceCfa:368 if (!setCFARegister(FRE, CFI))369 return false;370 return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset());371 case MCCFIInstruction::OpOffset:372 if (CFI.getRegister() == FPReg)373 FRE.FPOffset = CFI.getOffset();374 else if (CFI.getRegister() == RAReg)375 FRE.RAOffset = CFI.getOffset();376 return true;377 case MCCFIInstruction::OpRelOffset:378 if (CFI.getRegister() == FPReg)379 FRE.FPOffset += CFI.getOffset();380 else if (CFI.getRegister() == RAReg)381 FRE.RAOffset += CFI.getOffset();382 return true;383 case MCCFIInstruction::OpDefCfaOffset:384 return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset());385 case MCCFIInstruction::OpAdjustCfaOffset:386 return setCFAOffset(FRE, CFI.getLoc(), FRE.CFAOffset + CFI.getOffset());387 case MCCFIInstruction::OpRememberState:388 if (FDE.FREs.size() == 1) {389 // Error for gas compatibility: If the initial FRE isn't complete,390 // then any state is incomplete. FIXME: Dwarf doesn't error here.391 // Why should sframe?392 Streamer.getContext().reportWarning(393 CFI.getLoc(), "skipping SFrame FDE; .cfi_remember_state without "394 "prior SFrame FRE state");395 return false;396 }397 FDE.SaveState.push_back(FRE);398 return true;399 case MCCFIInstruction::OpRestore:400 // The first FRE generated has the original state.401 if (CFI.getRegister() == FPReg)402 FRE.FPOffset = FDE.FREs.front().FPOffset;403 else if (CFI.getRegister() == RAReg)404 FRE.RAOffset = FDE.FREs.front().RAOffset;405 return true;406 case MCCFIInstruction::OpRestoreState:407 // The cfi parser will have caught unbalanced directives earlier, so a408 // mismatch here is an implementation error.409 assert(!FDE.SaveState.empty() &&410 "cfi_restore_state without cfi_save_state");411 FRE = FDE.SaveState.pop_back_val();412 return true;413 case MCCFIInstruction::OpEscape:414 // This is a string of bytes that contains an arbitrary dwarf-expression415 // that may or may not affect unwind info.416 return isCFIEscapeSafe(FDE, FRE, CFI);417 default:418 // Instructions that don't affect the CFA, RA, and FP can be safely419 // ignored.420 return true;421 }422 }423 424public:425 SFrameEmitterImpl(MCObjectStreamer &Streamer)426 : Streamer(Streamer), TotalFREs(0) {427 assert(Streamer.getContext()428 .getObjectFileInfo()429 ->getSFrameABIArch()430 .has_value());431 FDEs.reserve(Streamer.getDwarfFrameInfos().size());432 SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();433 switch (SFrameABI) {434 case ABI::AArch64EndianBig:435 case ABI::AArch64EndianLittle:436 SPReg = 31;437 RAReg = 29;438 FPReg = 30;439 FixedRAOffset = 0;440 break;441 case ABI::AMD64EndianLittle:442 SPReg = 7;443 // RARegister untracked in this abi. Value chosen to match444 // MCDwarfFrameInfo constructor.445 RAReg = static_cast<unsigned>(INT_MAX);446 FPReg = 6;447 FixedRAOffset = -8;448 break;449 }450 451 FDESubSectionStart = Streamer.getContext().createTempSymbol();452 FRESubSectionStart = Streamer.getContext().createTempSymbol();453 FRESubSectionEnd = Streamer.getContext().createTempSymbol();454 }455 456 bool atSameLocation(const MCSymbol *Left, const MCSymbol *Right) {457 return Left != nullptr && Right != nullptr &&458 Left->getFragment() == Right->getFragment() &&459 Left->getOffset() == Right->getOffset();460 }461 462 bool equalIgnoringLocation(const SFrameFRE &Left, const SFrameFRE &Right) {463 return Left.CFAOffset == Right.CFAOffset &&464 Left.FPOffset == Right.FPOffset && Left.RAOffset == Right.RAOffset &&465 Left.Info.getFREInfo() == Right.Info.getFREInfo() &&466 Left.CFARegSet == Right.CFARegSet;467 }468 469 void buildSFDE(const MCDwarfFrameInfo &DF) {470 // Functions with zero size can happen with assembler macros and471 // machine-generated code. They don't need unwind info at all, so472 // no need to warn.473 if (atSameLocation(DF.Begin, DF.End))474 return;475 bool Valid = true;476 SFrameFDE FDE(DF, Streamer.getContext().createTempSymbol());477 // This would have been set via ".cfi_return_column", but478 // MCObjectStreamer doesn't emit an MCCFIInstruction for that. It just479 // sets the DF.RAReg.480 // FIXME: This also prevents providing a proper location for the error.481 // LLVM doesn't change the return column itself, so this was482 // hand-written assembly.483 if (DF.RAReg != RAReg) {484 Streamer.getContext().reportWarning(485 SMLoc(), "non-default RA register in .cfi_return_column " +486 Twine(DF.RAReg) +487 ". Omitting SFrame unwind info for this function");488 Valid = false;489 }490 MCSymbol *LastLabel = DF.Begin;491 SFrameFRE BaseFRE(LastLabel);492 if (!DF.IsSimple) {493 for (const auto &CFI :494 Streamer.getContext().getAsmInfo()->getInitialFrameState())495 if (!handleCFI(FDE, BaseFRE, CFI))496 Valid = false;497 }498 FDE.FREs.push_back(BaseFRE);499 500 for (const auto &CFI : DF.Instructions) {501 // Instructions from InitialFrameState may not have a label, but if these502 // instructions don't, then they are in dead code or otherwise unused.503 // TODO: This check follows MCDwarf.cpp504 // FrameEmitterImplementation::emitCFIInstructions, but nothing in the505 // testsuite triggers it. We should see if it can be removed in both506 // places, or alternately, add a test to exercise it.507 auto *L = CFI.getLabel();508 if (L && !L->isDefined())509 continue;510 511 SFrameFRE FRE = FDE.FREs.back();512 if (!handleCFI(FDE, FRE, CFI))513 Valid = false;514 515 // If nothing relevant but the location changed, don't add the FRE.516 if (equalIgnoringLocation(FRE, FDE.FREs.back()))517 continue;518 519 // If the location stayed the same, then update the current520 // row. Otherwise, add a new one.521 if (atSameLocation(LastLabel, L))522 FDE.FREs.back() = FRE;523 else {524 FDE.FREs.push_back(FRE);525 FDE.FREs.back().Label = L;526 LastLabel = L;527 }528 }529 530 if (Valid) {531 FDEs.push_back(FDE);532 TotalFREs += FDE.FREs.size();533 }534 }535 536 void emitPreamble() {537 Streamer.emitInt16(Magic);538 Streamer.emitInt8(static_cast<uint8_t>(Version::V2));539 Streamer.emitInt8(static_cast<uint8_t>(Flags::FDEFuncStartPCRel));540 }541 542 void emitHeader() {543 emitPreamble();544 // sfh_abi_arch545 Streamer.emitInt8(static_cast<uint8_t>(SFrameABI));546 // sfh_cfa_fixed_fp_offset547 Streamer.emitInt8(0);548 // sfh_cfa_fixed_ra_offset549 Streamer.emitInt8(FixedRAOffset);550 // sfh_auxhdr_len551 Streamer.emitInt8(0);552 // shf_num_fdes553 Streamer.emitInt32(FDEs.size());554 // shf_num_fres555 Streamer.emitInt32(TotalFREs);556 557 // shf_fre_len558 Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,559 sizeof(int32_t));560 // shf_fdeoff. With no sfh_auxhdr, these immediately follow this header.561 Streamer.emitInt32(0);562 // shf_freoff563 Streamer.emitInt32(FDEs.size() *564 sizeof(sframe::FuncDescEntry<endianness::native>));565 }566 567 void emitFDEs() {568 Streamer.emitLabel(FDESubSectionStart);569 for (auto &FDE : FDEs) {570 FDE.emit(Streamer, FRESubSectionStart);571 }572 }573 574 void emitFREs() {575 Streamer.emitLabel(FRESubSectionStart);576 for (auto &FDE : FDEs) {577 Streamer.emitLabel(FDE.FREStart);578 for (auto &FRE : FDE.FREs)579 FRE.emit(Streamer, FDE.DFrame.Begin, FDE.Frag);580 }581 Streamer.emitLabel(FRESubSectionEnd);582 }583};584 585} // end anonymous namespace586 587void MCSFrameEmitter::emit(MCObjectStreamer &Streamer) {588 MCContext &Context = Streamer.getContext();589 // If this target doesn't support sframes, return now. Gas doesn't warn in590 // this case, but if we want to, it should be done at option-parsing time,591 // rather than here.592 if (!Streamer.getContext()593 .getObjectFileInfo()594 ->getSFrameABIArch()595 .has_value())596 return;597 598 SFrameEmitterImpl Emitter(Streamer);599 ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getDwarfFrameInfos();600 601 // Both the header itself and the FDEs include various offsets and counts.602 // Therefore, all of this must be precomputed.603 for (const auto &DFrame : FrameArray)604 Emitter.buildSFDE(DFrame);605 606 MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();607 // Not strictly necessary, but gas always aligns to 8, so match that.608 Section->ensureMinAlignment(Align(8));609 Streamer.switchSection(Section);610 MCSymbol *SectionStart = Context.createTempSymbol();611 Streamer.emitLabel(SectionStart);612 Emitter.emitHeader();613 Emitter.emitFDEs();614 Emitter.emitFREs();615}616 617void MCSFrameEmitter::encodeFuncOffset(MCContext &C, uint64_t Offset,618 SmallVectorImpl<char> &Out,619 MCFragment *FDEFrag) {620 // If encoding into the FDE Frag itself, generate the sfde_func_info.621 if (FDEFrag == nullptr) {622 // sfde_func_info623 624 // Offset is the difference between the function start label and the final625 // FRE's offset, which is the max offset for this FDE.626 FDEInfo<endianness::native> I;627 I.Info = 0;628 if (isUInt<8>(Offset))629 I.setFREType(FREType::Addr1);630 else if (isUInt<16>(Offset))631 I.setFREType(FREType::Addr2);632 else {633 assert(isUInt<32>(Offset));634 I.setFREType(FREType::Addr4);635 }636 I.setFDEType(FDEType::PCInc);637 // TODO: When we support pauth keys, this will need to be retrieved638 // from the frag itself.639 I.setPAuthKey(0);640 641 Out.push_back(I.getFuncInfo());642 return;643 }644 645 const auto &FDEData = FDEFrag->getVarContents();646 FDEInfo<endianness::native> I;647 I.Info = FDEData.back();648 FREType T = I.getFREType();649 llvm::endianness E = C.getAsmInfo()->isLittleEndian()650 ? llvm::endianness::little651 : llvm::endianness::big;652 // sfre_start_address653 switch (T) {654 case FREType::Addr1:655 assert(isUInt<8>(Offset) && "Miscalculated Sframe FREType");656 support::endian::write<uint8_t>(Out, Offset, E);657 break;658 case FREType::Addr2:659 assert(isUInt<16>(Offset) && "Miscalculated Sframe FREType");660 support::endian::write<uint16_t>(Out, Offset, E);661 break;662 case FREType::Addr4:663 assert(isUInt<32>(Offset) && "Miscalculated Sframe FREType");664 support::endian::write<uint32_t>(Out, Offset, E);665 break;666 }667}668