nkeynes@539 | 1 | /**
|
nkeynes@586 | 2 | * $Id$
|
nkeynes@539 | 3 | *
|
nkeynes@926 | 4 | * Provides the implementation for the ia32 ABI variant
|
nkeynes@926 | 5 | * (eg prologue, epilogue, and calling conventions). Stack frame is
|
nkeynes@926 | 6 | * aligned on 16-byte boundaries for the benefit of OS X (which
|
nkeynes@926 | 7 | * requires it).
|
nkeynes@995 | 8 | *
|
nkeynes@995 | 9 | * Note: These should only be included from x86op.h
|
nkeynes@539 | 10 | *
|
nkeynes@539 | 11 | * Copyright (c) 2007 Nathan Keynes.
|
nkeynes@539 | 12 | *
|
nkeynes@539 | 13 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@539 | 14 | * it under the terms of the GNU General Public License as published by
|
nkeynes@539 | 15 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@539 | 16 | * (at your option) any later version.
|
nkeynes@539 | 17 | *
|
nkeynes@539 | 18 | * This program is distributed in the hope that it will be useful,
|
nkeynes@539 | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@539 | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@539 | 21 | * GNU General Public License for more details.
|
nkeynes@539 | 22 | */
|
nkeynes@539 | 23 |
|
nkeynes@995 | 24 | #define REG_ARG1 REG_EAX
|
nkeynes@995 | 25 | #define REG_ARG2 REG_EDX
|
nkeynes@995 | 26 | #define REG_RESULT1 REG_EAX
|
nkeynes@995 | 27 | #define MAX_REG_ARG 2
|
nkeynes@539 | 28 |
|
nkeynes@1004 | 29 | static inline void decode_address( uintptr_t base, int addr_reg )
|
nkeynes@953 | 30 | {
|
nkeynes@995 | 31 | MOVL_r32_r32( addr_reg, REG_ECX );
|
nkeynes@991 | 32 | SHRL_imm_r32( 12, REG_ECX );
|
nkeynes@991 | 33 | MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX );
|
nkeynes@953 | 34 | }
|
nkeynes@953 | 35 |
|
nkeynes@539 | 36 | /**
|
nkeynes@995 | 37 | * Note: clobbers ECX to make the indirect call - this isn't usually
|
nkeynes@995 | 38 | * a problem since the callee will generally clobber it anyway.
|
nkeynes@539 | 39 | */
|
nkeynes@995 | 40 | static inline void CALL_ptr( void *ptr )
|
nkeynes@539 | 41 | {
|
nkeynes@995 | 42 | MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX );
|
nkeynes@991 | 43 | CALL_r32(REG_ECX);
|
nkeynes@539 | 44 | }
|
nkeynes@539 | 45 |
|
nkeynes@905 | 46 | #ifdef HAVE_FASTCALL
|
nkeynes@995 | 47 | static inline void CALL1_ptr_r32( void *ptr, int arg1 )
|
nkeynes@905 | 48 | {
|
nkeynes@995 | 49 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 50 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@905 | 51 | }
|
nkeynes@995 | 52 | CALL_ptr(ptr);
|
nkeynes@953 | 53 | }
|
nkeynes@953 | 54 |
|
nkeynes@995 | 55 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
|
nkeynes@953 | 56 | {
|
nkeynes@995 | 57 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 58 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@953 | 59 | }
|
nkeynes@995 | 60 | CALL_r32disp(preg, disp);
|
nkeynes@953 | 61 | }
|
nkeynes@953 | 62 |
|
nkeynes@995 | 63 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
|
nkeynes@953 | 64 | {
|
nkeynes@995 | 65 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 66 | MOVL_r32_r32( arg2, REG_ARG2 );
|
nkeynes@953 | 67 | }
|
nkeynes@995 | 68 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 69 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@995 | 70 | }
|
nkeynes@995 | 71 | CALL_ptr(ptr);
|
nkeynes@953 | 72 | }
|
nkeynes@953 | 73 |
|
nkeynes@995 | 74 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
|
nkeynes@953 | 75 | {
|
nkeynes@995 | 76 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 77 | MOVL_r32_r32( arg2, REG_ARG2 );
|
nkeynes@953 | 78 | }
|
nkeynes@995 | 79 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 80 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@995 | 81 | }
|
nkeynes@995 | 82 | CALL_r32disp(preg, disp);
|
nkeynes@905 | 83 | }
|
nkeynes@905 | 84 |
|
nkeynes@995 | 85 | #define CALL3_r32disp_r32_r32_r32(preg,disp,arg1,arg2,arg3) CALL2_r32disp_r32_r32(preg,disp,arg1,arg2)
|
nkeynes@927 | 86 |
|
nkeynes@905 | 87 | #else
|
nkeynes@995 | 88 | static inline void CALL1_ptr( void *ptr, int arg1 )
|
nkeynes@539 | 89 | {
|
nkeynes@991 | 90 | SUBL_imms_r32( 12, REG_ESP );
|
nkeynes@539 | 91 | PUSH_r32(arg1);
|
nkeynes@995 | 92 | CALL_ptr(ptr);
|
nkeynes@991 | 93 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@539 | 94 | }
|
nkeynes@539 | 95 |
|
nkeynes@995 | 96 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
|
nkeynes@995 | 97 | {
|
nkeynes@995 | 98 | SUBL_imms_r32( 12, REG_ESP );
|
nkeynes@995 | 99 | PUSH_r32(arg1);
|
nkeynes@995 | 100 | CALL_r32disp(preg, disp);
|
nkeynes@995 | 101 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 102 | }
|
nkeynes@995 | 103 |
|
nkeynes@995 | 104 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
|
nkeynes@539 | 105 | {
|
nkeynes@991 | 106 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@539 | 107 | PUSH_r32(arg2);
|
nkeynes@539 | 108 | PUSH_r32(arg1);
|
nkeynes@995 | 109 | CALL_ptr(ptr);
|
nkeynes@995 | 110 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 111 | }
|
nkeynes@995 | 112 |
|
nkeynes@995 | 113 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
|
nkeynes@995 | 114 | {
|
nkeynes@995 | 115 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@995 | 116 | PUSH_r32(arg2);
|
nkeynes@995 | 117 | PUSH_r32(arg1);
|
nkeynes@995 | 118 | CALL_r32disp(preg, disp);
|
nkeynes@995 | 119 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 120 | }
|
nkeynes@995 | 121 |
|
nkeynes@995 | 122 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
|
nkeynes@995 | 123 | {
|
nkeynes@995 | 124 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@995 | 125 | PUSH_r32(arg2);
|
nkeynes@995 | 126 | PUSH_r32(arg1);
|
nkeynes@995 | 127 | MOVL_rspdisp_r32( 16, REG_EAX );
|
nkeynes@995 | 128 | MOVL_r32_rspdisp( R_EAX, 8 );
|
nkeynes@995 | 129 | CALL_r32disp(preg,disp);
|
nkeynes@991 | 130 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@539 | 131 | }
|
nkeynes@926 | 132 |
|
nkeynes@905 | 133 | #endif
|
nkeynes@539 | 134 |
|
nkeynes@539 | 135 | /**
|
nkeynes@539 | 136 | * Emit the 'start of block' assembly. Sets up the stack frame and save
|
nkeynes@539 | 137 | * SI/DI as required
|
nkeynes@926 | 138 | * Allocates 8 bytes for local variables, which also has the convenient
|
nkeynes@926 | 139 | * side-effect of aligning the stack.
|
nkeynes@539 | 140 | */
|
nkeynes@995 | 141 | static inline void enter_block( )
|
nkeynes@539 | 142 | {
|
nkeynes@991 | 143 | PUSH_r32(REG_EBP);
|
nkeynes@991 | 144 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@926 | 145 | }
|
nkeynes@736 | 146 |
|
nkeynes@926 | 147 | static inline void exit_block( )
|
nkeynes@926 | 148 | {
|
nkeynes@991 | 149 | ADDL_imms_r32( 8, REG_ESP );
|
nkeynes@991 | 150 | POP_r32(REG_EBP);
|
nkeynes@926 | 151 | RET();
|
nkeynes@539 | 152 | }
|