Search
lxdream.org :: lxdream/src/xlat/x86/amd64abi.h
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/x86/amd64abi.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@736
     4
 * Provides the implementation for the AMD64 ABI (eg prologue, epilogue, and
nkeynes@539
     5
 * calling conventions)
nkeynes@539
     6
 *
nkeynes@539
     7
 * Copyright (c) 2007 Nathan Keynes.
nkeynes@539
     8
 *
nkeynes@539
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@539
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@539
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@539
    12
 * (at your option) any later version.
nkeynes@539
    13
 *
nkeynes@539
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@539
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@539
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@539
    17
 * GNU General Public License for more details.
nkeynes@539
    18
 */
nkeynes@539
    19
nkeynes@995
    20
#define REG_ARG1 REG_RDI
nkeynes@995
    21
#define REG_ARG2 REG_RSI
nkeynes@995
    22
#define REG_ARG3 REG_RDX
nkeynes@995
    23
#define REG_RESULT1 REG_RAX
nkeynes@995
    24
#define MAX_REG_ARG 3  /* There's more, but we don't use more than 3 here anyway */
nkeynes@1292
    25
#define REG_SAVE1 REG_R12
nkeynes@1292
    26
#define REG_SAVE2 REG_R13
nkeynes@1292
    27
#define REG_SAVE3 REG_R14
nkeynes@1292
    28
#define REG_SAVE4 REG_R15
nkeynes@1292
    29
#define REG_CALLPTR REG_EBX
nkeynes@736
    30
nkeynes@1292
    31
static inline void decode_address( uintptr_t base, int addr_reg, int target_reg )
nkeynes@953
    32
{
nkeynes@1292
    33
    MOVL_r32_r32( addr_reg, target_reg );
nkeynes@1292
    34
    SHRL_imm_r32( 12, target_reg );
nkeynes@991
    35
    MOVP_immptr_rptr( base, REG_RDI );
nkeynes@1292
    36
    MOVP_sib_rptr( 3, target_reg, REG_RDI, 0, target_reg );
nkeynes@953
    37
}
nkeynes@953
    38
nkeynes@539
    39
/**
nkeynes@995
    40
 * Note: clobbers ECX to make the indirect call - this isn't usually
nkeynes@995
    41
 * a problem since the callee will generally clobber it anyway.
nkeynes@539
    42
 * Size: 12 bytes
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@995
    47
    CALL_r32(REG_ECX);
nkeynes@539
    48
}
nkeynes@539
    49
nkeynes@1146
    50
#define CALL1_PTR_MIN_SIZE 12
nkeynes@995
    51
static inline void CALL1_ptr_r32( void *ptr, int arg1 )
nkeynes@539
    52
{
nkeynes@995
    53
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    54
        MOVQ_r64_r64( arg1, REG_ARG1 );
nkeynes@995
    55
    }
nkeynes@995
    56
    CALL_ptr(ptr);
nkeynes@539
    57
}
nkeynes@539
    58
nkeynes@995
    59
static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
nkeynes@927
    60
{
nkeynes@995
    61
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    62
        MOVQ_r64_r64( arg1, REG_ARG1 );
nkeynes@995
    63
    }
nkeynes@995
    64
    CALL_r32disp(preg, disp);    
nkeynes@927
    65
}
nkeynes@927
    66
nkeynes@995
    67
static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
nkeynes@953
    68
{
nkeynes@995
    69
    if( arg2 != REG_ARG2 ) {
nkeynes@995
    70
        MOVQ_r64_r64( arg2, REG_ARG2 );
nkeynes@995
    71
    }
nkeynes@995
    72
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    73
        MOVQ_r64_r64( arg1, REG_ARG1 );
nkeynes@995
    74
    }
nkeynes@995
    75
    CALL_ptr(ptr);
nkeynes@953
    76
}
nkeynes@953
    77
nkeynes@995
    78
static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
nkeynes@953
    79
{
nkeynes@995
    80
    if( arg2 != REG_ARG2 ) {
nkeynes@995
    81
        MOVQ_r64_r64( arg2, REG_ARG2 );
nkeynes@995
    82
    }
nkeynes@995
    83
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    84
        MOVQ_r64_r64( arg1, REG_ARG1 );
nkeynes@995
    85
    }
nkeynes@995
    86
    CALL_r32disp(preg, disp);    
nkeynes@953
    87
}
nkeynes@953
    88
nkeynes@995
    89
static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
nkeynes@539
    90
{
nkeynes@995
    91
    if( arg3 != REG_ARG3 ) {
nkeynes@995
    92
        MOVQ_r64_r64( arg3, REG_ARG3 );
nkeynes@995
    93
    }
nkeynes@995
    94
    if( arg2 != REG_ARG2 ) {
nkeynes@995
    95
        MOVQ_r64_r64( arg2, REG_ARG2 );
nkeynes@995
    96
    }
nkeynes@995
    97
    if( arg1 != REG_ARG1 ) {
nkeynes@995
    98
        MOVQ_r64_r64( arg1, REG_ARG1 );
nkeynes@995
    99
    }
nkeynes@995
   100
    CALL_r32disp(preg, disp);    
nkeynes@539
   101
}
nkeynes@539
   102
nkeynes@1112
   103
#define PROLOGUE_SIZE 15
nkeynes@1112
   104
nkeynes@539
   105
/**
nkeynes@539
   106
 * Emit the 'start of block' assembly. Sets up the stack frame and save
nkeynes@539
   107
 * SI/DI as required
nkeynes@539
   108
 */
nkeynes@1125
   109
static inline void emit_prologue( )
nkeynes@539
   110
{
nkeynes@991
   111
    PUSH_r32(REG_RBP);
nkeynes@995
   112
    SUBQ_imms_r64( 16, REG_RSP ); 
nkeynes@1112
   113
    MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
nkeynes@926
   114
}
nkeynes@926
   115
nkeynes@1125
   116
static inline void emit_epilogue( )
nkeynes@926
   117
{
nkeynes@991
   118
    ADDQ_imms_r64( 16, REG_RSP );
nkeynes@991
   119
    POP_r32(REG_RBP);
nkeynes@539
   120
}
.