#ifndef context_h #define context_h 1 #include #if !defined(__x86_64__) #error "context.h solo soporta x86_64!" #endif namespace as { enum when : int { first = 0, next = 1 }; //-------------------------------------------------------------------- // struct inline_context //-------------------------------------------------------------------- struct inline_context // SystemV AMD64 ABI { void *reg[8]; // rsp, rbp, rbx, r12, r13, r14, r15, rip; when __attribute__((always_inline, returns_twice)) get() { when ret; asm volatile(" lea 0f(%%rip),%%rax \n" " mov %%rsp,0(%1) \n" " mov %%rbp,8(%1) \n" " mov %%rbx,16(%1) \n" " mov %%r12,24(%1) \n" " mov %%r13,32(%1) \n" " mov %%r14,40(%1) \n" " mov %%r15,48(%1) \n" " mov %%rax,56(%1) \n" " xor %%eax,%%eax \n" // ret = first = 0 "0: \n" : "=a"(ret) : "r"(this) : "cc", "memory"); return ret; } void __attribute__((always_inline, noreturn)) set(when ret = next) const { if (ret == first) ret = next; asm volatile("mov 0(%0),%%rsp \n" "mov 8(%0),%%rbp \n" "mov 16(%0),%%rbx \n" "mov 24(%0),%%r12 \n" "mov 32(%0),%%r13 \n" "mov 40(%0),%%r14 \n" "mov 48(%0),%%r15 \n" "jmp *56(%0) \n" : : "r"(this), "a"(ret)); std::unreachable(); } }; // inline_context //-------------------------------------------------------------------- // class context //-------------------------------------------------------------------- class context // SystemV AMD64 ABI { public: when __attribute__((naked, noinline, returns_twice)) get() noexcept { asm volatile("mov (%%rsp),%%rax \n" "mov %%rax,0(%0) \n" "lea 8(%%rsp),%%rax \n" "mov %%rax,8(%0) \n" "mov %%rbp,16(%0) \n" "mov %%rbx,24(%0) \n" "mov %%r12,32(%0) \n" "mov %%r13,40(%0) \n" "mov %%r14,48(%0) \n" "mov %%r15,56(%0) \n" "xor %%eax,%%eax \n" // first = 0 "ret \n" : : "r"(this) : "cc", "memory", "rax"); } void __attribute__((naked, noinline, noreturn)) set(when ret = next) const noexcept { if (ret == first) ret = next; asm volatile("mov 8(%0),%%rsp \n" "mov 16(%0),%%rbp \n" "mov 24(%0),%%rbx \n" "mov 32(%0),%%r12 \n" "mov 40(%0),%%r13 \n" "mov 48(%0),%%r14 \n" "mov 56(%0),%%r15 \n" "jmp *0(%0) \n" : : "r"(this), "a"(ret) : "memory"); std::unreachable(); } private: void *reg[8]; // rip, rsp, rbp, rbx, r12, r13, r14, r15; }; // context } // namespace as #endif // context_h