X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMCWin64EH.cpp;h=b8b07d3a180875f6bfd101c0bf576fedb353ffc2;hb=bf6f7a713f8b1509abe291dbf9df0ca8cfb56145;hp=c7141f7ad3ce5c5e92a93b08f184db50876729bc;hpb=c4cbf9b6aa95cf861a5a80bfccf615ff5c53e4ef;p=oota-llvm.git diff --git a/lib/MC/MCWin64EH.cpp b/lib/MC/MCWin64EH.cpp index c7141f7ad3c..b8b07d3a180 100644 --- a/lib/MC/MCWin64EH.cpp +++ b/lib/MC/MCWin64EH.cpp @@ -8,10 +8,13 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCWin64EH.h" -#include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" -#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" namespace llvm { @@ -61,19 +64,19 @@ static void EmitAbsDifference(MCStreamer &streamer, MCSymbol *lhs, static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, MCWin64EHInstruction &inst) { - uint8_t b1, b2; + uint8_t b2; uint16_t w; - b2 = (inst.getOperation() & 0x0F) << 4; + b2 = (inst.getOperation() & 0x0F); switch (inst.getOperation()) { case Win64EH::UOP_PushNonVol: EmitAbsDifference(streamer, inst.getLabel(), begin); - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_AllocLarge: EmitAbsDifference(streamer, inst.getLabel(), begin); if (inst.getSize() > 512*1024-8) { - b2 |= 1; + b2 |= 0x10; streamer.EmitIntValue(b2, 1); w = inst.getSize() & 0xFFF8; streamer.EmitIntValue(w, 2); @@ -85,18 +88,17 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, streamer.EmitIntValue(w, 2); break; case Win64EH::UOP_AllocSmall: - b2 |= ((inst.getSize()-8) >> 3) & 0x0F; + b2 |= (((inst.getSize()-8) >> 3) & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_SetFPReg: - b1 = inst.getOffset() & 0xF0; - streamer.EmitIntValue(b1, 1); + EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; case Win64EH::UOP_SaveNonVol: case Win64EH::UOP_SaveXMM128: - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); w = inst.getOffset() >> 3; @@ -106,7 +108,7 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, break; case Win64EH::UOP_SaveNonVolBig: case Win64EH::UOP_SaveXMM128Big: - b2 |= inst.getRegister() & 0x0F; + b2 |= (inst.getRegister() & 0x0F) << 4; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) @@ -119,21 +121,36 @@ static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, break; case Win64EH::UOP_PushMachFrame: if (inst.isPushCodeFrame()) - b2 |= 1; + b2 |= 0x10; EmitAbsDifference(streamer, inst.getLabel(), begin); streamer.EmitIntValue(b2, 1); break; } } +static void EmitSymbolRefWithOfs(MCStreamer &streamer, + const MCSymbol *Base, + const MCSymbol *Other) { + MCContext &Context = streamer.getContext(); + const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::Create(Base, Context); + const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::Create(Other, Context); + const MCExpr *Ofs = MCBinaryExpr::CreateSub(OtherRef, BaseRef, Context); + const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::Create(Base, + MCSymbolRefExpr::VK_COFF_IMGREL32, + Context); + streamer.EmitValue(MCBinaryExpr::CreateAdd(BaseRefRel, Ofs, Context), 4); +} + static void EmitRuntimeFunction(MCStreamer &streamer, const MCWin64EHUnwindInfo *info) { MCContext &context = streamer.getContext(); streamer.EmitValueToAlignment(4); - streamer.EmitValue(MCSymbolRefExpr::Create(info->Begin, context), 4); - streamer.EmitValue(MCSymbolRefExpr::Create(info->End, context), 4); - streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, context), 4); + EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); + EmitSymbolRefWithOfs(streamer, info->Function, info->End); + streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, + MCSymbolRefExpr::VK_COFF_IMGREL32, + context), 4); } static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { @@ -142,22 +159,25 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { MCContext &context = streamer.getContext(); streamer.EmitValueToAlignment(4); - // Upper 3 bits are the version number (currently 1). - uint8_t flags = 0x20; info->Symbol = context.CreateTempSymbol(); streamer.EmitLabel(info->Symbol); + // Upper 3 bits are the version number (currently 1). + uint8_t flags = 0x01; if (info->ChainedParent) - flags |= Win64EH::UNW_ChainInfo; + flags |= Win64EH::UNW_ChainInfo << 3; else { if (info->HandlesUnwind) - flags |= Win64EH::UNW_TerminateHandler; + flags |= Win64EH::UNW_TerminateHandler << 3; if (info->HandlesExceptions) - flags |= Win64EH::UNW_ExceptionHandler; + flags |= Win64EH::UNW_ExceptionHandler << 3; } streamer.EmitIntValue(flags, 1); - EmitAbsDifference(streamer, info->PrologEnd, info->Begin); + if (info->PrologEnd) + EmitAbsDifference(streamer, info->PrologEnd, info->Begin); + else + streamer.EmitIntValue(0, 1); uint8_t numCodes = CountOfUnwindCodes(info->Instructions); streamer.EmitIntValue(numCodes, 1); @@ -166,8 +186,8 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { if (info->LastFrameInst >= 0) { MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst]; assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg); - frame = ((frameInst.getRegister() & 0x0F) << 4) | - ((frameInst.getOffset() >> 4) & 0x0F); + frame = (frameInst.getRegister() & 0x0F) | + (frameInst.getOffset() & 0xF0); } streamer.EmitIntValue(frame, 1); @@ -179,11 +199,67 @@ static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) { EmitUnwindCode(streamer, info->Begin, inst); } - if (flags & Win64EH::UNW_ChainInfo) + // For alignment purposes, the instruction array will always have an even + // number of entries, with the final entry potentially unused (in which case + // the array will be one longer than indicated by the count of unwind codes + // field). + if (numCodes & 1) { + streamer.EmitIntValue(0, 2); + } + + if (flags & (Win64EH::UNW_ChainInfo << 3)) EmitRuntimeFunction(streamer, info->ChainedParent); - else if (flags &(Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler)) - streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, context), - 4); + else if (flags & + ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3)) + streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, + MCSymbolRefExpr::VK_COFF_IMGREL32, + context), 4); + else if (numCodes == 0) { + // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not + // a chained unwind info, if there is no handler, and if there are fewer + // than 2 slots used in the unwind code array, we have to pad to 8 bytes. + streamer.EmitIntValue(0, 4); + } +} + +StringRef MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol *func) { + if (!func || !func->isInSection()) return ""; + const MCSection *section = &func->getSection(); + const MCSectionCOFF *COFFSection; + if ((COFFSection = dyn_cast(section))) { + StringRef name = COFFSection->getSectionName(); + size_t dollar = name.find('$'); + size_t dot = name.find('.', 1); + if (dollar == StringRef::npos && dot == StringRef::npos) + return ""; + if (dot == StringRef::npos) + return name.substr(dollar); + if (dollar == StringRef::npos || dot < dollar) + return name.substr(dot); + return name.substr(dollar); + } + return ""; +} + +static const MCSection *getWin64EHTableSection(StringRef suffix, + MCContext &context) { + if (suffix == "") + return context.getObjectFileInfo()->getXDataSection(); + + return context.getCOFFSection((".xdata"+suffix).str(), + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); +} + +static const MCSection *getWin64EHFuncTableSection(StringRef suffix, + MCContext &context) { + if (suffix == "") + return context.getObjectFileInfo()->getPDataSection(); + return context.getCOFFSection((".pdata"+suffix).str(), + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); } void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, @@ -191,8 +267,8 @@ void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, // Switch sections (the static function above is meant to be called from // here and from Emit(). MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); - const MCSection *xdataSect = asmInfo.getWin64EHTableSection(); + const MCSection *xdataSect = + getWin64EHTableSection(GetSectionSuffix(info->Function), context); streamer.SwitchSection(xdataSect); llvm::EmitUnwindInfo(streamer, info); @@ -201,16 +277,21 @@ void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) { MCContext &context = streamer.getContext(); // Emit the unwind info structs first. - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); - const MCSection *xdataSect = asmInfo.getWin64EHTableSection(); - streamer.SwitchSection(xdataSect); - for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) - llvm::EmitUnwindInfo(streamer, &streamer.getW64UnwindInfo(i)); + for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { + MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); + const MCSection *xdataSect = + getWin64EHTableSection(GetSectionSuffix(info.Function), context); + streamer.SwitchSection(xdataSect); + llvm::EmitUnwindInfo(streamer, &info); + } // Now emit RUNTIME_FUNCTION entries. - const MCSection *pdataSect = asmInfo.getWin64EHFuncTableSection(); - streamer.SwitchSection(pdataSect); - for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) - EmitRuntimeFunction(streamer, &streamer.getW64UnwindInfo(i)); + for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { + MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); + const MCSection *pdataSect = + getWin64EHFuncTableSection(GetSectionSuffix(info.Function), context); + streamer.SwitchSection(pdataSect); + EmitRuntimeFunction(streamer, &info); + } } } // End of namespace llvm