return p[0] == 0x07 && p[1] == (0xF0 | reg); /* BCR 15,reg */
}
-static __inline__ Bool
-s390_insn_is_BASR(const UChar *p, UChar link_reg, UChar other_reg)
-{
- return p[0] == 0x0D && p[1] == ((link_reg << 4) | other_reg);
-}
+
+/* The length of the BASR insn */
+#define S390_BASR_LEN 2
+
/* Load the 64-bit VALUE into REG. Note that this function must NOT
optimise the generated code by looking at the value. I.e. using
static UInt
s390_tchain_load64_len(void)
{
- return S390_TCHAIN_LOAD64_LEN;
+ return 4 + 4 + 4 + 4; /* IIHH + IIHL + IILH + IILL */
}
/* Verify that CODE is the code sequence generated by s390_tchain_load64
buf = s390_emit_STG(buf, R0, 0, b, DISP20(d));
- /* --- FIRST PATCHABLE BYTE follows --- */
- /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling
- to) backs up the return address, so as to find the address of
- the first patchable byte. So: don't change the length of the
- two instructions below. */
-
/* Load the chosen entry point into the scratch reg */
void *disp_cp_chain_me;
disp_cp_chain_me =
insn->variant.xdirect.to_fast_entry ? disp_cp_chain_me_to_fastEP
: disp_cp_chain_me_to_slowEP;
+ /* Get the address of the beginning of the load64 code sequence into %r1.
+ Do not change the register! This is part of the protocol with the
+ dispatcher. */
+ buf = s390_emit_BASR(buf, 1, R0);
+ /* --- FIRST PATCHABLE BYTE follows (must not modify %r1) --- */
ULong addr = Ptr_to_ULong(disp_cp_chain_me);
buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, addr);
- /* call *tchain_scratch */
- buf = s390_emit_BASR(buf, 1, S390_REGNO_TCHAIN_SCRATCH);
+ /* goto *tchain_scratch */
+ buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
/* --- END of PATCHABLE BYTES --- */
static UInt
s390_xdirect_patchable_len(void)
{
- return s390_tchain_load64_len() + S390_TCHAIN_CALL_LEN;
+ return s390_tchain_load64_len() + S390_BASR_LEN;
}
/* load tchain_scratch, #disp_indir */
buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH,
Ptr_to_ULong(disp_cp_xindir));
- /* BR *tchain_direct */
+ /* goto *tchain_direct */
buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
/* Fix up the conditional jump, if there was one. */
buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH,
Ptr_to_ULong(disp_cp_xassisted));
- /* BR *tchain_direct */
+ /* goto *tchain_direct */
buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
/* Fix up the conditional jump, if there was one. */
void *disp_cp_chain_me_EXPECTED,
void *place_to_jump_to)
{
- /* What we're expecting to see @ PLACE_TI_CHAIN is:
+ /* What we're expecting to see @ PLACE_TO_CHAIN is:
- load tchain-scratch, #disp_cp_chain_me_EXPECTED
- BASR 1,S390_REGNO_TCHAIN_SCRATCH
+ load tchain_scratch, #disp_cp_chain_me_EXPECTED
+ goto *tchain_scratch
*/
const UChar *next;
next = s390_tchain_verify_load64(place_to_chain, S390_REGNO_TCHAIN_SCRATCH,
Ptr_to_ULong(disp_cp_chain_me_EXPECTED));
- vassert(s390_insn_is_BASR(next, 1, S390_REGNO_TCHAIN_SCRATCH));
+ vassert(s390_insn_is_BR(next, S390_REGNO_TCHAIN_SCRATCH));
/* And what we want to change it to is either:
(general case):
- load tchain_scratch, #place_to_jump_to
- BR *tchain_scratch
+ load tchain_scratch, #place_to_jump_to
+ goto *tchain_scratch
---OR---
p[i] = 0x00;
} else {
/*
- load tchain_scratch, #place_to_jump_to
- BR *tchain_scratch
+ load tchain_scratch, #place_to_jump_to
+ goto *tchain_scratch
*/
ULong addr = Ptr_to_ULong(place_to_jump_to);
p = s390_tchain_load64(p, S390_REGNO_TCHAIN_SCRATCH, addr);
- s390_emit_BCR(p, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
+ /* There is not need to emit a BCR here, as it is already there. */
}
VexInvalRange vir = {0, 0};
{
/* What we're expecting to see @ PLACE_TO_UNCHAIN:
- load tchain_scratch, #place_to_jump_to_EXPECTED
- BR *tchain_scratch
+ load tchain_scratch, #place_to_jump_to_EXPECTED
+ goto *tchain_scratch
---OR---
in the case where the displacement falls within 32 bits
*/
UChar *p = place_to_unchain;
+ Bool uses_short_form = False;
+
if (s390_insn_is_BRCL(p, S390_CC_ALWAYS)) {
/* Looks like the short form */
Int num_hw = *(Int *)&p[2];
Int i;
for (i = 0; i < s390_xdirect_patchable_len() - 6; ++i)
vassert(p[6+i] == 0x00);
+ uses_short_form = True;
} else {
/* Should be the long form */
const UChar *next;
/* And what we want to change it to is:
load tchain_scratch, #disp_cp_chain_me
- call *tchain_scratch
+ goto *tchain_scratch
*/
+
+ /* Get the address of the beginning of the load64 code sequence into %r1.
+ Do not change the register! This is part of the protocol with the
+ dispatcher.
+ Note: the incoming argument PLACE_TO_CHAIN points to the beginning of the
+ load64 insn sequence. That sequence is prefixed with a BASR to get its
+ address (see s390_insn_xdirect_emit). */
+ p = s390_emit_BASR(p - S390_BASR_LEN, 1, R0);
+
ULong addr = Ptr_to_ULong(disp_cp_chain_me);
p = s390_tchain_load64(p, S390_REGNO_TCHAIN_SCRATCH, addr);
- s390_emit_BASR(p, 1, S390_REGNO_TCHAIN_SCRATCH);
+
+ /* Emit the BCR in case the short form was used. In case of the long
+ form, the BCR is already there. */
+ if (uses_short_form)
+ s390_emit_BCR(p, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
VexInvalRange vir = {0, 0};
return vir;