/*
 *	ucontext.c
 *
 *	儐乕僓乕僐儞僥僉僗僩(System V屳姺)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 Naoyuki Sawa
 *
 *	* Sun May 17 15:20:04 JST 2015 Naoyuki Sawa
 *	- 1st 儕儕乕僗丅
 *	* Tue Nov 29 23:01:43 JST 2016 Naoyuki Sawa
 *	- 婛懚偺P/ECE梡偺幚憰偵壛偊偰丄Win32梡偲Win64梡偺幚憰傪捛壛偟傑偟偨丅
 *	  婛懚偺P/ECE梡偺幚憰偼丄曄峏偟偰偄傑偣傫丅
 *	- Win32梡偺幚憰偵偮偄偰偼丄壓婰偺儁乕僕偵幚憰椺偑桳傝傑偡偑丄偙傟偼惓偟偔摦嶌偟傑偣傫丅
 *	  乽CodeProject - Unix ucontext_t Operations on Windows Platforms乿(https://www.codeproject.com/tips/4225/unix-ucontext-t-operations-on-windows-platforms)
 *	  忋婰偺幚憰椺偼丄GetThreadContext(),SetThreadContext() API傪棙梡偟偰偄傑偡偑丄偦傟傜偺API偼幚峴拞偺僗儗僢僪帺恎偵懳偟偰惓偟偄抣傪曉偝側偄巇條偩偐傜偱偡丅
 *	  (傕偟忋庤偔摦偄偨傛偆偵尒偊偰傕丄偦傟偼偨傑偨傑忋庤偔摦偄偨傛偆偵尒偊偰偄傞偩偗偱偡丅)
 *	  廬偭偰崱夞偼丄GetThreadContext(),SetThreadContext() API傪巊梡偣偢偵丄傾僙儞僽儔偱幚憰偡傞帠偵偟傑偟偨丅
 *	  傾僙儞僽儔偱幚憰偡傞偵偁偨傝丄Win32偲Win64偦傟偧傟偱丄setjmp()/longjmp()偺惗惉僐乕僪傪尒偰丄偦傟傜偑峴偭偰偄傞張棟傪嶲峫偵偟偰幚憰偟傑偟偨丅
 *	- Win64偺傾僙儞僽儔傪彂偔偺偼崱夞偑弶傔偰偱丄屇傃弌偟婯栺偵偮偄偰偄偔偮偐偺婰帠傪嶲峫偵偝偣偰捀偒傑偟偨丅
 *	  崱夞嶲峫偵偝偣偰捀偄偨婰帠傪丄ucontext.c偺拞偺乽Win64梡偺幚憰帪偵嶲峫偵偟偨帒椏乿偵堷梡偟偰偍偒傑偟偨丅
 *	- Win64梡偺getcontext(),setcontext(),makecontext()偼丄/clip/libclip.x64/ucontext_x64.asm偵偰幚憰偟傑偟偨丅
 *	  徻嵶偼丄ucontext.c偺拞偺乽Win64乿偺幚憰売強偺僐儊儞僩傪嶲徠偟偰壓偝偄丅
 */
#include "clip.h"
/****************************************************************************
 *	
 ****************************************************************************/
#ifdef  PIECE
static_assert((sizeof(stack_t) ==  8) && (sizeof(mcontext_t) ==  24) && (sizeof(ucontext_t) ==  36), "stack_t峔憿懱,枖偼,mcontext_t峔憿懱,枖偼,ucontext_t峔憿懱偺僒僀僘偑晄惓偱偡丅");	//P/ECE
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if     (defined(_WIN32) && !defined(_WIN64))
static_assert((sizeof(stack_t) ==  8) && (sizeof(mcontext_t) ==  24) && (sizeof(ucontext_t) ==  36), "stack_t峔憿懱,枖偼,mcontext_t峔憿懱,枖偼,ucontext_t峔憿懱偺僒僀僘偑晄惓偱偡丅");	//Win32
#endif//(defined(_WIN32) && !defined(_WIN64))
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if     (defined(_WIN32) &&  defined(_WIN64))
static_assert((sizeof(stack_t) == 16) && (sizeof(mcontext_t) == 240) && (sizeof(ucontext_t) == 264), "stack_t峔憿懱,枖偼,mcontext_t峔憿懱,枖偼,ucontext_t峔憿懱偺僒僀僘偑晄惓偱偡丅");	//Win64
#endif//(defined(_WIN32) &&  defined(_WIN64))
/****************************************************************************
 *	P/ECE
 ****************************************************************************/
#ifdef  PIECE
/*static*/ void ContextEntry();
/*static*/ void ContextLink();
asm("
		.code
		.align		1
ContextEntry:	;//-------------------------------------;//
		xld.w		%r12, [%sp+ 0]		;//%r12 := arg1,枖偼,晄掕抣
		xld.w		%r13, [%sp+ 4]		;//%r13 := arg2,枖偼,晄掕抣
		xld.w		%r14, [%sp+ 8]		;//%r14 := arg3,枖偼,晄掕抣
		xld.w		%r15, [%sp+12]		;//%r15 := arg4,枖偼,晄掕抣
		xadd		%sp, %sp,  16		;//
		ret					;//func(arg1,arg2,arg3,arg4)
ContextLink:	;//-------------------------------------;//
		xld.w		%r12, [%sp+0]		;//%r12 := ucp
	;//晄梫	xadd		%sp, %sp, 4		;//
		xld.w		%r12, [%r12+0]		;//%r12 := uc_link = ucp->uc_link
		cmp		%r12, 0			;//
		xjreq		exit			;//if(!uc_link) { exit(0) }
		xjp		setcontext		;//setcontext(uc_link)
");
/*--------------------------------------------------------------------------*/
int swapcontext(ucontext_t* oucp, const ucontext_t* ucp);
int setcontext(const ucontext_t* ucp);
int getcontext(ucontext_t* ucp);
asm("
		.code
		.align		1
		.global		swapcontext
		.global		setcontext
		.global		getcontext
swapcontext:	;//-------------------------------------;//
		add		%r12, 12		;//%r12 := mcp = &oucp->uc_mcontext
		ld.w		%r4, %sp		;//%r4  := %sp
		ld.w		%r5, [%r4]+		;//%r5  := %pc = [%r4]+
		ld.w		%sp, %r4		;//%sp  := %r4
		ld.w		[%r12]+, %r0		;//mcp->r0 := %r0
		ld.w		[%r12]+, %r1		;//mcp->r1 := %r1
		ld.w		[%r12]+, %r2		;//mcp->r2 := %r2
		ld.w		[%r12]+, %r3		;//mcp->r3 := %r3
		ld.w		[%r12]+, %r4		;//mcp->sp := %r4
		ld.w		[%r12]+, %r5		;//mcp->pc := %r5
		ld.w		%r12, %r13		;//%r12 := ucp				return setcontext(ucp)
setcontext:	;//- - - - - - - - - - - - - - - - - - -;//
		add		%r12, 12		;//%r12 := mcp = &ucp->uc_mcontext
		ld.w		%r0, [%r12]+		;//%r0  := mcp->r0
		ld.w		%r1, [%r12]+		;//%r1  := mcp->r1
		ld.w		%r2, [%r12]+		;//%r2  := mcp->r2
		ld.w		%r3, [%r12]+		;//%r3  := mcp->r3
		ld.w		%r4, [%r12]+		;//%r4  := mcp->sp
		ld.w		%r5, [%r12]+		;//%r5  := mcp->pc
		ld.w		%sp, %r4		;//%sp  := %r4
		ld.w		%r10, 0			;//%r10 := 0
		jp		%r5			;//return  0				'jp.d %rb'偼晄壜
getcontext:	;//-------------------------------------;//
		add		%r12, 12		;//%r12 := mcp = &ucp->uc_mcontext
		ld.w		%r4, %sp		;//%r4  := %sp
		ld.w		%r5, [%r4]+		;//%r5  := %pc = [%r4]+
		ld.w		%sp, %r4		;//%sp  := %r4
		ld.w		[%r12]+, %r0		;//mcp->r0 := %r0
		ld.w		[%r12]+, %r1		;//mcp->r1 := %r1
		ld.w		[%r12]+, %r2		;//mcp->r2 := %r2
		ld.w		[%r12]+, %r3		;//mcp->r3 := %r3
		ld.w		[%r12]+, %r4		;//mcp->sp := %r4
		ld.w		[%r12]+, %r5		;//mcp->pc := %r5
		ld.w		%r10, 0			;//%r10 := 0
		jp		%r5			;//return  0				'jp.d %rb'偼晄壜
");
/*--------------------------------------------------------------------------*/
void makecontext(ucontext_t* ucp, void (*func)(), int argc, ...) {
	void** stack;
	va_list ap;
	stack = (void**)((char*)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
	*--stack = ucp;
	*--stack = ContextLink;
	*--stack = func;
	ucp->uc_mcontext.sp = (stack -= 4);
	ucp->uc_mcontext.pc = ContextEntry;
	if((unsigned)argc > 4) { DIE(); }		//摉幚憰偼(argc亝4)偵惂尷偟偨丅(argc亜4)偵懳墳偡傞帠傕壜擻偩偑幚憰僐僗僩偑戝偒偄妱偵幚嵺偵巊梡偡傞帠偼婬偩偐傜丅
	va_start(ap, argc);
	while(--argc >= 0) { *stack++ = va_arg(ap, void*); }
	va_end(ap);
}
#endif//PIECE
/****************************************************************************
 *	Win32
 ****************************************************************************/
#if     (defined(_WIN32) && !defined(_WIN64))
static void ContextEntry(ucontext_t* ucp, void (*func)(), void* arg1, void* arg2, void* arg3, void* arg4) {
	(*func)(arg1, arg2, arg3, arg4);
	if(ucp->uc_link) { setcontext(ucp->uc_link); }
	exit(0);
}
/*--------------------------------------------------------------------------*/
__declspec(naked) int getcontext(ucontext_t* ucp) {
	__asm {
			;//[esp+ 0] := retp
			;//[esp+ 4] := ucp
			pop		edx					;//edx := retp = *esp++
			mov		ecx, dword ptr [esp+ 0]			;//ecx := ucp
			mov		dword ptr [ecx+12], ebx			;//ucp->uc_mcontext.ebx := ebx
			mov		dword ptr [ecx+16], esi			;//ucp->uc_mcontext.esi := esi
			mov		dword ptr [ecx+20], edi			;//ucp->uc_mcontext.edi := edi
			mov		dword ptr [ecx+24], ebp			;//ucp->uc_mcontext.ebp := ebp
			mov		dword ptr [ecx+28], esp			;//ucp->uc_mcontext.esp := esp
			mov		dword ptr [ecx+32], edx			;//ucp->uc_mcontext.eip := retp
			mov		eax, 0					;//eax := 0
			jmp		edx					;//return 0
	}
}
/*--------------------------------------------------------------------------*/
__declspec(naked) int setcontext(const ucontext_t* ucp) {
	__asm {
			;//[esp+ 0] := retp
			;//[esp+ 4] := ucp
			mov		ecx, dword ptr [esp+ 4]			;//ecx := ucp
			mov		ebx, dword ptr [ecx+12]			;//ebx := ucp->uc_mcontext.ebx
			mov		esi, dword ptr [ecx+16]			;//esi := ucp->uc_mcontext.esi
			mov		edi, dword ptr [ecx+20]			;//edi := ucp->uc_mcontext.edi
			mov		ebp, dword ptr [ecx+24]			;//ebp := ucp->uc_mcontext.ebp
			mov		esp, dword ptr [ecx+28]			;//esp := ucp->uc_mcontext.esp
			mov		edx, dword ptr [ecx+32]			;//edx := ucp->uc_mcontext.eip
			mov		eax, 0					;//eax := 0
			jmp		edx					;//return 0
	}
}
/*--------------------------------------------------------------------------*/
__declspec(naked) int swapcontext(ucontext_t* oucp, const ucontext_t* ucp) {
	__asm {
			;//[esp+ 0] := retp
			;//[esp+ 4] := oucp
			;//[esp+ 8] := ucp
			pop		edx					;//edx := retp = *esp++
			mov		ecx, dword ptr [esp+ 0]			;//ecx := oucp
			mov		dword ptr [ecx+12], ebx			;//oucp->uc_mcontext.ebx := ebx
			mov		dword ptr [ecx+16], esi			;//oucp->uc_mcontext.esi := esi
			mov		dword ptr [ecx+20], edi			;//oucp->uc_mcontext.edi := edi
			mov		dword ptr [ecx+24], ebp			;//oucp->uc_mcontext.ebp := ebp
			mov		dword ptr [ecx+28], esp			;//oucp->uc_mcontext.esp := esp
			mov		dword ptr [ecx+32], edx			;//oucp->uc_mcontext.eip := retp
			;//- - - - - - - - - - - - - - - - - - - - - - - - - - -;//
			mov		ecx, dword ptr [esp+ 4]			;//ecx := ucp
			mov		ebx, dword ptr [ecx+12]			;//ebx := ucp->uc_mcontext.ebx
			mov		esi, dword ptr [ecx+16]			;//esi := ucp->uc_mcontext.esi
			mov		edi, dword ptr [ecx+20]			;//edi := ucp->uc_mcontext.edi
			mov		ebp, dword ptr [ecx+24]			;//ebp := ucp->uc_mcontext.ebp
			mov		esp, dword ptr [ecx+28]			;//esp := ucp->uc_mcontext.esp
			mov		edx, dword ptr [ecx+32]			;//edx := ucp->uc_mcontext.eip
			mov		eax, 0					;//eax := 0
			jmp		edx					;//return 0
	}
}
/*--------------------------------------------------------------------------*/
void makecontext(ucontext_t* ucp, void (*func)(), int argc, ...) {
	void** stack;
	va_list ap;
	stack = (void**)((char*)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
	stack -= (1/*retp(僟儈乕)*/ + 1/*ucp*/ + 1/*func*/ + 4/*arg1,arg2,arg3,arg4*/);
	ucp->uc_mcontext.esp = stack;
	ucp->uc_mcontext.eip = ContextEntry;
	if((unsigned)argc > 4) { DIE(); }		//摉幚憰偼(argc亝4)偵惂尷偟偨丅(argc亜4)偵懳墳偡傞帠傕壜擻偩偑幚憰僐僗僩偑戝偒偄妱偵幚嵺偵巊梡偡傞帠偼婬偩偐傜丅
	stack += 1/*retp(僟儈乕)*/;
	*stack++ = ucp;
	*stack++ = func;
	va_start(ap, argc);
	while(--argc >= 0) { *stack++ = va_arg(ap, void*); }
	va_end(ap);
	//僗僞僢僋偺撪梕偼埲壓偺傛偆偵側偭偰偄傑偡丅
	//劇劅劅劅劅劅劅劉ucp->uc_stack.ss_sp
	//劆丒		劆
	//劆丒		劆
	//劆丒		劆
	//劆retp(僟儈乕)劆ucp->uc_mcontext.esp+ 0
	//劆ucp		劆ucp->uc_mcontext.esp+ 4
	//劆func	劆ucp->uc_mcontext.esp+ 8
	//劆arg1	劆ucp->uc_mcontext.esp+12
	//劆arg2	劆ucp->uc_mcontext.esp+16
	//劆arg3	劆ucp->uc_mcontext.esp+20
	//劆arg4	劆ucp->uc_mcontext.esp+24
	//劋劅劅劅劅劅劅劊ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size
}
#endif//(defined(_WIN32) && !defined(_WIN64))
/****************************************************************************
 *	Win64
 ****************************************************************************/
#if     (defined(_WIN32) &&  defined(_WIN64))
static void ContextEntry(void* rcx, void* rdx, void* r8, void* r9, ucontext_t* ucp, void (*func)(), void* arg1, void* arg2, void* arg3, void* arg4) {
	//               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~fastcall屇傃弌偟婯栺偱偼(偨偲偊壜曄堷悢偱傕)嵟弶偺4偮偺堷悢偼忢偵儗僕僗僞搉偟偵側傞丅makecontext()偵偰堷悢傪僗僞僢僋偵愊傓偨傔偵嵟弶偺4偮傪僟儈乕堷悢偲偟偨丅
	(*func)(arg1, arg2, arg3, arg4);
	if(ucp->uc_link) { setcontext(ucp->uc_link); }
	exit(0);
}
/*--------------------------------------------------------------------------*/
// * Tue Nov 29 23:01:43 JST 2016 Naoyuki Sawa
// - Win64梡偺getcontext(),setcontext(),makecontext()偼丄/clip/libclip.x64/ucontext_x64.asm偵偰幚憰偟傑偟偨丅
//   VS2015偺x64僞乕僎僢僩偱偼丄C僜乕僗僼傽僀儖撪偱僀儞儔僀儞傾僙儞僽儔偑巊偊偢丄傾僙儞僽儔僜乕僗僼傽僀儖傪嶌惉偟偰傾僙儞僽儖偡傞昁梫偑桳傞偐傜偱偡丅
// - 仩嶲峫帒椏
//   劆嘆乽Yahoo抦宐戃 - Windows偱VisualC++傪巊偭偰傾僙儞僽儔僾儘僌儔儉傪僐儞僷僀儖偡傞曽朄偵偮偄偰乿(http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1296433897)
//   劆嘇乽僆僼傿僗僨僀僞僀儉乿(http://www.officedaytime.com/)偝傫偺丄乽Visual C++僀儞儔僀儞傾僙儞僽儔傪x64偵堏怉偡傞乿(http://www.officedaytime.com/tips/asm64/index.html)
//   劆嘊乽Sample is best! ASM > hello乿(http://www32.atwiki.jp/sampleisbest/pages/82.html)
//   劆嘋乽YouTube - How to create a Visual Studio 2010, 2012, 2013 or 2015 64 bit Assembly language project.乿(https://www.youtube.com/watch?v=QWWTrdNkhBI)
// - 忋婰偺嘆偑摿偵徻偟偔彂偐傟偰偄偰丄嶲峫偵側傝傑偡丅
//   偨偩偟丄嘆偺婰帠偱偼丄VS2010傪巊偭偰價儖僪愝掕偺曽朄偑彂偐傟偰偄傑偡偑丄VS2015偱偼偦偺曽朄偱偼愝掕偱偒傑偣傫偱偟偨丅
//   VS2015偱偼丄嘊媦傃嘋偱愢柧偝傟偰偄傞曽朄偱丄忋庤偔峴偒傑偟偨丅
//   嘆嘊嘋傪撉傓偲丄嘊嘋偺曽朄偱偼傾僙儞僽儔Only偺僾儘僕僃僋僩偟偐嶌傟側偄傛偆偵巚偭偰偟傑偄傑偡偑丄晛捠偵C偲傾僙儞僽儔偑崿嵼偟偨僾儘僕僃僋僩偵弌棃傑偟偨丅
// - 婛懚偺丄64價僢僩梡CLiP儔僀僽儔儕僾儘僕僃僋僩偵丄ucontext_x64.asm傪捛壛偟偨曽朄偼丄埲壓偺捠傝偱偡丅
//   劆1. VS2015偱丄64價僢僩梡CLiP儔僀僽儔儕僾儘僕僃僋僩(\Home\Share\Piece\clip\libclip.x64\libclip.sln)傪奐偔丅
//   劆2. 僜儕儏乕僔儑儞僄僋僗僾儘乕儔偺儁僀儞偱丄乽libclip乿傪嵍僋儕僢僋偟偰慖戰忬懺偵偡傞丅
//   劆3. 儊僯儏乕僶乕偺丄乽僾儘僕僃僋僩(P)乿佀乽價儖僪偺僇僗僞儅僀僘(B)...乿傪慖戰偡傞丅
//   劆4. 乽Visual C++ 價儖僪僇僗僞儅僀僘僼傽僀儖乿僟僀傾儘僌偑昞帵偝傟傞偺偱丄乽masm(.targets,.props)乿偵僠僃僢僋傪晅偗丄乽OK乿傪墴偟偰僟僀傾儘僌傪暵偠傞丅
//   劆5. 僜儕儏乕僔儑儞僄僋僗僾儘乕儔偺儁僀儞偱丄乽libclip乿傪塃僋儕僢僋偟丄乽捛壛(D)乿佀乽婛懚偺崁栚(G)...乿傪慖戰偟丄ucontext_x64.asm傪捛壛偡傞丅
//   埲忋偱偡丅
//   2.乣4.偲5.偺庤弴傪媡偵偡傞偲丄ucontext_x64.asm偺價儖僪愝掕偑忋庤偔側偝傟側偄偺偱丄庤弴偵拲堄偟偰壓偝偄丅(嶲峫帒椏嘊偺乽僜乕僗僼傽僀儖偺捛壛乿偺強偵傕彂偄偰偁傝傑偡丅)
//   彯丄2.乣4.偺愝掕偼堦搙偩偗峴偊偽椙偄偲巚偆偺偱丄崱屻偼丄扨偵asm僼傽僀儖傪捛壛偡傞偩偗偱椙偄偲巚偄傑偡丅
/*--------------------------------------------------------------------------*/
void makecontext(ucontext_t* ucp, void (*func)(), int argc, ...) {
	void** stack;
	va_list ap;
	stack = (void**)((char*)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
	stack -= (4/*rcx,rdx,r8,r9戅旔梡*/ + 1/*ucp*/ + 1/*func*/ + 4/*arg1,arg2,arg3,arg4*/);
	stack = (void**)((intptr_t)stack & ~(16 - 1));	//16 byte aligned
	stack -= 1/*retp(僟儈乕)*/;
	ucp->uc_mcontext.rsp = stack;
	ucp->uc_mcontext.rip = ContextEntry;
	stack += (1/*retp(僟儈乕)*/ + 4/*rcx,rdx,r8,r9戅旔梡*/);
	*stack++ = ucp;
	*stack++ = func;
	if((unsigned)argc > 4) { DIE(); }		//摉幚憰偼(argc亝4)偵惂尷偟偨丅(argc亜4)偵懳墳偡傞帠傕壜擻偩偑幚憰僐僗僩偑戝偒偄妱偵幚嵺偵巊梡偡傞帠偼婬偩偐傜丅
	va_start(ap, argc);
	while(--argc >= 0) { *stack++ = va_arg(ap, void*); }
	va_end(ap);
	//僗僞僢僋偺撪梕偼埲壓偺傛偆偵側偭偰偄傑偡丅
	//劇劅劅劅劅劅劅劉ucp->uc_stack.ss_sp
	//劆丒		劆
	//劆丒		劆
	//劆丒		劆
	//劆retp(僟儈乕)劆ucp->uc_mcontext.esp+ 0
	//劆rcx戅旔梡	劆ucp->uc_mcontext.esp+ 8	仼16 byte aligned
	//劆rdx戅旔梡	劆ucp->uc_mcontext.esp+16
	//劆r8戅旔梡	劆ucp->uc_mcontext.esp+24
	//劆r9戅旔梡	劆ucp->uc_mcontext.esp+32
	//劆ucp		劆ucp->uc_mcontext.esp+40
	//劆func	劆ucp->uc_mcontext.esp+48
	//劆arg1	劆ucp->uc_mcontext.esp+56
	//劆arg2	劆ucp->uc_mcontext.esp+64
	//劆arg3	劆ucp->uc_mcontext.esp+72
	//劆arg4	劆ucp->uc_mcontext.esp+80
	//劋劅劅劅劅劅劅劊ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size
}
#endif//(defined(_WIN32) &&  defined(_WIN64))
/****************************************************************************
 *	getcontext(),setcontext()偺巊梡椺
 ****************************************************************************/
#if 0
//getcontext(),setcontext()偺巊梡椺
void app_main(){
 volatile int i=0;//'volatile'昁恵
 ucontext_t c;
 getcontext(&c);
 printf("%d\n",i);
 delay(SEC(1));
 if(++i<=9){setcontext(&c);}
}
#endif
/****************************************************************************
 *	makecontext(),swapcontext()偺巊梡椺
 ****************************************************************************/
#if 0
ucontext_t c1,c2,c3;
unsigned char stack[1024];
void func2(const char* fmt,int num){
 printf("func2 called\n");
 do{
  printf(fmt,num);
  swapcontext(&c2,&c1);
 }while(--num);
 //偙偺屻c2.uc_link偵廬偭偰c3傊慗堏偡傞丅
}
void func3(){
 printf("func3 called\n");
 //偙偺屻c3.uc_link==NULL側偺偱廔椆偡傞丅
}
void app_main(){
 //'uc_link'傪愝掕偡傞椺
 getcontext(&c2);//makecontext()偺慜偵getcontext()傪屇傇偟偒偨傝丅P/ECE偱偼徣棯壜擻偩偑宍幃忋屇傫偱偍偔帠偵偟偨丅
 c2.uc_link=&c3;
 c2.uc_stack.ss_sp=stack;
 c2.uc_stack.ss_size=sizeof stack;
 makecontext(&c2,func2,2,"num=%d",5);
 //'uc_link'傪愝掕偟側偄椺
 getcontext(&c3);//makecontext()偺慜偵getcontext()傪屇傇偟偒偨傝丅P/ECE偱偼徣棯壜擻偩偑宍幃忋屇傫偱偍偔帠偵偟偨丅
 c3.uc_link=NULL;
 c3.uc_stack.ss_sp=FRAM4_START;//stack_switch_FRAM4()憡摉偺摦嶌偲偡傞帠傕壜擻丅
 c3.uc_stack.ss_size=FRAM4_SIZE;//
 makecontext(&c3,func3,0);
 //c1佀c2(5)佀c1佀c2(4)佀c1佀c2(3)佀c1佀c2(2)佀c1佀c2(1)佀c1佀c2(0)佀c3佀廔椆
 for(;;){
  swapcontext(&c1,&c2);
  putchar('\n');
 }
}
#endif
/****************************************************************************
 *	Win64梡偺幚憰帪偵嶲峫偵偟偨帒椏
 ****************************************************************************/
#if 0
仩嶲峫帒椏乽MSDN - x64僜僼僩僂僃傾婯栺 - 儗僕僗僞偺巊梡乿(https://msdn.microsoft.com/ja-jp/library/9z1stfyw.aspx)
劆儗僕僗僞偺巊梡
劆
劆x64傾乕僉僥僋僠儍偵偼丄16屄偺斈梡儗僕僗僞(偙傟埲崀丄惍悢儗僕僗僞偲屇傃傑偡)偲16屄偺晜摦彫悢揰梡偺XMM/YMM儗僕僗僞偑梡堄偝傟偰偄傑偡丅
劆volatile儗僕僗僞偼丄屇傃弌偟偱巊梡偝傟偨屻偵撪梕偑攋婞偝傟傞偙偲偑丄屇傃弌偟尦偵傛偭偰憐掕偝傟偰偄傞僗僋儔僢僠儗僕僗僞偱偡丅
劆娭悢屇傃弌偟偱巊梡偝傟偨屻傕儗僕僗僞偺抣傪曐帩偡傞偵偼旕volatile儗僕僗僞偑昁梫偱偡丅
劆巊梡偝傟偨旕volatile儗僕僗僞偺曐懚偼丄屇傃弌偟愭偑峴偆昁梫偑偁傝傑偡丅
劆
劆娭悢屇傃弌偟偱奺儗僕僗僞偑偳偺傛偆偵巊梡偝傟傞偐傪師偺昞偵帵偟傑偡丅
劆
劆	劇劅劅劅劅劅劅劅劅劅劅劅劍劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劍劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劉
劆	劆儗僕僗僞		劆忬懺					劆梡搑																	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劑劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劑劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆RAX			劆Volatile				劆栠傝抣儗僕僗僞															劆
劆	劆RCX			劆Volatile				劆1斣栚偺惍悢堷悢															劆
劆	劆RDX			劆Volatile				劆2斣栚偺惍悢堷悢															劆
劆	劆R8			劆Volatile				劆3斣栚偺惍悢堷悢															劆
劆	劆R9			劆Volatile				劆4斣栚偺惍悢堷悢															劆
劆	劆R10:R11		劆Volatile				劆昁梫偵墳偠偰丄屇傃弌偟尦偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅syscall/sysret柦椷偱巊梡偝傟傑偡丅						劆
劆	劆R12:R15		劆旕volatile				劆屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅												劆
劆	劆RDI			劆旕volatile				劆屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅												劆
劆	劆RSI			劆旕volatile				劆屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅												劆
劆	劆RBX			劆旕volatile				劆屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅												劆
劆	劆RBP			劆旕volatile				劆僼儗乕儉億僀儞僞乕偲偟偰巊梡偱偒傑偡丅屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅							劆
劆	劆RSP			劆旕volatile				劆僗僞僢僋億僀儞僞乕															劆
劆	劆XMM0,YMM0		劆Volatile				劆1斣栚偺FP堷悢丅__vectorcall偑巊梡偝傟偨応崌偺1斣栚偺儀僋僞乕宆堷悢丅									劆
劆	劆XMM1,YMM1		劆Volatile				劆2斣栚偺FP堷悢丅__vectorcall偑巊梡偝傟偨応崌偺2斣栚偺儀僋僞乕宆堷悢丅									劆
劆	劆XMM2,YMM2		劆Volatile				劆3斣栚偺FP堷悢丅__vectorcall偑巊梡偝傟偨応崌偺3斣栚偺儀僋僞乕宆堷悢丅									劆
劆	劆XMM3,YMM3		劆Volatile				劆4斣栚偺FP堷悢丅__vectorcall偑巊梡偝傟偨応崌偺4斣栚偺儀僋僞乕宆堷悢丅									劆
劆	劆XMM4,YMM4		劆Volatile				劆昁梫偵墳偠偰丄屇傃弌偟尦偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅__vectorcall偑巊梡偝傟偨応崌偺5斣栚偺儀僋僞乕宆堷悢丅			劆
劆	劆XMM5,YMM5		劆Volatile				劆昁梫偵墳偠偰丄屇傃弌偟尦偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅__vectorcall偑巊梡偝傟偨応崌偺6斣栚偺儀僋僞乕宆堷悢丅			劆
劆	劆XMM6:XMM15,YMM6:YMM15	劆旕volatile(XMM),volatile(YMM偺忋敿暘)	劆昁梫偵墳偠偰丄屇傃弌偟愭偵傛偭偰曐帩偝傟傞昁梫偑偁傝傑偡丅昁梫偵墳偠偰丄屇傃弌偟尦偵傛偭偰YMM儗僕僗僞偑曐帩偝傟傞昁梫偑偁傝傑偡丅	劆
劆	劋劅劅劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劏劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劊
#endif
#if 0
仩嶲峫帒椏乽Akihiro Notes乿(http://akihironotes.blogspot.jp/)偝傫偺丄乽Microsoft x64 屇傃弌偟婯栺乿(http://akihironotes.blogspot.jp/2009/04/microsoft-x64.html)偺婰帠
劆Microsoft x64 屇傃弌偟婯栺
劆
劆x86偼cdecl傗stdcall,fastcall側偳偄偔偮偐偺屇傃弌偟婯栺偑偁傝傑偡偑丄x64偼fastcall偟偐偁傝傑偣傫丅
劆
劆堷悢
劆
劆丒戞1堷悢rcx傕偟偔偼xmm0
劆丒戞2堷悢rdx傕偟偔偼xmm1
劆丒戞3堷悢r8傕偟偔偼xmm2
劆丒戞4堷悢r9傕偟偔偼xmm3
劆丒戞5堷悢埲崀僗僞僢僋
劆
劆戞1堷悢偐傜戞4堷悢偵偮偄偰偼宆偵傛偭偰埲壓偺傛偆側抣偑搉偝傟傑偡丅
劆
劆丒惍悢宆丄1,2,4,8僶僀僩偺峔憿懱丄__m64偼斈梡儗僕僗僞偵抣偲偟偰搉偝傟傞丅枹巊梡忋埵價僢僩偼僋儕傾偝傟側偄丅
劆丒float/double偼xmm儗僕僗僞偵抣偲偟偰搉偝傟傞丅枹巊梡忋埵價僢僩偼僋儕傾偝傟側偄丅
劆丒忋婰埲奜(1,2,4,8僶僀僩埲奜偺峔憿懱丄__m128)偼斈梡儗僕僗僞偵億僀儞僞偲偟偰搉偝傟傞丅億僀儞僞偼16byte偱傾儔僀儞儊儞僩偝傟偰偄傞丅
劆
劆栠傝抣
劆
劆丒惍悢宆丄1,2,4,8僶僀僩偺峔憿懱丄__m64偼rax偵抣偲偟偰曉偝傟傞丅
劆丒float/double/__m128偼xmm0偵抣偲偟偰曉偝傟傞丅
劆丒忋婰埲奜偼娭悢屇傃弌偟帪偺嵟弶偺堷悢(rcx)偲偟偰栠傝抣偺億僀儞僞傪搉偟丄偦偺傾僪儗僗偵栠傝抣偺撪梕偑僐僺乕偝傟傞丅rax偵偼偦偺億僀儞僞(偮傑傝戞1堷悢偲摨偠抣)偑曉偝傟傞丅戞1堷悢偑栠傝抣偺億僀儞僞偲側傞偨傔丄娭悢偺杮棃偺堷悢偼戞2堷悢埲崀偵搉偝傟傞丅
劆
劆屇傃弌偟捈屻偺僗僞僢僋
劆
劆丂娭悢屇傃弌偟帪偼屇傃弌偟懁偱32僶僀僩埲忋偺僗僞僢僋椞堟傪妋曐偟偰偐傜call傪峴偆昁梫偑偁傝傑偡丅
劆丂32僶僀僩偲偄偆偺偼儗僕僗僞搉偟偲側傞4偮偺堷悢傪僗僞僢僋偵戅旔偡傞偺偵昁梫偲側傞僒僀僘偱偡丅偙傟偼屇傃弌偟偨偄娭悢偺幚嵺偺堷悢偑3偮埲壓偺偲偒偱傕妋曐偟偰偍偔昁梫偑偁傝傑偡丅妋曐偟偨僗僞僢僋偺拞恎偼枹弶婜壔偺傑傑偱峔偄傑偣傫丅5偮栚埲崀偺堷悢偼偦傟偵懕偔傛偆偵push偝傟傑偡丅
劆丂偝傜偵傕偆堦偮偺寛傑傝偲偟偰call捈慜偺僗僞僢僋億僀儞僞偑16僶僀僩傾儔僀儞偝傟偰偄傞昁梫偑偁傝傑偡丅
劆
劆	劇劅劅劅劅劅劅劅劅劅劅劅劉
劆	劆(僗僞僢僋壓埵)	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆儕僞乕儞傾僪儗僗	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎仼16 byte aligned
劆	劆戞1堷悢(rcx)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞2堷悢(rdx)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞3堷悢(r8)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞4堷悢(r9)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆(僗僞僢僋忋埵)	劆
劆	劋劅劅劅劅劅劅劅劅劅劅劅劊
劆	堷悢偑4偮埲壓偺娭悢傪屇傃弌偟偨捈屻偺僗僞僢僋偺忬懺
劆
劆	劇劅劅劅劅劅劅劅劅劅劅劅劉
劆	劆(僗僞僢僋壓埵)	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆儕僞乕儞傾僪儗僗	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎仼16 byte aligned
劆	劆戞1堷悢(rcx)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞2堷悢(rdx)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞3堷悢(r8)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞4堷悢(r9)戅旔梡	劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆戞5堷悢		劆
劆	劌劅劅劅劅劅劅劅劅劅劅劅劎
劆	劆(僗僞僢僋忋埵)	劆
劆	劋劅劅劅劅劅劅劅劅劅劅劅劊
劆	堷悢偑5偮偺娭悢傪屇傃弌偟偨捈屻偺僗僞僢僋偺忬懺
#endif
#if 0
仩嶲峫帒椏乽偪乕偪乕偺彫僱僞晹壆乿(http://kirihari.net/)偝傫偺丄乽SSE2柦椷(movdqu)傪巊梡偟偨128價僢僩扨埵偺儊儌儕娫揮憲僾儘僌儔儉乿(http://kirihari.net/program/memcpy.html)偺婰帠
劆SSE2柦椷(movdqu)傪巊梡偟偨128價僢僩扨埵偺儊儌儕娫揮憲僾儘僌儔儉
劆
劆SSE2偱偼丄128價僢僩惍悢墘嶼偺SIMD柦椷偺奼挘偑峴傢傟偰偍傝丄墘嶼偩偗偱側偔丄movdqa丒movdqu偲偄偆柦椷傪巊偆偙偲偱128價僢僩扨埵偱儊儌儕娫偺僨乕僞僐僺乕傪崅懍偵峴偆偙偲偑偱偒傑偡丅
劆movdqa偼揮憲懳徾偺儊儌儕偺傾僪儗僗偑16僶僀僩偺嫬奅(傾儔僀儊儞僩)偵懙偭偰傞昁梫偑偁傝傑偡(傾僪儗僗抣偑16偱妱傝愗傟傞)丅
劆偙傟偵懳偟偰丄movdqu偱偼16僶僀僩偺傾儔僀儊儞僩惂栺偼側偔丄偳偺傾僪儗僗抣偐傜偱傕撉傒彂偒偱偒傑偡丅
劆偨偩丄傾儔僀儊儞僩偑懙偭偰偄傞暘丄CPU偑張棟偟傗偡偄偨傔丄movdqa柦椷偺曽偑幚峴懍搙偑懍偄偱偡丅
劆懍偝傪捛媮偡傞側傜偽丄malloc傗攝楍偺妋曐帪偵16僶僀僩偺傾儔僀儊儞僩傪堄幆偡傞昁梫偑偁傝傑偡丅
劆奺柦椷偺婎杮揑側幚峴懍搙偼Intel偐傜埲壓偺帒椏偑弌偰偄傑偡偑丄偙偺帒椏忋偱偼movdqa丒movdqu偺僗儖乕僾僢僩偲儗僀僥儞僔偼摨偠偵側偭偰傑偡偹丒丒丒丅
劆偪傚偭偲偙偺偁偨傝偼晄柧偱偡丅
劆丒Intel媄弍帒椏乽IA-32柦椷偺儗僀僥儞僔偲僗儖乕僾僢僩乿(PDF)
劆
劆偙偺帒椏偵偼MMX傗SSE偺奼挘柦椷傕嵹偭偰偄傑偡丅
劆偪側傒偵偞偭偔傝暘偗傞偲丄MMX偼64價僢僩偺SIMD柦椷偺奼挘偱丄SSE偼128價僢僩偺晜摦彫悢揰墘嶼偺SIMD柦椷奼挘偩偭偨偲巚偄傑偡丅
劆偲傝偁偊偢丄movdqu傪巊偭偰儊儌儕娫偺僨乕僞揮憲傪峴偆僒儞僾儖偼埲壓偺傛偆偵側傝傑偡丅
劆Linux+gcc偺娐嫬偱摦偒傑偡丅
劆src偲dst偵億僀儞僞傪搉偟丄揮憲僒僀僘傪size偱巜掕偡傞偩偗偱偡丅
劆SSE2旕懳墳偺応崌傪峫偊偰丄normalcalc偺晹暘傪捛壛偟偰傑偡丅
劆
劆僜乕僗僐乕僪
劆
劆//SSE2偺movdqu柦椷傪梡偄偰儊儌儕娫揮憲
劆void memcpy_sse2(void* src, void* dst, size_t size) {
劆  asm("  mov     %0,%%eax          \n"
劆      "  lea     (%%esi,%0),%%ebx  \n"
劆      "ssecalc:                    \n"
劆      "  movdqu  (%%esi),%%xmm0    \n"
劆      "  lea     16(%%esi),%%esi   \n"
劆      "  movdqu  %%xmm0,(%%edi)    \n"
劆      "  lea     16(%%edi),%%edi   \n"
劆      "  sub     $16,%%eax         \n"
劆      "  cmp     $16,%%eax         \n"
劆      "  jge     ssecalc           \n"
劆      "  cmp     %%ebx,%%esi       \n"
劆      "  je      end               \n"
劆      "normalcalc:                 \n"
劆      "  mov     (%%esi),%%al      \n"
劆      "  lea     1(%%esi),%%esi    \n"
劆      "  mov     %%al,(%%edi)      \n"
劆      "  lea     1(%%edi),%%edi    \n"
劆      "  cmp     %%ebx,%%esi       \n"
劆      "  jne     normalcalc        \n"
劆      " end:                       \n"
劆      "  emms"
劆      : : "r"(size),"S"(src),"D"(dst));
劆}
#endif
