fis-gtm/sr_unix/make_mode.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 */