224 lines
6.7 KiB
C
224 lines
6.7 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2009 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
|
|
#include "error.h"
|
|
#include "dm_setup.h"
|
|
#include "rtnhdr.h"
|
|
#include "op.h"
|
|
#include "compiler.h"
|
|
#include "emit_code.h"
|
|
#include "gtmci.h"
|
|
#include "inst_flush.h"
|
|
#include "obj_file.h"
|
|
#include "gtm_text_alloc.h"
|
|
|
|
#ifdef USHBIN_SUPPORTED
|
|
/* From here down is only defined in a shared binary environment */
|
|
|
|
#include "make_mode.h"
|
|
|
|
#ifdef __ia64
|
|
|
|
#if defined(__linux__)
|
|
|
|
void dmode_table_init() __attribute__((constructor));
|
|
|
|
#else /* __hpux */
|
|
|
|
#pragma INIT "dmode_table_init"
|
|
|
|
#endif /* __linux__ */
|
|
|
|
void dmode_table_init(void);
|
|
|
|
#endif /* __ia64 */
|
|
|
|
/* This routine is called to create (currently two different) dynamic routines that
|
|
can be executed. One is a direct mode frame, the other is a callin base frame. They
|
|
are basically identical except in the entry points that they call. To this end, this
|
|
common routine is called for both with the entry points to be put into the generated
|
|
code being passed in as parameters.
|
|
*/
|
|
|
|
typedef struct dyn_modes_struct
|
|
{
|
|
char *rtn_name;
|
|
int rtn_name_len;
|
|
void (*func_ptr1)(void);
|
|
void (*func_ptr2)(void);
|
|
int (*func_ptr3)(void);
|
|
} dyn_modes;
|
|
|
|
static dyn_modes our_modes[2] =
|
|
{
|
|
{
|
|
GTM_DMOD,
|
|
SIZEOF(GTM_DMOD) - 1,
|
|
dm_setup,
|
|
mum_tstart,
|
|
opp_ret
|
|
},
|
|
{
|
|
GTM_CIMOD,
|
|
SIZEOF(GTM_CIMOD) - 1,
|
|
ci_restart,
|
|
ci_ret_code,
|
|
opp_ret
|
|
}
|
|
};
|
|
|
|
#if defined(__ia64)
|
|
|
|
/* On IA64, we want to use CODE_ADDRESS() macro, to dereference all the function pointers, before storing them in
|
|
global array. Now doing a dereference operation, as part of initialization, is not allowed by linux/gcc (HP'a aCC
|
|
was more tolerant towards this). So to make sure that the xfer_table is initialized correctly, before anyone
|
|
uses it, one needs to create a 'constructor/initializer' function, which is gauranted to be called as soon as
|
|
this module is loaded, and initialize the xfer_table correctly within that function. gcc provides the below
|
|
mechanism to do this
|
|
*/
|
|
|
|
static char dyn_modes_type[2][3] = {
|
|
{'C','A','A'},
|
|
{'A','C','A'}
|
|
};
|
|
|
|
void dmode_table_init()
|
|
{
|
|
/*
|
|
our_modes[0].func_ptr1 = (void (*)())CODE_ADDRESS(our_modes[0].func_ptr1);
|
|
our_modes[0].func_ptr2 = (void (*)())CODE_ADDRESS(our_modes[0].func_ptr2);
|
|
our_modes[0].func_ptr3 = (int (*)())CODE_ADDRESS(our_modes[0].func_ptr3);
|
|
|
|
our_modes[1].func_ptr1 = (void (*)())CODE_ADDRESS(our_modes[1].func_ptr1);
|
|
our_modes[1].func_ptr2 = (void (*)())CODE_ADDRESS(our_modes[1].func_ptr2);
|
|
our_modes[1].func_ptr3 = (int (*)())CODE_ADDRESS(our_modes[1].func_ptr3);
|
|
*/
|
|
}
|
|
|
|
#endif /* __ia64 */
|
|
|
|
rhdtyp *make_mode (int mode_index)
|
|
{
|
|
rhdtyp *base_address;
|
|
lab_tabent *lbl;
|
|
lnr_tabent *lnr;
|
|
CODEBUF_TYPE *code;
|
|
dyn_modes *dmode;
|
|
int algnd_rtnhdr_size = (int)ROUND_UP2(SIZEOF(rhdtyp), SECTION_ALIGN_BOUNDARY);
|
|
int algnd_code_size = (int)ROUND_UP2(CODE_SIZE, NATIVE_WSIZE);
|
|
int algnd_lbltab_size = (int)ROUND_UP2(SIZEOF(lab_tabent), NATIVE_WSIZE);
|
|
int algnd_lnrtab_size = (int)ROUND_UP2(CODE_LINES * SIZEOF(lnr_tabent), NATIVE_WSIZE);
|
|
|
|
assert(DM_MODE == mode_index || CI_MODE == mode_index);
|
|
base_address = (rhdtyp *)GTM_TEXT_ALLOC(algnd_rtnhdr_size + algnd_code_size + algnd_lbltab_size + algnd_lnrtab_size);
|
|
memset(base_address, 0, algnd_rtnhdr_size + algnd_code_size + algnd_lbltab_size + algnd_lnrtab_size);
|
|
dmode = &our_modes[mode_index];
|
|
base_address->routine_name.len = dmode->rtn_name_len;
|
|
base_address->routine_name.addr = dmode->rtn_name;
|
|
|
|
base_address->ptext_adr = (unsigned char *)base_address + algnd_rtnhdr_size;
|
|
base_address->ptext_end_adr = (unsigned char *)base_address->ptext_adr + algnd_code_size;
|
|
|
|
base_address->lnrtab_adr = (lnr_tabent *)base_address->ptext_end_adr;
|
|
|
|
base_address->labtab_adr = (lab_tabent *)((unsigned char *)base_address + algnd_rtnhdr_size +
|
|
algnd_code_size + algnd_lnrtab_size);
|
|
|
|
base_address->lnrtab_len = CODE_LINES;
|
|
base_address->labtab_len = 1;
|
|
|
|
code = (CODEBUF_TYPE *)base_address->ptext_adr; /* start of executable code */
|
|
#ifdef __ia64
|
|
if (dyn_modes_type[mode_index][0] == 'C')
|
|
{
|
|
GEN_CALL_C(CODE_ADDRESS(dmode->func_ptr1)) /* line 0,1 */
|
|
} else
|
|
{
|
|
GEN_CALL_ASM(CODE_ADDRESS(dmode->func_ptr1)) /* line 0,1 */
|
|
}
|
|
#else
|
|
GEN_CALL(dmode->func_ptr1); /* line 0,1 */
|
|
#endif /* __ia64 */
|
|
|
|
#ifdef _AIX
|
|
if (CI_MODE == mode_index)
|
|
{
|
|
/* Following 2 instructions are generated to call the routine stored in GTM_REG_ACCUM.
|
|
* ci_restart would have loaded this register with the address of op_extcall/op_extexfun.
|
|
* On other platforms, ci_start usually invokes op_ext* which will return directly
|
|
* to the generated code. Since RS6000 doesn't support call instruction without altering
|
|
* return address register (LR), the workaround is to call op_ext* not from ci_restart
|
|
* but from this dummy code */
|
|
*code++ = RS6000_INS_MTLR | GTM_REG_ACCUM << RS6000_SHIFT_RS;
|
|
*code++ = RS6000_INS_BRL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __ia64
|
|
if (dyn_modes_type[mode_index][1] == 'C')
|
|
{
|
|
GEN_CALL_C(CODE_ADDRESS(dmode->func_ptr2))
|
|
} else
|
|
{
|
|
GEN_CALL_ASM(CODE_ADDRESS(dmode->func_ptr2))
|
|
}
|
|
#else
|
|
GEN_CALL(dmode->func_ptr2);
|
|
#endif /* __ia64 */
|
|
|
|
#if defined (__ia64)
|
|
if (DM_MODE == mode_index)
|
|
{
|
|
GEN_UNCOD_JUMP(-(2 * 5)); /* branch to dm_setup which is at the top of the direct mode frame. */
|
|
}
|
|
#elif defined(__hpux)
|
|
if (DM_MODE == mode_index)
|
|
{
|
|
*code++ = HPPA_INS_BEQ | (MAKE_COND_BRANCH_TARGET(-8) << HPPA_SHIFT_OFFSET); /* BEQ r0,r0, -8 */
|
|
*code++ = HPPA_INS_NOP;
|
|
}
|
|
#endif /* __ia64 */
|
|
|
|
#ifdef __ia64
|
|
if (dyn_modes_type[mode_index][2] == 'C')
|
|
{
|
|
GEN_CALL_C(CODE_ADDRESS(dmode->func_ptr3)); /* line 2 */
|
|
} else
|
|
{
|
|
GEN_CALL_ASM(CODE_ADDRESS(dmode->func_ptr3)); /* line 2 */
|
|
}
|
|
#else
|
|
GEN_CALL(dmode->func_ptr3); /* line 2 */
|
|
#endif /* __ia64 */
|
|
|
|
lnr = LNRTAB_ADR(base_address);
|
|
*lnr++ = 0; /* line 0 */
|
|
*lnr++ = 0; /* line 1 */
|
|
IA64_ONLY(*lnr++ = 2 * CALL_SIZE + EXTRA_INST_SIZE;) /* line 2 */
|
|
NON_IA64_ONLY(*lnr++ = 2 * CALL_SIZE + EXTRA_INST * SIZEOF(int);) /* line 2 */
|
|
|
|
lbl = base_address->labtab_adr;
|
|
lbl->lnr_adr = base_address->lnrtab_adr;
|
|
|
|
base_address->current_rhead_adr = base_address;
|
|
zlput_rname(base_address);
|
|
|
|
inst_flush(base_address, algnd_rtnhdr_size + algnd_code_size + algnd_lbltab_size + algnd_lnrtab_size);
|
|
|
|
return base_address;
|
|
}
|
|
|
|
#endif /* USHBIN_SUPPORTED */
|