feat(libc): windows way for ex handling (wip)
This commit is contained in:
parent
ea3f7b5ae0
commit
a1116fe948
|
|
@ -32,6 +32,13 @@ std::vector<std::uint8_t> WindowsPePatcher::Patch(const std::vector<std::uint8_t
|
|||
auto sections = image.BuildSections();
|
||||
std::array<PeDirectory, 16> directories{};
|
||||
auto nextRva = image.GetEndRva();
|
||||
for (const auto& header : originalHeaders) {
|
||||
if (header.Type != 0x6474e550) continue;
|
||||
std::vector<std::uint8_t> metadata(4);
|
||||
Io::WriteU32(metadata, 0, image.GetRva(header.MappedAddress, header.FileSize));
|
||||
sections.push_back({".ehmeta", nextRva, SectionRead | 0x40u, std::move(metadata)});
|
||||
nextRva = AlignRva(nextRva + sections.back().Data.size());
|
||||
}
|
||||
directories[9] = WindowsTlsBuilder().Build(sourceElf, originalHeaders, image, sections, relocations.BaseRelocations, nextRva);
|
||||
auto relocationData = relocationBuilder.BuildBaseRelocations(relocations.BaseRelocations);
|
||||
if (!relocationData.empty()) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,22 @@ void PeNidPatcher::PatchNids(std::vector<std::uint8_t>& pe, const std::string& l
|
|||
const auto sizeOfOptionalHeader = Read<std::uint16_t>(pe, coffHeaderOffset + 16u);
|
||||
if (sizeOfOptionalHeader == 0u) throw std::runtime_error("no optional header");
|
||||
|
||||
const std::size_t sectionTableOffset = coffHeaderOffset + 20u + sizeOfOptionalHeader;
|
||||
const auto symbolTable = Read<std::uint32_t>(pe, coffHeaderOffset + 8u);
|
||||
const auto symbolCount = Read<std::uint32_t>(pe, coffHeaderOffset + 12u);
|
||||
for (std::uint16_t i = 0; i < numberOfSections; ++i) {
|
||||
const auto offset = sectionTableOffset + i * sizeof(PeSectionHeader);
|
||||
auto section = Read<PeSectionHeader>(pe, offset);
|
||||
if (pe[offset] != '/' || !symbolTable) continue;
|
||||
const std::string reference(reinterpret_cast<const char*>(pe.data() + offset), 8);
|
||||
const auto stringOffset = std::stoul(reference.substr(1));
|
||||
const auto name = ReadCStr(pe, static_cast<std::size_t>(symbolTable) + static_cast<std::size_t>(symbolCount) * 18 + stringOffset);
|
||||
if (name == ".eh_frame") {
|
||||
const char shortName[8] = ".ehfram";
|
||||
std::memcpy(pe.data() + offset, shortName, 8);
|
||||
}
|
||||
}
|
||||
|
||||
const std::size_t optionalHeaderOffset = coffHeaderOffset + 20u;
|
||||
const auto magic = Read<std::uint16_t>(pe, optionalHeaderOffset);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
struct _Unwind_Context {
|
||||
std::uintptr_t registers[17] {};
|
||||
#ifdef _WIN32
|
||||
std::uintptr_t vectorRegisters[16][2] {};
|
||||
#endif
|
||||
std::uintptr_t cfa {};
|
||||
std::uintptr_t region {};
|
||||
std::uintptr_t lsda {};
|
||||
|
|
|
|||
|
|
@ -20,3 +20,42 @@ GCC_GLOBAL_ALIAS(_Unwind_Resume_nid_no_patch_cut, _Unwind_Resume_nid_postfix);
|
|||
GCC_LOCAL_ALIAS(__cxa_free_exception, __cxa_free_exception_nid_postfix);
|
||||
GCC_LOCAL_ALIAS(_ZSt9terminatev, _ZSt9terminatev_nid_postfix);
|
||||
GCC_LOCAL_ALIAS(__cxa_call_terminate, __cxa_call_terminate_nid_postfix);
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C" {
|
||||
void* NativeAllocateException(std::size_t size) asm("__cxa_allocate_exception");
|
||||
void* NativeAllocateException(std::size_t size) {
|
||||
void* object = __cxa_allocate_exception_nid_postfix(size);
|
||||
LibcException::FromObject(object)->_pad = 1;
|
||||
return object;
|
||||
}
|
||||
void NativeFreeException(void* object) asm("__cxa_free_exception");
|
||||
void NativeFreeException(void* object) { __cxa_free_exception_nid_postfix(object); }
|
||||
[[noreturn]] void NativeThrow(void* object, std::type_info* type, void (*destructor)(void*)) asm("__cxa_throw");
|
||||
[[noreturn]] void NativeThrow(void* object, std::type_info* type, void (*destructor)(void*)) {
|
||||
__cxa_throw_nid_postfix(object, type, destructor);
|
||||
}
|
||||
void* NativeBeginCatch(void* exception) asm("__cxa_begin_catch");
|
||||
void* NativeBeginCatch(void* exception) { return __cxa_begin_catch_nid_postfix(exception); }
|
||||
void NativeEndCatch() asm("__cxa_end_catch");
|
||||
void NativeEndCatch() { __cxa_end_catch_nid_postfix(); }
|
||||
[[noreturn]] void NativeRethrow() asm("__cxa_rethrow");
|
||||
[[noreturn]] void NativeRethrow() { __cxa_rethrow_nid_postfix(); }
|
||||
[[noreturn]] void NativeResume(_Unwind_Exception* exception) asm("_Unwind_Resume");
|
||||
[[noreturn]] void NativeResume(_Unwind_Exception* exception) { _Unwind_Resume_nid_postfix(exception); }
|
||||
[[noreturn]] void NativeTerminate() asm("_ZSt9terminatev");
|
||||
[[noreturn]] void NativeTerminate() { LibcException::Terminate(); }
|
||||
[[noreturn]] void NativeCallTerminate(void* exception) asm("__cxa_call_terminate");
|
||||
[[noreturn]] void NativeCallTerminate(void* exception) { __cxa_call_terminate_nid_postfix(exception); }
|
||||
void* NativeExceptionPointer(void* exception) asm("__cxa_get_exception_ptr");
|
||||
void* NativeExceptionPointer(void* exception) { return __cxa_get_exception_ptr_nid_postfix(exception); }
|
||||
void* NativeGlobals() asm("__cxa_get_globals");
|
||||
void* NativeGlobals() { return &LibcException::globals; }
|
||||
void* NativeGlobalsFast() asm("__cxa_get_globals_fast");
|
||||
void* NativeGlobalsFast() { return &LibcException::globals; }
|
||||
unsigned NativeUncaughtExceptions() asm("__cxa_uncaught_exceptions");
|
||||
unsigned NativeUncaughtExceptions() { return LibcException::globals.uncaught; }
|
||||
bool NativeUncaughtException() asm("__cxa_uncaught_exception");
|
||||
bool NativeUncaughtException() { return LibcException::globals.uncaught != 0; }
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ namespace LibcException {
|
|||
struct VtableLayout { std::ptrdiff_t offset; const void* type; void (*destroy)(void*); void (*del)(void*); const char* (*whatFn)(const void*); };
|
||||
const void* vtable = *static_cast<const void* const*>(primary->adjusted);
|
||||
auto* layout = reinterpret_cast<const VtableLayout*>(static_cast<const char*>(vtable) - offsetof(VtableLayout, destroy));
|
||||
#ifdef _WIN32
|
||||
if (!primary->_pad) {
|
||||
using GuestWhat = const char* (__attribute__((sysv_abi)) *)(const void*);
|
||||
what = reinterpret_cast<GuestWhat>(layout->whatFn)(primary->adjusted);
|
||||
} else
|
||||
#endif
|
||||
what = layout->whatFn(primary->adjusted);
|
||||
}
|
||||
int status = 0;
|
||||
|
|
@ -46,7 +52,17 @@ void Release(void* object) {
|
|||
auto* header = FromObject(object);
|
||||
auto* allocation = AllocationOf(header);
|
||||
if (allocation->references.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||
try { if (header->destructor) header->destructor(object); }
|
||||
try {
|
||||
if (header->destructor) {
|
||||
#ifdef _WIN32
|
||||
if (!header->_pad) {
|
||||
using GuestDestructor = void (__attribute__((sysv_abi)) *)(void*);
|
||||
reinterpret_cast<GuestDestructor>(header->destructor)(object);
|
||||
} else
|
||||
#endif
|
||||
header->destructor(object);
|
||||
}
|
||||
}
|
||||
catch (...) { Terminate(); }
|
||||
allocation->~Allocation();
|
||||
std::free(allocation);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,35 @@
|
|||
#include "prx/libc/include/specifics/linux/ElfTypes.hpp"
|
||||
#include "prx/libc/src/specifics/x86_64/RegisterContext.cpp"
|
||||
|
||||
#if defined(__linux__)
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int, _Unwind_Action, std::uint64_t, _Unwind_Exception*, _Unwind_Context*);
|
||||
#endif
|
||||
|
||||
namespace LibcUnwind {
|
||||
bool OwnPersonality(Word personality) {
|
||||
#ifdef _WIN32
|
||||
const auto* code = reinterpret_cast<const Byte*>(personality);
|
||||
if (code[0] == 0xff && code[1] == 0x25) {
|
||||
std::int32_t displacement;
|
||||
std::memcpy(&displacement, code + 2, 4);
|
||||
std::memcpy(&personality, code + 6 + displacement, sizeof(personality));
|
||||
}
|
||||
#endif
|
||||
if (personality == reinterpret_cast<Word>(__gxx_personality_v0_nid_postfix)) return true;
|
||||
#ifdef _WIN32
|
||||
if (personality == reinterpret_cast<Word>(__gxx_personality_v0)) return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
struct Lookup { Word pc; const Byte* fde {}; Word text {}; Word data {}; };
|
||||
|
||||
#ifdef __linux__
|
||||
int FindFrame(dl_phdr_info* info, std::size_t, void* argument) {
|
||||
auto& query = *static_cast<Lookup*>(argument);
|
||||
const Byte* header = nullptr;
|
||||
|
|
@ -40,6 +64,8 @@ int FindFrame(dl_phdr_info* info, std::size_t, void* argument) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct Frame {
|
||||
const Byte* cieBegin {};
|
||||
const Byte* cieEnd {};
|
||||
|
|
@ -52,9 +78,7 @@ struct Frame {
|
|||
bool signal {};
|
||||
};
|
||||
|
||||
bool DecodeFrame(_Unwind_Context& context, Frame& frame) {
|
||||
Lookup query {context.registers[16] - !context.signalFrame};
|
||||
dl_iterate_phdr(FindFrame, &query);
|
||||
bool DecodeCandidate(_Unwind_Context& context, Frame& frame, const Lookup& query) {
|
||||
if (!query.fde) return false;
|
||||
const Byte* p = query.fde;
|
||||
auto length = Read<std::uint32_t>(p);
|
||||
|
|
@ -75,7 +99,11 @@ bool DecodeFrame(_Unwind_Context& context, Frame& frame) {
|
|||
frame.codeAlign = Uleb(c);
|
||||
frame.dataAlign = Sleb(c);
|
||||
frame.returnRegister = version == 1 ? *c++ : Uleb(c);
|
||||
#ifdef _WIN32
|
||||
if (frame.returnRegister >= 17 && frame.returnRegister != 32) return false;
|
||||
#else
|
||||
if (frame.returnRegister >= 17) return false;
|
||||
#endif
|
||||
Byte pointerEncoding = 0, lsdaEncoding = 255;
|
||||
if (*augmentation == 'z') {
|
||||
Word size = Uleb(c);
|
||||
|
|
@ -110,8 +138,73 @@ bool DecodeFrame(_Unwind_Context& context, Frame& frame) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DecodeFrame(_Unwind_Context& context, Frame& frame) {
|
||||
Lookup query {context.registers[16] - !context.signalFrame};
|
||||
#ifdef __linux__
|
||||
dl_iterate_phdr(FindFrame, &query);
|
||||
return DecodeCandidate(context, frame, query);
|
||||
#else
|
||||
MEMORY_BASIC_INFORMATION memory{};
|
||||
if (!VirtualQuery(reinterpret_cast<void*>(query.pc), &memory, sizeof(memory)) || memory.Type != MEM_IMAGE)
|
||||
return false;
|
||||
const auto* base = static_cast<const Byte*>(memory.AllocationBase);
|
||||
const auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(base);
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return false;
|
||||
const auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS64*>(base + dos->e_lfanew);
|
||||
if (nt->Signature != IMAGE_NT_SIGNATURE) return false;
|
||||
const auto* sections = IMAGE_FIRST_SECTION(nt);
|
||||
for (unsigned i = 0; i < nt->FileHeader.NumberOfSections; ++i) {
|
||||
const auto& section = sections[i];
|
||||
if (std::memcmp(section.Name, ".ehmeta", 8) == 0) {
|
||||
const Byte* metadata = base + section.VirtualAddress;
|
||||
const Byte* header = base + Read<std::uint32_t>(metadata);
|
||||
if (header[0] != 1 || header[3] == 255) return false;
|
||||
const Byte* p = header + 4;
|
||||
Encoded(p, header[1], Word(header));
|
||||
const Word count = Encoded(p, header[2]);
|
||||
const auto width = EncodingSize(header[3]);
|
||||
const Byte* table = p;
|
||||
Word lo = 0, hi = count;
|
||||
while (lo < hi) {
|
||||
const Word mid = lo + (hi - lo) / 2;
|
||||
p = table + mid * width * 2;
|
||||
if (Encoded(p, header[3], Word(header)) <= query.pc) lo = mid + 1;
|
||||
else hi = mid;
|
||||
}
|
||||
if (!lo) return false;
|
||||
p = table + (lo - 1) * width * 2 + width;
|
||||
query.fde = reinterpret_cast<const Byte*>(Encoded(p, header[3], Word(header)));
|
||||
return DecodeCandidate(context, frame, query);
|
||||
}
|
||||
if (std::memcmp(section.Name, ".ehfram", 8) != 0) continue;
|
||||
const Byte* p = base + section.VirtualAddress;
|
||||
const Byte* end = p + section.Misc.VirtualSize;
|
||||
while (end - p >= 8) {
|
||||
const Byte* record = p;
|
||||
const auto length = Read<std::uint32_t>(p);
|
||||
if (!length) break;
|
||||
if (length == 0xffffffff || length < 4 || Word(end - p) < length) return false;
|
||||
const Byte* next = p + length;
|
||||
if (Read<std::uint32_t>(p)) {
|
||||
query.fde = record;
|
||||
frame = {};
|
||||
if (DecodeCandidate(context, frame, query)) return true;
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Rule { unsigned kind {}; std::intptr_t value {}; const Byte* expression {}; };
|
||||
struct Rules { Rule registers[17] {}; unsigned cfaRegister {7}; std::intptr_t cfaOffset {}; const Byte* cfaExpression {}; };
|
||||
#ifdef _WIN32
|
||||
constexpr unsigned RuleCount = 33;
|
||||
#else
|
||||
constexpr unsigned RuleCount = 17;
|
||||
#endif
|
||||
|
||||
struct Rules { Rule registers[RuleCount] {}; unsigned cfaRegister {7}; std::intptr_t cfaOffset {}; const Byte* cfaExpression {}; };
|
||||
|
||||
bool Instructions(const Byte* p, const Byte* end, const Frame& frame, Word target, Rules& state, const Rules& initial) {
|
||||
Word location = frame.start;
|
||||
|
|
@ -124,12 +217,12 @@ bool Instructions(const Byte* p, const Byte* end, const Frame& frame, Word targe
|
|||
if ((opcode & 192) == 128) {
|
||||
reg = opcode & 63;
|
||||
auto offset = Uleb(p) * frame.dataAlign;
|
||||
if (reg < 17) state.registers[reg] = {1, static_cast<std::intptr_t>(offset)};
|
||||
if (reg < RuleCount) state.registers[reg] = {1, static_cast<std::intptr_t>(offset)};
|
||||
continue;
|
||||
}
|
||||
if ((opcode & 192) == 192) {
|
||||
reg = opcode & 63;
|
||||
if (reg < 17) state.registers[reg] = initial.registers[reg];
|
||||
if (reg < RuleCount) state.registers[reg] = initial.registers[reg];
|
||||
continue;
|
||||
}
|
||||
switch (opcode) {
|
||||
|
|
@ -141,12 +234,12 @@ bool Instructions(const Byte* p, const Byte* end, const Frame& frame, Word targe
|
|||
case 5: case 17: case 20: case 21: {
|
||||
reg = Uleb(p);
|
||||
auto offset = (opcode == 17 || opcode == 21 ? Sleb(p) : std::intptr_t(Uleb(p))) * frame.dataAlign;
|
||||
if (reg < 17) state.registers[reg] = {unsigned(opcode >= 20 ? 4 : 1), offset};
|
||||
if (reg < RuleCount) state.registers[reg] = {unsigned(opcode >= 20 ? 4 : 1), offset};
|
||||
break;
|
||||
}
|
||||
case 6: reg = Uleb(p); if (reg < 17) state.registers[reg] = initial.registers[reg]; break;
|
||||
case 7: case 8: reg = Uleb(p); if (reg < 17) state.registers[reg] = {unsigned(opcode == 7 ? 5 : 0)}; break;
|
||||
case 9: { reg = Uleb(p); auto other = Uleb(p); if (reg < 17) state.registers[reg] = {2, std::intptr_t(other)}; break; }
|
||||
case 6: reg = Uleb(p); if (reg < RuleCount) state.registers[reg] = initial.registers[reg]; break;
|
||||
case 7: case 8: reg = Uleb(p); if (reg < RuleCount) state.registers[reg] = {unsigned(opcode == 7 ? 5 : 0)}; break;
|
||||
case 9: { reg = Uleb(p); auto other = Uleb(p); if (reg < RuleCount) state.registers[reg] = {2, std::intptr_t(other)}; break; }
|
||||
case 10: if (depth == 16) return false; saved[depth++] = state; break;
|
||||
case 11: if (!depth) return false; state = saved[--depth]; break;
|
||||
case 12: case 18:
|
||||
|
|
@ -157,7 +250,7 @@ bool Instructions(const Byte* p, const Byte* end, const Frame& frame, Word targe
|
|||
case 15: { state.cfaExpression = p; auto size = Uleb(p); p += size; break; }
|
||||
case 16: case 22: {
|
||||
reg = Uleb(p); const Byte* expr = p; auto size = Uleb(p); p += size;
|
||||
if (reg < 17) state.registers[reg] = {unsigned(opcode == 16 ? 3 : 6), 0, expr};
|
||||
if (reg < RuleCount) state.registers[reg] = {unsigned(opcode == 16 ? 3 : 6), 0, expr};
|
||||
break;
|
||||
}
|
||||
case 46: Uleb(p); break;
|
||||
|
|
@ -223,6 +316,13 @@ bool GetRules(_Unwind_Context& context, Frame& frame, Rules& rules) {
|
|||
if (!DecodeFrame(context, frame)) return false;
|
||||
Rules initial;
|
||||
if (!Instructions(frame.cieBegin, frame.cieEnd, frame, ~Word(0), initial, {})) return false;
|
||||
#ifdef _WIN32
|
||||
if (frame.returnRegister == 32) {
|
||||
initial.registers[16] = initial.registers[32];
|
||||
initial.registers[32] = {};
|
||||
frame.returnRegister = 16;
|
||||
}
|
||||
#endif
|
||||
rules = initial;
|
||||
if (!Instructions(frame.begin, frame.end, frame, context.registers[16] - !context.signalFrame, rules, initial)) return false;
|
||||
if (rules.cfaExpression) return Expression(rules.cfaExpression, context, 0, context.cfa);
|
||||
|
|
@ -250,6 +350,17 @@ bool Step(_Unwind_Context& context) {
|
|||
case 5: next.registers[i] = 0; break;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
for (unsigned i = 17; i < RuleCount; ++i) {
|
||||
const auto& rule = rules.registers[i];
|
||||
auto* destination = next.vectorRegisters[i - 17];
|
||||
if (rule.kind == 1) std::memcpy(destination, reinterpret_cast<void*>(context.cfa + rule.value), 16);
|
||||
else if (rule.kind == 2 && rule.value >= 17 && rule.value < RuleCount)
|
||||
std::memcpy(destination, context.vectorRegisters[rule.value - 17], 16);
|
||||
else if (rule.kind == 5) std::memset(destination, 0, 16);
|
||||
else if (rule.kind != 0) return false;
|
||||
}
|
||||
#endif
|
||||
next.registers[7] = context.cfa;
|
||||
next.registers[16] = next.registers[frame.returnRegister];
|
||||
next.signalFrame = frame.signal;
|
||||
|
|
@ -277,7 +388,7 @@ _Unwind_Reason_Code PhaseTwo(_Unwind_Context context, _Unwind_Exception* excepti
|
|||
if (result != _URC_NO_REASON) return result;
|
||||
} else if (context.cfa == exception->private_2) actions = _Unwind_Action(actions | _UA_HANDLER_FRAME);
|
||||
if (frame.personality) {
|
||||
if (frame.personality != reinterpret_cast<Word>(__gxx_personality_v0_nid_postfix)) return _URC_FATAL_PHASE2_ERROR;
|
||||
if (!OwnPersonality(frame.personality)) return _URC_FATAL_PHASE2_ERROR;
|
||||
auto result = __gxx_personality_v0_nid_postfix(1, actions, exception->exception_class, exception, &context);
|
||||
if (result == _URC_INSTALL_CONTEXT) LibcRestoreRegisters(context.registers);
|
||||
if (result != _URC_CONTINUE_UNWIND) return _URC_FATAL_PHASE2_ERROR;
|
||||
|
|
@ -306,7 +417,7 @@ _Unwind_Reason_Code APS5_VABI _Unwind_RaiseException_nid_postfix(_Unwind_Excepti
|
|||
LibcUnwind::Frame frame; LibcUnwind::Rules rules;
|
||||
if (!LibcUnwind::GetRules(context, frame, rules)) return _URC_END_OF_STACK;
|
||||
if (frame.personality) {
|
||||
if (frame.personality != reinterpret_cast<std::uintptr_t>(__gxx_personality_v0_nid_postfix)) return _URC_FATAL_PHASE1_ERROR;
|
||||
if (!LibcUnwind::OwnPersonality(frame.personality)) return _URC_FATAL_PHASE1_ERROR;
|
||||
auto result = __gxx_personality_v0_nid_postfix(1, _UA_SEARCH_PHASE, exception->exception_class, exception, &context);
|
||||
if (result == _URC_HANDLER_FOUND) {
|
||||
exception->private_2 = context.cfa;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,57 @@ asm(
|
|||
"movq 104(%r10),%r13\nmovq 112(%r10),%r14\nmovq 120(%r10),%r15\njmp *%r11\n"
|
||||
".size LibcRestoreRegisters,.-LibcRestoreRegisters\n"
|
||||
);
|
||||
#elif defined(_WIN32) && defined(__x86_64__)
|
||||
asm(
|
||||
".text\n"
|
||||
".globl LibcCaptureRegisters\n"
|
||||
"LibcCaptureRegisters:\n"
|
||||
"movq %rax,0(%rcx)\nmovq %rdx,8(%rcx)\nmovq %rcx,16(%rcx)\nmovq %rbx,24(%rcx)\n"
|
||||
"movq %rsi,32(%rcx)\nmovq %rdi,40(%rcx)\nmovq %rbp,48(%rcx)\n"
|
||||
"leaq 8(%rsp),%rax\nmovq %rax,56(%rcx)\n"
|
||||
"movq %r8,64(%rcx)\nmovq %r9,72(%rcx)\nmovq %r10,80(%rcx)\nmovq %r11,88(%rcx)\n"
|
||||
"movq %r12,96(%rcx)\nmovq %r13,104(%rcx)\nmovq %r14,112(%rcx)\nmovq %r15,120(%rcx)\n"
|
||||
"movdqu %xmm0,136(%rcx)\n"
|
||||
"movdqu %xmm1,152(%rcx)\n"
|
||||
"movdqu %xmm2,168(%rcx)\n"
|
||||
"movdqu %xmm3,184(%rcx)\n"
|
||||
"movdqu %xmm4,200(%rcx)\n"
|
||||
"movdqu %xmm5,216(%rcx)\n"
|
||||
"movdqu %xmm6,232(%rcx)\n"
|
||||
"movdqu %xmm7,248(%rcx)\n"
|
||||
"movdqu %xmm8,264(%rcx)\n"
|
||||
"movdqu %xmm9,280(%rcx)\n"
|
||||
"movdqu %xmm10,296(%rcx)\n"
|
||||
"movdqu %xmm11,312(%rcx)\n"
|
||||
"movdqu %xmm12,328(%rcx)\n"
|
||||
"movdqu %xmm13,344(%rcx)\n"
|
||||
"movdqu %xmm14,360(%rcx)\n"
|
||||
"movdqu %xmm15,376(%rcx)\n"
|
||||
"movq (%rsp),%rax\nmovq %rax,128(%rcx)\nret\n"
|
||||
".globl LibcRestoreRegisters\n"
|
||||
"LibcRestoreRegisters:\n"
|
||||
"movq %rcx,%r10\nmovq 128(%r10),%r11\n"
|
||||
"movdqu 136(%r10),%xmm0\n"
|
||||
"movdqu 152(%r10),%xmm1\n"
|
||||
"movdqu 168(%r10),%xmm2\n"
|
||||
"movdqu 184(%r10),%xmm3\n"
|
||||
"movdqu 200(%r10),%xmm4\n"
|
||||
"movdqu 216(%r10),%xmm5\n"
|
||||
"movdqu 232(%r10),%xmm6\n"
|
||||
"movdqu 248(%r10),%xmm7\n"
|
||||
"movdqu 264(%r10),%xmm8\n"
|
||||
"movdqu 280(%r10),%xmm9\n"
|
||||
"movdqu 296(%r10),%xmm10\n"
|
||||
"movdqu 312(%r10),%xmm11\n"
|
||||
"movdqu 328(%r10),%xmm12\n"
|
||||
"movdqu 344(%r10),%xmm13\n"
|
||||
"movdqu 360(%r10),%xmm14\n"
|
||||
"movdqu 376(%r10),%xmm15\n"
|
||||
"movq 0(%r10),%rax\nmovq 8(%r10),%rdx\nmovq 16(%r10),%rcx\nmovq 24(%r10),%rbx\n"
|
||||
"movq 32(%r10),%rsi\nmovq 40(%r10),%rdi\nmovq 48(%r10),%rbp\nmovq 56(%r10),%rsp\n"
|
||||
"movq 64(%r10),%r8\nmovq 72(%r10),%r9\nmovq 96(%r10),%r12\n"
|
||||
"movq 104(%r10),%r13\nmovq 112(%r10),%r14\nmovq 120(%r10),%r15\njmp *%r11\n"
|
||||
);
|
||||
#else
|
||||
void LibcCaptureRegisters(std::uintptr_t*) { std::abort(); }
|
||||
[[noreturn]] void LibcRestoreRegisters(const std::uintptr_t*) { std::abort(); }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
#include <stdexcept>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" void NotImplemented_nid_no_patch(const char*);
|
||||
|
||||
static int destroyed;
|
||||
struct Guard { ~Guard() { ++destroyed; } };
|
||||
__attribute__((noinline)) static void ThrowNested() {
|
||||
Guard guard;
|
||||
throw std::runtime_error("native own unwind");
|
||||
}
|
||||
__attribute__((noinline)) static void Rethrow() {
|
||||
Guard guard;
|
||||
try { ThrowNested(); }
|
||||
catch (const std::runtime_error&) { throw; }
|
||||
}
|
||||
int main() {
|
||||
try {
|
||||
Rethrow();
|
||||
return 1;
|
||||
} catch (const std::runtime_error& error) {
|
||||
if (std::strcmp(error.what(), "native own unwind") || destroyed != 2) return 2;
|
||||
}
|
||||
try { NotImplemented_nid_no_patch("cross DLL"); }
|
||||
catch (const std::runtime_error& error) {
|
||||
if (std::strcmp(error.what(), "cross DLL not implemented")) return 3;
|
||||
std::puts("Own Windows exceptions: catch, rethrow, destructors, cross DLL passed");
|
||||
return 0;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
Loading…
Reference in New Issue