/* compute the address and check it. This code is only called by your
    program. Not portable...
   Copyright 1993 Tristan Gingold
		  Written September 1993 Tristan Gingold

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address marc@david.saclay.cea.fr,
   or (US/French mail) as Tristan Gingold 
   			  8 rue Parmentier
   			  F91120 PALAISEAU
   			  FRANCE 
*/

#include "config.h"

#ifdef CHKR_USE_BITMAP
/* infos: on Linux, ss = ds = es = fs = gs
	  esi points to the encoded address (i.e. Disp or Modrm)
   Line comment is hard: neither "/*", nor "/" works. So I use the good and
	very old '#'. 
   Binary constants must begin with "0B", not with "0b" (backward local
	label)
*/
	.file "codecheck.s"
/* Registers saved: */
	.data
	.align 4

/* Keep this order */
registers:
Reax:	.long 0
Recx:	.long 0
Redx:	.long 0
Rebx:	.long 0
Resp:	.long 0
Rebp:	.long 0
Resi:	.long 0
Redi:	.long 0	
Reip:	.long 0
Rflag:	.long 0

size:	.long 0
right:	.long 0
accmod:	.long 0
addr:	.long 0

	.text
	.align 4
#ifdef CHKR_DEBUG
	.globl save_register, restore_register, Chkr_Modrm
	.globl Sib, Check_addr
	.globl Reax, Recx, Redx, Rebx, Resp, Rebp, Resi, Redi, Reip
	.globl size, right, accmod
#endif

/* function to save register, so that, we can directly access to them */
save_register:
	movl %eax, Reax
	movl %ebx, Rebx
	movl %ecx, Recx
	movl %edx, Redx
	movl %esi, Resi
	movl %edi, Redi
	movl %ebp, Rebp
	movl %ebp, _chkr_frames_pointer
	pushf			# /* save flag */
	popl Rflag
	cld			# /* default for gcc */
	movl %esp, %eax		# /* compute esp */
	addl $8, %eax
	movl %eax, Resp
	movl %eax, _known_stack_limit	# /* always up to date */
	cmpl %eax, _stack_bitmapped
	jge L00
	movl %eax, _stack_bitmapped	# /* adjust bitmap */
L00:	movl 4(%esp), %eax
	movl %eax, Reip		# /* compute eip */
	movl %eax, _chkr_frames_ip
	movl %eax, %esi
	ret

	.align 4
restore_register:
	pushl Rflag		# /* restore flags */
	popf
	movl Reax, %eax
	movl Rebx, %ebx
	movl Recx, %ecx
	movl Redx, %edx
	movl Resi, %esi
	movl Redi, %edi
	movl Rebp, %ebp
/* eip and esp will be automatically restored */
/*	movl Resp, %esp
	jump (Reip) */
	ret

	.align 4
Chkr_Modrm:
	movb (%esi), %al	# /* load the ModRm byte into al */ 
	andb $0B11000111, %al	# /* We use only the Mod and Rm fields */
#ifndef CHKR_IS_SAFE
	movb %al, %ah		# /* Is it a register ? */
	andb $0B11000000, %ah
	cmpb $0B11000000, %ah
	jne L0
	jmp abort		# /* This is a register. Must never happen */
#endif /* !CHKR_IS_SAFE */
L0:	movb %al, %ah		# /* Test for s-i-b byte */
	andb $0B00000111, %ah
	cmpb $0B00000100, %ah
	je Sib
/* s-i-b byte doesn't follow */
	cmpb $0B00000101, %al	# /* 0b00???101 is special. test it */
	jne L1
/* A 32 disp follows */
	movl 1(%esi),%edi
	jmp Check_addr
/* Load the register */
L1:	movl %eax, %edi
	andl $0B00000111, %edi
	movl registers(,%edi,4), %edi
/* Is there a disp ? */
	movb %al, %ah
	andb $0B11000000, %ah
	cmp  $0B00000000, %ah
	je Check_addr 		# /* no disp, so finish */
	cmp  $0B01000000, %ah	# /* test for mod == 01 */
	jne L2
/* just add a disp8 */
	movsbl 1(%esi), %edx	# /* signed convertion 8 bits to 32 bits */
	addl %edx, %edi
	jmp Check_addr
/* Just add a disp32 */
L2:	addl 1(%esi), %edi
	jmp Check_addr

/* Handle the sib byte 
   In Sib: %al is Modrm, %ah is s-i-b */
Sib:	andb $0B11000000, %al	# /* ignore unuseful bits */
	movb 1(%esi), %ah	# /* load sib byte into ah */
/* handle scale and index */
	movb %ah, %cl
	andb $0B00111000, %cl	# /* mask scale and base */
	cmpb $0B00100000, %cl	# /* test for no index */
	jne L3
	xor  %edi, %edi		# /* clean the address */
	jmp L4			# /* skipf scale, handle directlry the disp */
L3:	xor %ecx, %ecx		# /* clean all 32bits of ecx */
	movb %ah, %cl		
	andb $0B00111000, %cl	# /* keep only index */
	shrb $1, %cl		# /* shift -> the index is good */
	movl registers(%ecx), %edi	# /* load the register */
	movb %ah, %cl		
	andb $0B11000000, %cl	# /* mask index and base */
	shrb $6, %cl		# /* move the index into the first 2 bits */
	shll %cl, %edi		# /* scale now */
L4:	andb $0B00000111, %ah	# /* keep only base */
	cmpw $0x0500, %ax	# /* special case: mod=0, base=101. */
	jne L5
	addl 2(%esi), %edi	# /* add the disp32 */
	jmp Check_addr		# /* end */
L5:	xor %ecx, %ecx		# /* clean ecx, for base register */
	movb %ah, %cl		# /* load base into cl */
	addl registers(,%ecx,4), %edi	# /* add the base register */
	cmpb $0B01000000, %al	# /* Is this a disp8 */
	jne L6			# /* not, handle no disp/disp32 */
	movsbl 2(%esi), %edx	# /* convert disp8 to 32 bits */
	addl %edx, %edi		# /* add the disp */
	jmp Check_addr
L6:	cmpb $0B00000000, %al	# /* test for no disp */
	je Check_addr
	addl 2(%esi), %edi	# /* add disp32 */
	jmp Check_addr
	
# /* Check_addr calls _chkr_check_addr		*/
# /*         arguments: accmod -> right		*/
# /*			size -> len		*/
# /*			%edi -> ptr		*/
Check_addr:
#if 0
/* make a dummy frame, in order to be used by chkr_show_frames */
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	movl accmod, %eax	# /* push the "right" arg */
	pushl %eax
	movl size, %eax		# /* push the "len" arg */
	pushl %eax
	pushl %edi		# /* push the "ptr" arg */
	call _chkr_check_addr	# /* call the chkr_check_addr */
	addl $12, %esp		# /* normalize the stack */
	ret

# /* display a message (unknown instruction) and abort */
abort:	
#if 0
/* make a dummy frame, in order to be used by chkr_show_frames */
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
#endif
	movl $11, _chkr_errno
	call _chkr_perror
	call _chkr_abort
here:	jmp here		# /* infinite loop */

	.globl _make_syscall
_make_syscall:			# /* just do the int instruction */
	pusha			# /* save register for gcc */
#ifndef CHKR_IS_SAFE
	movl Reip, %esi
	cmpw $0x80cd, (%esi)	# /* check for int $0x80 */
	je L7			
	jmp abort		# /* check fails */
L7:
#endif /* CHKR_IS_SAFE */
	movb Rflag, %ah		# /* restore flags */
	sahf
	movl Reax, %eax		# /* restore registers */
	movl Rebx, %ebx
	movl Recx, %ecx
	movl Redx, %edx
	movl Resi, %esi
	movl Redi, %edi
	int $0x80		# /* make the sys call */
	movl %eax, Reax		# /* save registers */
	movl %ebx, Rebx
	movl %ecx, Recx
	movl %edx, Redx
	movl %esi, Resi
	movl %edi, Redi
	lahf			# /* save flag */
	movb %ah, Rflag
	movl Resp, %esi
#ifndef CHKR_IS_SAFE
	movl Reip, %ecx		# /* Be sure about the eip */
	cmpl -4(%esi), %ecx
	je L8
	jmp abort		# /* check fails */
L8:
#endif	/* !CHKR_IS_SAFE */
	addl $2,Reip		# /* forget the int instruction */
	addl $2,-4(%esi)	# /* really forget */
	popa			# /* restore for gcc */
	ret

	
/* chkr functions have this prototype:
        chkr_?_?_?_?_chkr
             | | | |
             | | | +------------------ size of the memory zone
             | | +-------------------- right demanded
             | +---------------------- addressing mode 1:disp, 2:Modrm, 3:str
             |                           4:int, 5:stack, 6:Modrm, 7:call
             +------------------------ bytes to skipf
   str mode is special: accmode: 1 is repne, 2 is repe/rep, 0 means no prefix
*/

#define chkr_1_2_x_x_chkr(accm,s) \
	.globl chkr_1_2_##accm##_##s##_chkr; \
chkr_1_2_##accm##_##s##_chkr:; \
	call save_register;\
	movl $##s##,size; \
	movl $##accm##,accmod; \
	incl %esi; \
	call Chkr_Modrm; \
	call restore_register; \
	ret

#define chkr_x_2_x_x_chkr(l,accm,s) \
	.globl chkr_##l##_2_##accm##_##s##_chkr; \
chkr_##l##_2_##accm##_##s##_chkr:; \
	call save_register;\
	movl $##s##,size; \
	movl $##accm##,accmod; \
	addl $##l##, %esi; \
	call Chkr_Modrm; \
	call restore_register; \
	ret

#define chkr_1_1_x_x_chkr(accm,s) \
	.globl chkr_1_1_##accm##_##s##_chkr; \
chkr_1_1_##accm##_##s##_chkr:; \
	call save_register;\
	movl $##s##,size; \
	movl $##accm##,accmod; \
	movl 1(%esi), %edi; \
	call Check_addr; \
	call restore_register; \
	ret

#define chkr_x_1_x_x_chkr(l,accm,s) \
	.globl chkr_##l##_1_##accm##_##s##_chkr; \
chkr_##l##_1_##accm##_##s##_chkr:; \
	call save_register;\
	movl $##s##,size; \
	movl $##accm##,accmod; \
	movl l##(%esi), %edi; \
	call Check_addr; \
	call restore_register; \
	ret

/* be careful: do not change flags before calling save_register */
#define chkr_0_6_x_x_chkr(accm,s) \
	.globl chkr_0_6_##accm##_##s##_chkr; \
chkr_0_6_##accm##_##s##_chkr:; \
	movl %eax, addr; /* save %eax */ \
	movl (%esp), %eax; /* load the old eip */ \
	xchgl 4(%esp), %eax; /* change the addr and the old eip */ \
	xchgl %eax, addr; /* save addr and restore %eax */ \
	leal 4(%esp), %esp; /* adjust esp */ \
	call save_register;\
	pushl $##accm##; \
	pushl $##s##; \
	pushl addr; \
	call _chkr_check_addr; \
	addl $12, %esp; \
	call restore_register; \
	ret

/* be careful: do not change flags before calling save_register */
#define chkr_1_6_x_x_chkr(accm,s) \
	.globl chkr_1_6_##accm##_##s##_chkr; \
chkr_1_6_##accm##_##s##_chkr:; \
	movl %eax, addr; /* save the addr */ \
	movl (%esp), %eax; /* load the old eip */ \
	xchgl 4(%esp), %eax; /* save the old eip */ \
	leal 4(%esp), %esp; /* change %esp */ \
	call save_register;\
	pushl $##accm##; \
	pushl $0x##s##; \
	pushl addr; \
	call _chkr_check_addr; \
	addl $12, %esp; \
	call restore_register; \
	ret

#ifdef OLD_CHKR
chkr_1_2_x_x_chkr(1,1);		# /* size = 1, accmod = read */
chkr_1_2_x_x_chkr(2,1);		# /* size = 1, accmod = write */
chkr_1_2_x_x_chkr(3,1);		# /* size = 1, accmod = read & write */

chkr_1_2_x_x_chkr(1,2);		# /* size = 2, accmod = read */
chkr_1_2_x_x_chkr(2,2);		# /* size = 2, accmod = write */

chkr_1_2_x_x_chkr(1,4);		# /* size = 4, accmod = read */
chkr_1_2_x_x_chkr(2,4);		# /* size = 4, accmod = write */
chkr_1_2_x_x_chkr(3,4);		# /* size = 4, accmod = read & write */

chkr_1_2_x_x_chkr(1,8);		# /* size = 8, accmod = read */
chkr_1_2_x_x_chkr(2,8);		# /* size = 8, accmod = write */

chkr_x_2_x_x_chkr(2,1,1);	# /* size = 1, accmod = read */

chkr_x_2_x_x_chkr(2,1,2);	# /* size = 2, accmod = read */
chkr_x_2_x_x_chkr(2,2,2);	# /* size = 2, accmod = write */
chkr_x_2_x_x_chkr(2,3,2);	# /* size = 2, accmod = read & write */

chkr_x_2_x_x_chkr(2,1,4);	# /* size = 4, accmod = read */
chkr_x_2_x_x_chkr(2,3,4);	# /* size = 4, accmod = read & write */

chkr_x_2_x_x_chkr(3,1,1);	# /* size = 1, accmod = read */
chkr_x_2_x_x_chkr(3,1,2);	# /* size = 2, accmod = read */
chkr_x_2_x_x_chkr(3,1,4);	# /* size = 4, accmod = read */

chkr_1_1_x_x_chkr(1,4);		# /* size = 4, accmod = read */
chkr_1_1_x_x_chkr(2,4);		# /* size = 4, accmod = write */

chkr_x_1_x_x_chkr(2,1,4);	# /* size = 4, accmod = read */
chkr_x_1_x_x_chkr(2,2,4);	# /* size = 4, accmod = write */
#endif /* OLD_CHKR */

chkr_0_6_x_x_chkr(1,1);		# /* size = 1, accmod = read */
chkr_0_6_x_x_chkr(2,1);		# /* size = 1, accmod = write */
chkr_0_6_x_x_chkr(3,1);		# /* size = 1, accmod = read/write */

chkr_0_6_x_x_chkr(1,2);		# /* size = 2, accmod = read */
chkr_0_6_x_x_chkr(2,2);		# /* size = 2, accmod = write */
chkr_0_6_x_x_chkr(3,2);		# /* size = 2, accmod = read/write */

chkr_0_6_x_x_chkr(1,4);		# /* size = 4, accmod = read */
chkr_0_6_x_x_chkr(2,4);		# /* size = 4, accmod = write */
chkr_0_6_x_x_chkr(3,4);		# /* size = 4, accmod = read/write */

chkr_0_6_x_x_chkr(1,8);		# /* size = 8, accmod = read */
chkr_0_6_x_x_chkr(2,8);		# /* size = 8, accmod = write */
chkr_0_6_x_x_chkr(3,8);		# /* size = 8, accmod = read/write */

chkr_1_6_x_x_chkr(1,1);		# /* size = 1, accmod = read */
chkr_1_6_x_x_chkr(2,1);		# /* size = 1, accmod = write */
chkr_1_6_x_x_chkr(3,1);		# /* size = 1, accmod = read/write */

chkr_1_6_x_x_chkr(1,2);		# /* size = 2, accmod = read */
chkr_1_6_x_x_chkr(2,2);		# /* size = 2, accmod = write */
chkr_1_6_x_x_chkr(3,2);		# /* size = 2, accmod = read/write */

chkr_1_6_x_x_chkr(1,4);		# /* size = 4, accmod = read */
chkr_1_6_x_x_chkr(2,4);		# /* size = 4, accmod = write */
chkr_1_6_x_x_chkr(3,4);		# /* size = 4, accmod = read/write */

chkr_1_6_x_x_chkr(1,8);		# /* size = 8, accmod = read */
chkr_1_6_x_x_chkr(2,8);		# /* size = 8, accmod = write */
chkr_1_6_x_x_chkr(3,8);		# /* size = 8, accmod = read/write */

chkr_1_6_x_x_chkr(1,a);		# /* size = 10, accmod = read */
chkr_1_6_x_x_chkr(2,a);		# /* size = 10, accmod = write */

/* entry point for repne xxx instructions */
	.globl chkr_1_3_1_0_chkr
chkr_1_3_1_0_chkr:
	call save_register
	testl %ecx, %ecx
	je L20
	testl $0x00000400, Rflag
	je Lrepnecld
	jmp abort
Lrepnecld:
	cmpb $0xae, 1(%esi)	# /* is repne scasb */
	je Lzscasb
	jmp abort		# /* don't know */
Lzscasb:
	movl Reax, %eax		# /* load aex */
	repne			# /* execute the instruction */
	scasb
	subl Recx, %ecx		# /* compute the lenth */
	negl %ecx		# /* since we need Recx - %ecx */
	movl %ecx, size
	movl $1, accmod		# /* access is read */
	movl Redi, %edi
	call Check_addr		# /* go... */
L20:	call restore_register
	ret

/* entry point for rep/repe/repz xxx instructions */
	.globl chkr_1_3_2_0_chkr
chkr_1_3_2_0_chkr:
	call save_register
	testl %ecx,%ecx		# /* nothing to check */
	je L30
	testl $0x00000400, Rflag
	je Lrepecld
	cmpb $0xa4, 1(%esi)
	je Lsemovsb		# /* is rep movsb */
	cmpb $0xa5, 1(%esi)
	je Lsemovsl		# /* is rep movsl */
	jmp abort
Lrepecld:			# /* cld */
	cmpb $0xa5, 1(%esi)	# /* is rep movsl */
	je Lcemovsl
	cmpb $0xa6, 1(%esi)	# /* is repz cmpsb */
	je Lcecmpsb
	cmpb $0xaa, 1(%esi)	# /* is rep stosb */
	je Lcestosb
	cmpb $0xab, 1(%esi)	# /* is rep stosl */
	je Lcestosl
	cmpb $0xa4, 1(%esi)	# /* is rep movsb */
	je Lcemovsb
	jmp abort		# /* don't know */
Lcemovsl:			# /* cld rep movsl */
	movl $2, accmod		# /* destination: write */
	shll $2, %ecx		# /* convert nbr of dword to nbr of bytes */
	movl %ecx, size		# /* load the lenth */
	call Check_addr		# /* first check */
	movl Resi, %edi		# /* source is in Resi */
	movl $1, accmod		# /* one read the source */
	movl Recx, %ecx
	shll $2, %ecx
	movl %ecx, size
	call Check_addr
L30:	call restore_register
	ret
Lsemovsl:			# /* std rep movsl */
	movl $2, accmod
	shll $2, %ecx
	movl %ecx, size
	subl %ecx, %edi
	incl %edi
	call Check_addr
	movl Resi, %edi
	movl $1, accmod
	movl Recx, %ecx
	shll $2, %ecx
	subl %ecx, %edi
	incl %edi
	movl %ecx, size
	call Check_addr
	call restore_register
	ret
Lcemovsb:			# /* cld rep movsb */
	movl $2, accmod		# /* destination: write */
	movl %ecx, size		# /* load the lenth */
	call Check_addr		# /* first check */
	movl Resi, %edi		# /* source is in Resi */
	movl $1, accmod		# /* one read the source */
	movl Recx, %ecx
	movl %ecx, size
	call Check_addr
	call restore_register
	ret
Lsemovsb:			# /* std rep movsb */
	movl $2, accmod
	movl %ecx, size
	subl %ecx, %edi
	incl %edi
	call Check_addr
	movl $1, accmod
	movl Resi, %edi
	movl Recx, %ecx
	subl %ecx, %edi
	incl %edi
	movl %ecx, size
	call Check_addr
	call restore_register
	ret
Lcestosb:			# /* cld rep stosb */
	movl $2, accmod		# /* destination: write */
	movl %ecx, size		# /* load the lenth */
	call Check_addr		# /* first check */
	call restore_register
	ret
Lcestosl:
	movl $2, accmod		# /* destination: write */
	shll $2, %ecx		# /* covert nbr of dword to nbr of bytes */
	movl %ecx, size		# /* load the lenth */
	call Check_addr		# /* first check */
	call restore_register
	ret
Lcecmpsb:
	movl Resi, %esi		# /* secure */
	movl Recx, %ecx
	movl Redi, %edi
	repz			# /* execute the instruction */
	cmpsb
	subl Recx, %ecx		# /* Now, we known the size */
	negl %ecx		# /* In fact, we want Recx - %ecx */
	movl %ecx, size
	pushl $1		# /* accmod is read */
	pushl %ecx
	pushl Redi		# /* first operand */
	call _chkr_check_addr
	addl $12, %esp
	pushl $1
	pushl size
	pushl Resi		# /* second operand */
	call _chkr_check_addr
	addl $12, %esp
	call restore_register
	ret

/* entry point for lodsb, scasb, stosb instructions */
	.globl chkr_1_3_0_1_chkr
chkr_1_3_0_1_chkr:
	call save_register
	cmpb $0xac, (%esi)	# /* is lodsb */
	je Llodsb
	cmpb $0xae, (%esi)	# /* is scasb */
	je Lscasb
	cmpb $0xaa, (%esi)	# /* is stosb */
	je Lstosb
	cmpb $0xa4, (%esi)	# /* is movsb */
	je Lmovsb
	jmp abort		# /* don't know */
Llodsb:	movl $1, accmod		# /* source: read */
	movl $1, size		# /* load the lenth 1:char size */
	movl Resi, %edi
	call Check_addr		# /* first check */
	call restore_register
	ret
Lscasb:	movl $1, accmod		# /* source: read */
	movl $1, size		# /* load the lenth 1:char size */
	call Check_addr		# /* first check */
	call restore_register
	ret
Lstosb: movl $2, accmod		# /* source: write */
	movl $1, size		# /* byte */
	call Check_addr
	call restore_register
	ret
Lmovsb:	movl $2, accmod
	movl $1, size
	call Check_addr
	movl $1, accmod
	movl Resi, %edi
	call Check_addr
	call restore_register
	ret

/* entry point for movsw instructions */
	.globl chkr_2_3_0_2_chkr
chkr_2_3_0_2_chkr:
	call save_register
	cmpb $0xa5, 1(%esi)	# /* is movsw */
	je Lmovsw
	jmp abort		# /* don't know */
Lmovsw:	movl $1, accmod		# /* source: read */
	movl $2, size		# /* load the lenth 2:word size */
	movl Resi, %edi
	call Check_addr		# /* first check */
	movl $2, accmod		# /* destination: write */
	movl Redi, %edi
	call Check_addr
	call restore_register
	ret

/* entry point for int $0x80 (ie syscall entry). */
	.globl chkr_1_4_8_0_chkr
chkr_1_4_8_0_chkr:
	call save_register
	pushl $registers
	call _check_syscall	# /* really check */
	addl $4,%esp
	call restore_register
	ret

/* entry point for StOp. It is designed to be quick */
	.globl chkr_0_5_0_0_chkr
chkr_0_5_0_0_chkr:
	pushl %eax
	pushf
	movl %esp, %eax
	addl $0x0C, %eax	# /* %eax, %eip and flags*/
	movl %eax, _known_stack_limit
	cmpl %eax, _stack_bitmapped
	jge L40
	movl %eax, _stack_bitmapped	# /* adjust bitmap */
L40:	popf
	popl %eax
	ret

/* entry point for "ret". It is designed to be quick */
	.globl chkr_1_5_0_4_chkr
chkr_1_5_0_4_chkr:
	pushl %eax
	movl %esp, %eax
	addl $0x0c, %eax	# /* %eax and %eip^2 */
	movl %eax, _known_stack_limit
	popl %eax
	ret

/* entry point for "ret x". It is designed to be quick */
	.globl chkr_1_5_0_0_chkr
chkr_1_5_0_0_chkr:
	pushl %eax
	pushl %esi
	movl %esp, %esi
	movl 8(%esi), %esi	# /* %esi equals old %eip */
	movzwl 1(%esi), %eax	# /* %eax contains the disp */
	addl $0x0c, %eax	# /* %eax, %esi, and %eip^2 */
	addl %esp, %eax
	movl %eax, _known_stack_limit
	popl %esi
	popl %eax
	ret

/* entry point for pushl */
	.globl chkr_0_5_2_4_chkr
chkr_0_5_2_4_chkr:
	call save_register
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	subl $0x04, _known_stack_limit
	pushl $0x03	# /* right is read and write */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

/* entry point for pushl %ebp */
	.globl chkr_0_5_0_4_chkr
chkr_0_5_0_4_chkr:
	call save_register
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	subl $0x04, _known_stack_limit
	pushl $0x00	# /* right is none */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

/* entry point for popl */
	.globl chkr_0_5_1_4_chkr
chkr_0_5_1_4_chkr:
	call save_register
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	pushl $0x01	# /* right is read */
	pushl $0x04	# /* length is 4 (long) */
	pushl Resp	# /* addr is %esp */
	call _chkr_check_addr
	addl $12, %esp	# /* normalize the stack */
	addl $0x04, _known_stack_limit
	call restore_register
	ret

/* entry point for pushl (addr)*/
	.globl chkr_2_6_2_4_chkr
chkr_2_6_2_4_chkr:
	movl %eax, addr 	/* save addr */
	movl (%esp), %eax	/* load the old eip */
	xchgl 4(%esp), %eax	/* change the addr and the old eip */
	leal 4(%esp), %esp	/* adjust esp */
	call save_register
	pushl $1
	pushl $4
	pushl addr
	call _chkr_check_addr
	addl $12, %esp
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	subl $0x04, _known_stack_limit
	pushl $0x03	# /* right is read and write */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

/* entry point for pushl (addr)*/
	.globl chkr_1_5_2_4_chkr
chkr_1_5_2_4_chkr:
	call save_register
	pushl $1
	pushl $4
	pushl 1(%esi)
	call _chkr_check_addr	# /* check addr can be read */
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	subl $0x04, _known_stack_limit
	pushl $0x03	# /* right is read and write */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

/* entry point for popl (addr)*/
	.globl chkr_1_5_1_4_chkr
chkr_1_5_1_4_chkr:
	call save_register
	pushl $2
	pushl $4
	pushl 1(%esi)
	call _chkr_check_addr	# /* check addr can be written */
	addl $12, %esp
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	pushl $0x01	# /* right is read */
	pushl $0x04	# /* length is 4 (long) */
	pushl Resp	# /* addr is %esp */
	call _chkr_check_addr
	addl $12, %esp	# /* normalize the stack */
	addl $0x04, _known_stack_limit
	call restore_register
	ret

/* entry point for call addr
 * addr is an immediat. Just protects the stack.
 */
	.globl chkr_0_7_0_4_chkr
chkr_0_7_0_4_chkr:
	call save_register
#if 0
	movl Reip, %eax		# /* return address */
	pushl %eax
	pushl %ebp		# /* push the frame pointer */
	movl %esp, %ebp
	# /* don't forget the addl $??, %esp */
#endif
	subl $0x04, _known_stack_limit
	pushl $0x00	# /* right is none */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

/* for call xxx, where xxx is mod/rm
 * xxx is at first checked, and then the stack is protected: you can't read
 * the saved eip.
 */
	.globl chkr_1_7_1_4_chkr
chkr_1_7_1_4_chkr:
	movl %eax, addr		/* save the addr */ 
	movl (%esp), %eax	/* load the old eip */ 
	xchgl 4(%esp), %eax	/* save the old eip */ 
	leal 4(%esp), %esp	/* change %esp */ 
	call save_register
	pushl $1
	pushl $4
	pushl addr		/* test xxx */
	call _chkr_check_addr
	addl $12, %esp
	subl $0x04, _known_stack_limit
	pushl $0x00	# /* right is none */
	pushl $0x04	# /* length is 4 (long) */
	movl Resp, %eax
	subl $0x04, %eax
	pushl %eax	# /* addr is %esp - 4*/
	call _chkr_set_right
	addl $12, %esp	# /* normalize the stack */
	call restore_register
	ret

#else /* !CHKR_USE_BITMAP */
/* Makes ld happy */
dummy:
	.byte 0
#endif /* CHKR_USE_BITMAP */