Search
lxdream.org :: lxdream/src/xlat/x86/ia32abi.h
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/x86/ia32abi.h
changeset 1292:799fdd4f704a
prev1146:76c5d1064262
author nkeynes
date Fri Aug 24 08:53:50 2012 +1000 (8 years ago)
permissions -rw-r--r--
last change Move the generated prologue/epilogue code out into a common entry stub
(reduces space requirements) and pre-save all saved registers. Change
FASTCALL to use 3 regs instead of 2 since we can now keep everything in
regs.
file annotate diff log raw
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@1292
    26
#define REG_ARG3 REG_ECX
nkeynes@995
    27
#define REG_RESULT1 REG_EAX
nkeynes@1292
    28
#define MAX_REG_ARG 3
nkeynes@1292
    29
#define REG_SAVE1 REG_ESI
nkeynes@1292
    30
#define REG_SAVE2 REG_EDI
nkeynes@1292
    31
#define REG_CALLPTR REG_EBX
nkeynes@539
    32
nkeynes@1292
    33
static inline void decode_address( uintptr_t base, int addr_reg, int target_reg )
nkeynes@953
    34
{
nkeynes@1292
    35
    MOVL_r32_r32( addr_reg, target_reg );
nkeynes@1292
    36
    SHRL_imm_r32( 12, target_reg );
nkeynes@1292
    37
    MOVP_sib_rptr( 2, target_reg, -1, base, target_reg );
nkeynes@953
    38
}
nkeynes@953
    39
nkeynes@539
    40
/**
nkeynes@995
    41
 * Note: clobbers ECX to make the indirect call - this isn't usually
nkeynes@995
    42
 * a problem since the callee will generally clobber it anyway.
nkeynes@539
    43
 */
nkeynes@995
    44
static inline void CALL_ptr( void *ptr )
nkeynes@539
    45
{
nkeynes@995
    46
    MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX );
nkeynes@991
    47
    CALL_r32(REG_ECX);
nkeynes@539
    48
}
nkeynes@539
    49
nkeynes@905
    50
#ifdef HAVE_FASTCALL
nkeynes@1146
    51
#define CALL1_PTR_MIN_SIZE 7
nkeynes@1146
    52
nkeynes@995
    53
static inline void CALL1_ptr_r32( void *ptr, int arg1 )
nkeynes@905
    54
{
nkeynes@995
    55
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    56
        MOVL_r32_r32( arg1, REG_ARG1 );
nkeynes@905
    57
    }
nkeynes@995
    58
    CALL_ptr(ptr);
nkeynes@953
    59
}
nkeynes@953
    60
nkeynes@995
    61
static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
nkeynes@953
    62
{
nkeynes@995
    63
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    64
        MOVL_r32_r32( arg1, REG_ARG1 );
nkeynes@953
    65
    }
nkeynes@995
    66
    CALL_r32disp(preg, disp);
nkeynes@953
    67
}
nkeynes@953
    68
nkeynes@995
    69
static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
nkeynes@953
    70
{
nkeynes@995
    71
    if( arg2 != REG_ARG2 ) {
nkeynes@995
    72
        MOVL_r32_r32( arg2, REG_ARG2 );
nkeynes@953
    73
    }
nkeynes@995
    74
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    75
        MOVL_r32_r32( arg1, REG_ARG1 );
nkeynes@995
    76
    }
nkeynes@995
    77
    CALL_ptr(ptr);
nkeynes@953
    78
}
nkeynes@953
    79
nkeynes@995
    80
static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
nkeynes@953
    81
{
nkeynes@995
    82
    if( arg2 != REG_ARG2 ) {
nkeynes@995
    83
        MOVL_r32_r32( arg2, REG_ARG2 );
nkeynes@953
    84
    }
nkeynes@995
    85
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    86
        MOVL_r32_r32( arg1, REG_ARG1 );
nkeynes@995
    87
    }
nkeynes@995
    88
    CALL_r32disp(preg, disp);
nkeynes@905
    89
}
nkeynes@905
    90
nkeynes@1292
    91
static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3)
nkeynes@1292
    92
{
nkeynes@1292
    93
    if( arg3 != REG_ARG3 ) {
nkeynes@1292
    94
        MOVL_r32_r32( arg3, REG_ARG3 );
nkeynes@1292
    95
    }
nkeynes@1292
    96
    if( arg2 != REG_ARG2 ) {
nkeynes@1292
    97
        MOVL_r32_r32( arg2, REG_ARG2 );
nkeynes@1292
    98
    }
nkeynes@1292
    99
    if( arg1 != REG_ARG1 ) {
nkeynes@1292
   100
        MOVL_r32_r32( arg1, REG_ARG1 );
nkeynes@1292
   101
    }
nkeynes@1292
   102
    CALL_r32disp(preg, disp);
nkeynes@1292
   103
}
nkeynes@927
   104
nkeynes@905
   105
#else
nkeynes@1146
   106
nkeynes@1146
   107
#define CALL1_PTR_MIN_SIZE (3+1+7+3)
nkeynes@1146
   108
nkeynes@1146
   109
static inline void CALL1_ptr_r32( void *ptr, int arg1 )
nkeynes@539
   110
{
nkeynes@991
   111
    SUBL_imms_r32( 12, REG_ESP );
nkeynes@539
   112
    PUSH_r32(arg1);
nkeynes@995
   113
    CALL_ptr(ptr);
nkeynes@991
   114
    ADDL_imms_r32( 16, REG_ESP );
nkeynes@539
   115
}
nkeynes@539
   116
nkeynes@995
   117
static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
nkeynes@995
   118
{
nkeynes@995
   119
    SUBL_imms_r32( 12, REG_ESP );
nkeynes@995
   120
    PUSH_r32(arg1);
nkeynes@995
   121
    CALL_r32disp(preg, disp);
nkeynes@995
   122
    ADDL_imms_r32( 16, REG_ESP );
nkeynes@995
   123
}
nkeynes@995
   124
nkeynes@995
   125
static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
nkeynes@539
   126
{
nkeynes@991
   127
    SUBL_imms_r32( 8, REG_ESP );
nkeynes@539
   128
    PUSH_r32(arg2);
nkeynes@539
   129
    PUSH_r32(arg1);
nkeynes@995
   130
    CALL_ptr(ptr);
nkeynes@995
   131
    ADDL_imms_r32( 16, REG_ESP );
nkeynes@995
   132
}
nkeynes@995
   133
nkeynes@995
   134
static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
nkeynes@995
   135
{
nkeynes@995
   136
    SUBL_imms_r32( 8, REG_ESP );
nkeynes@995
   137
    PUSH_r32(arg2);
nkeynes@995
   138
    PUSH_r32(arg1);
nkeynes@995
   139
    CALL_r32disp(preg, disp);
nkeynes@995
   140
    ADDL_imms_r32( 16, REG_ESP );
nkeynes@995
   141
}
nkeynes@995
   142
nkeynes@995
   143
static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
nkeynes@995
   144
{
nkeynes@995
   145
    SUBL_imms_r32( 8, REG_ESP );
nkeynes@995
   146
    PUSH_r32(arg2);
nkeynes@995
   147
    PUSH_r32(arg1);
nkeynes@995
   148
    MOVL_rspdisp_r32( 16, REG_EAX );
nkeynes@1146
   149
    MOVL_r32_rspdisp( REG_EAX, 8 );
nkeynes@995
   150
    CALL_r32disp(preg,disp);
nkeynes@991
   151
    ADDL_imms_r32( 16, REG_ESP );
nkeynes@539
   152
}
nkeynes@926
   153
nkeynes@905
   154
#endif
nkeynes@539
   155
nkeynes@1112
   156
#define PROLOGUE_SIZE 9
nkeynes@1112
   157
nkeynes@539
   158
/**
nkeynes@539
   159
 * Emit the 'start of block' assembly. Sets up the stack frame and save
nkeynes@539
   160
 * SI/DI as required
nkeynes@926
   161
 * Allocates 8 bytes for local variables, which also has the convenient
nkeynes@926
   162
 * side-effect of aligning the stack.
nkeynes@539
   163
 */
nkeynes@1125
   164
static inline void emit_prologue( )
nkeynes@539
   165
{
nkeynes@991
   166
    PUSH_r32(REG_EBP);
nkeynes@991
   167
    SUBL_imms_r32( 8, REG_ESP ); 
nkeynes@1112
   168
    MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
nkeynes@926
   169
}
nkeynes@736
   170
nkeynes@1125
   171
static inline void emit_epilogue( )
nkeynes@926
   172
{
nkeynes@991
   173
    ADDL_imms_r32( 8, REG_ESP );
nkeynes@991
   174
    POP_r32(REG_EBP);
nkeynes@539
   175
}
nkeynes@1125
   176
.