gccのビルトイン関数には関数のリターンアドレスやフレームポインタなどを取得することができる関数がある。この関数を使用しsetjmp/longjmpの実装は以下の様になる。たぶんバグはないはず?

jmp.c

#include <stdio.h>
#include <stdlib.h>

#define JMP_BUFFSIZE 6

typedef struct {
	unsigned long __jmp_buf[JMP_BUFFSIZE];
} jmp_buf[1];

jmp_buf jmp_buffer;

int setjmp(jmp_buf env)
{
	void *return_addr = __builtin_return_address(0);

	asm volatile("movl %%edx, 0(%%ecx)\n\t"	/* return address */
		     "movl %%ebx, 4(%%ecx)\n\t"
		     "movl %%esp, 8(%%ecx)\n\t"
		     "movl %%ebp, 12(%%ecx)\n\t"
		     "movl %%esi, 16(%%ecx)\n\t"
 		     "movl %%edi, 20(%%ecx)"
		     :: "d" (return_addr), "c" (env));
	return 0;
}

int longjmp(jmp_buf env, int val)
{
	asm volatile("movl 0(%%edx), %%ecx\n\t"	/* return address */
		     "movl 4(%%edx), %%ebx\n\t"
		     "movl 8(%%edx), %%esp\n\t"
		     "movl 12(%%edx), %%ebp\n\t"
		     "movl 16(%%edx), %%esi\n\t"
		     "movl 20(%%edx), %%edi\n\t"
		     "cmpl $0, %%eax\n\t" /* if val = 0 */
		     "jne  1f\n\t"
		     "movl $1, %%eax\n\t" /* then val = 1 */
		     "1: jmp *%%ecx"
		     :: "a" (val), "d" (env));
	/* NOTREACHED */

        return 0;
}

void func2(void)
{
	longjmp(jmp_buffer, 100);
}

void func1(void)
{
	func2();
}

int main(void)
{
	int ret = 0;

	ret = setjmp(jmp_buffer);
	if (ret != 0) {
		printf("longjmp: %d\n", ret);
		exit(0);
	}

	func1();

	printf("Error: cannot reach this code\n");
	
	return ret;
}

コンパイルと実行

$ gcc jmp.c
$ ./a.out
longjmp: 100