119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//                     The LLVM Compiler Infrastructure
419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file is distributed under the University of Illinois Open Source
619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// License. See LICENSE.TXT for details.
719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===//
919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCWin64EH.h"
1119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCStreamer.h"
1219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCContext.h"
1319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCObjectFileInfo.h"
1419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCSymbol.h"
1519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCSectionCOFF.h"
1619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/MC/MCExpr.h"
1719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/ADT/Twine.h"
1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumannamespace llvm {
2019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
2119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// NOTE: All relocations generated here are 4-byte image-relative.
2219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
2319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &instArray){
2419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t count = 0;
2519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  for (std::vector<MCWin64EHInstruction>::const_iterator I = instArray.begin(),
2619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman       E = instArray.end(); I != E; ++I) {
2719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    switch (I->getOperation()) {
2819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_PushNonVol:
2919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_AllocSmall:
3019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_SetFPReg:
3119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_PushMachFrame:
3219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      count += 1;
3319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      break;
3419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_SaveNonVol:
3519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_SaveXMM128:
3619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      count += 2;
3719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      break;
3819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_SaveNonVolBig:
3919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_SaveXMM128Big:
4019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      count += 3;
4119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      break;
4219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    case Win64EH::UOP_AllocLarge:
4319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      if (I->getSize() > 512*1024-8)
4419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        count += 3;
4519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      else
4619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        count += 2;
4719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      break;
4819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
4919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
5019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return count;
5119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
5219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
5319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic void EmitAbsDifference(MCStreamer &streamer, MCSymbol *lhs,
5419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                              MCSymbol *rhs) {
5519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MCContext &context = streamer.getContext();
5619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCExpr *diff = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(
5719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                                                  lhs, context),
5819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                               MCSymbolRefExpr::Create(
5919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                                                  rhs, context),
6019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                               context);
6119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitAbsValue(diff, 1);
6219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
6319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
6419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
6519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin,
6619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                           MCWin64EHInstruction &inst) {
6719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t b1, b2;
6819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint16_t w;
6919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  b2 = (inst.getOperation() & 0x0F);
7019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  switch (inst.getOperation()) {
7119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_PushNonVol:
7219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
7319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    b2 |= (inst.getRegister() & 0x0F) << 4;
7419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
7519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
7619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_AllocLarge:
7719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
7819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (inst.getSize() > 512*1024-8) {
7919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      b2 |= 0x10;
8019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      streamer.EmitIntValue(b2, 1);
8119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w = inst.getSize() & 0xFFF8;
8219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      streamer.EmitIntValue(w, 2);
8319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w = inst.getSize() >> 16;
8419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    } else {
8519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      streamer.EmitIntValue(b2, 1);
8619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w = inst.getSize() >> 3;
8719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
8819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(w, 2);
8919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
9019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_AllocSmall:
9119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    b2 |= (((inst.getSize()-8) >> 3) & 0x0F) << 4;
9219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
9319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
9419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
9519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_SetFPReg:
9619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    b1 = inst.getOffset() & 0xF0;
9719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b1, 1);
9819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
9919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_SaveNonVol:
10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_SaveXMM128:
10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    b2 |= (inst.getRegister() & 0x0F) << 4;
10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
10519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    w = inst.getOffset() >> 3;
10619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (inst.getOperation() == Win64EH::UOP_SaveXMM128)
10719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w >>= 1;
10819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(w, 2);
10919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
11019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_SaveNonVolBig:
11119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_SaveXMM128Big:
11219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    b2 |= (inst.getRegister() & 0x0F) << 4;
11319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
11419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
11519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big)
11619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w = inst.getOffset() & 0xFFF0;
11719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    else
11819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      w = inst.getOffset() & 0xFFF8;
11919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(w, 2);
12019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    w = inst.getOffset() >> 16;
12119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(w, 2);
12219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
12319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  case Win64EH::UOP_PushMachFrame:
12419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (inst.isPushCodeFrame())
12519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      b2 |= 0x10;
12619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, inst.getLabel(), begin);
12719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(b2, 1);
12819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    break;
12919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
13019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
13119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic void EmitRuntimeFunction(MCStreamer &streamer,
13319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                const MCWin64EHUnwindInfo *info) {
13419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MCContext &context = streamer.getContext();
13519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
13619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitValueToAlignment(4);
13719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitValue(MCSymbolRefExpr::Create(info->Begin, context), 4);
13819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitValue(MCSymbolRefExpr::Create(info->End, context), 4);
13919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, context), 4);
14019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
14119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) {
14319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // If this UNWIND_INFO already has a symbol, it's already been emitted.
14419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (info->Symbol) return;
14519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
14619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MCContext &context = streamer.getContext();
14719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitValueToAlignment(4);
14819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Upper 3 bits are the version number (currently 1).
14919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t flags = 0x01;
15019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  info->Symbol = context.CreateTempSymbol();
15119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitLabel(info->Symbol);
15219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
15319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (info->ChainedParent)
15419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    flags |= Win64EH::UNW_ChainInfo << 3;
15519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  else {
15619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (info->HandlesUnwind)
15719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      flags |= Win64EH::UNW_TerminateHandler << 3;
15819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (info->HandlesExceptions)
15919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      flags |= Win64EH::UNW_ExceptionHandler << 3;
16019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
16119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitIntValue(flags, 1);
16219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (info->PrologEnd)
16419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
16519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  else
16619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitIntValue(0, 1);
16719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
16819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
16919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitIntValue(numCodes, 1);
17019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
17119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t frame = 0;
17219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (info->LastFrameInst >= 0) {
17319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst];
17419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg);
17519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    frame = (frameInst.getRegister() & 0x0F) |
17619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            (frameInst.getOffset() & 0xF0);
17719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
17819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.EmitIntValue(frame, 1);
17919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
18019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Emit unwind instructions (in reverse order).
18119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  uint8_t numInst = info->Instructions.size();
18219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  for (uint8_t c = 0; c < numInst; ++c) {
18319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    MCWin64EHInstruction inst = info->Instructions.back();
18419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    info->Instructions.pop_back();
18519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitUnwindCode(streamer, info->Begin, inst);
18619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
18719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
18819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (flags & (Win64EH::UNW_ChainInfo << 3))
18919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitRuntimeFunction(streamer, info->ChainedParent);
19019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  else if (flags &
19119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman           ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
19219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, context),
19319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                       4);
19419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  else if (numCodes < 2) {
19519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
19619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // a chained unwind info, if there is no handler, and if there are fewer
19719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
19819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (numCodes == 1)
19919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      streamer.EmitIntValue(0, 2);
20019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    else
20119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      streamer.EmitIntValue(0, 4);
20219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
20319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
20419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
20519bac1e08be200c31efd26f0f5fd144c9b3eefd3John BaumanStringRef MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol *func) {
20619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (!func || !func->isInSection()) return "";
20719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCSection *section = &func->getSection();
20819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCSectionCOFF *COFFSection;
20919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if ((COFFSection = dyn_cast<MCSectionCOFF>(section))) {
21019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    StringRef name = COFFSection->getSectionName();
21119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    size_t dollar = name.find('$');
21219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    size_t dot = name.find('.', 1);
21319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (dollar == StringRef::npos && dot == StringRef::npos)
21419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      return "";
21519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (dot == StringRef::npos)
21619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      return name.substr(dollar);
21719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    if (dollar == StringRef::npos || dot < dollar)
21819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      return name.substr(dot);
21919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return name.substr(dollar);
22019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
22119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return "";
22219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
22319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
22419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic const MCSection *getWin64EHTableSection(StringRef suffix,
22519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                               MCContext &context) {
22619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (suffix == "")
22719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return context.getObjectFileInfo()->getXDataSection();
22819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
22919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return context.getCOFFSection((".xdata"+suffix).str(),
23019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
23119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_MEM_READ |
23219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_MEM_WRITE,
23319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                SectionKind::getDataRel());
23419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
23519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
23619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic const MCSection *getWin64EHFuncTableSection(StringRef suffix,
23719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                                   MCContext &context) {
23819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (suffix == "")
23919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    return context.getObjectFileInfo()->getPDataSection();
24019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return context.getCOFFSection((".pdata"+suffix).str(),
24119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
24219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_MEM_READ |
24319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                COFF::IMAGE_SCN_MEM_WRITE,
24419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                SectionKind::getDataRel());
24519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
24619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
24719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanvoid MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer,
24819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                            MCWin64EHUnwindInfo *info) {
24919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Switch sections (the static function above is meant to be called from
25019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // here and from Emit().
25119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MCContext &context = streamer.getContext();
25219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  const MCSection *xdataSect =
25319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    getWin64EHTableSection(GetSectionSuffix(info->Function), context);
25419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  streamer.SwitchSection(xdataSect);
25519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
25619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  llvm::EmitUnwindInfo(streamer, info);
25719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
25819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
25919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanvoid MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) {
26019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MCContext &context = streamer.getContext();
26119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Emit the unwind info structs first.
26219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) {
26319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i);
26419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    const MCSection *xdataSect =
26519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      getWin64EHTableSection(GetSectionSuffix(info.Function), context);
26619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.SwitchSection(xdataSect);
26719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    llvm::EmitUnwindInfo(streamer, &info);
26819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
26919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  // Now emit RUNTIME_FUNCTION entries.
27019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) {
27119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i);
27219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    const MCSection *pdataSect =
27319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman      getWin64EHFuncTableSection(GetSectionSuffix(info.Function), context);
27419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    streamer.SwitchSection(pdataSect);
27519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    EmitRuntimeFunction(streamer, &info);
27619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  }
27719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
27819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
27919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} // End of namespace llvm
28019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
281