Skip to content

Commit

Permalink
i#3544 RV64: Rebase the dcontext pointer. (#7235)
Browse files Browse the repository at this point in the history
For RISC-V the dcontext_t struct is larger than the biggest valid
displacement of the load and store instructions.

By rebasing the pointer kept in spill_state_t's TLS slot by 0x800, we
can access the entire struct, because the displacement can be in the
range of -0x800 to 0x7ff. Architectures other than RV64 are unaffected
by these changes.

Issue: #3544
  • Loading branch information
mariospaok4 authored Feb 21, 2025
1 parent e7b57f6 commit cc7830f
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 44 deletions.
30 changes: 30 additions & 0 deletions core/arch/arch_exports.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* **********************************************************
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* Copyright (c) 2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -165,6 +166,10 @@ typedef struct _spill_state_t {
reg_t reg_stolen;
#endif
/* XXX: move this below the tables to fit more on cache line */
/* In RISCV64 dcontext does not poiont to the actual dcontext. It points somewhere
* in the middle of that. This value is the actual pointer offseted by
* DCONTEXT_TLS_MIDPTR_OFFSET.
*/
dcontext_t *dcontext;
#if defined(RISCV64) || defined(AARCHXX)
/* We store addresses here so we can load pointer-sized addresses into
Expand Down Expand Up @@ -1819,4 +1824,29 @@ typedef struct _rseq_entry_state_t {
} rseq_entry_state_t;
#endif

/*
* In riscv we cannot address the entire dcontext by using base + immediate.
* For the reason we add 0x800 to the saved pointer and access it by
* substracting 0x800 from the offset in the struct.
*/
#ifdef RISCV64
# define DCONTEXT_TLS_MIDPTR_OFFSET 0x800
#else
# define DCONTEXT_TLS_MIDPTR_OFFSET 0
#endif

#if (DCONTEXT_TLS_MIDPTR_OFFSET != 0)
# define DCONTEXT_ACTUAL_TO_TLS_PTR(x) \
((dcontext_t *)(((ptr_uint_t)x) + DCONTEXT_TLS_MIDPTR_OFFSET))
# define DCONTEXT_TLS_TO_ACTUAL_PTR(x) \
((dcontext_t *)(((ptr_uint_t)x) - DCONTEXT_TLS_MIDPTR_OFFSET))
# define DCONTEXT_ACTUAL_TO_TLS_OFFSET(x) (x - DCONTEXT_TLS_MIDPTR_OFFSET)
# define DCONTEXT_TLS_TO_ACTUAL_OFFSET(x) (x + DCONTEXT_TLS_MIDPTR_OFFSET)
#else
# define DCONTEXT_ACTUAL_TO_TLS_PTR(x) x
# define DCONTEXT_TLS_TO_ACTUAL_PTR(x) x
# define DCONTEXT_ACTUAL_TO_TLS_OFFSET(x) x
# define DCONTEXT_TLS_TO_ACTUAL_OFFSET(x) x
#endif

#endif /* _ARCH_EXPORTS_H_ */
35 changes: 31 additions & 4 deletions core/arch/emit_utils_shared.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* **********************************************************
* Copyright (c) 2010-2022 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* Copyright (c) 2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -2180,12 +2181,16 @@ emit_fcache_enter_common(dcontext_t *dcontext, generated_code_t *code, byte *pc,
#elif defined(RISCV64)
APP(&ilist,
INSTR_CREATE_ld(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_base_disp(REG_DCXT, DR_REG_NULL, 0,
REG_OFFSET(DR_REG_A0), OPSZ_8)));
opnd_create_base_disp(
REG_DCXT, DR_REG_NULL, 0,
DCONTEXT_ACTUAL_TO_TLS_OFFSET((int)REG_OFFSET(DR_REG_A0)),
OPSZ_8)));
APP(&ilist,
INSTR_CREATE_ld(dcontext, opnd_create_reg(DR_REG_A1),
opnd_create_base_disp(REG_DCXT, DR_REG_NULL, 0,
REG_OFFSET(DR_REG_A1), OPSZ_8)));
opnd_create_base_disp(
REG_DCXT, DR_REG_NULL, 0,
DCONTEXT_ACTUAL_TO_TLS_OFFSET((int)REG_OFFSET(DR_REG_A1)),
OPSZ_8)));

APP(&ilist,
INSTR_CREATE_sd(
Expand Down Expand Up @@ -2380,9 +2385,31 @@ append_call_dispatch(dcontext_t *dcontext, instrlist_t *ilist, bool absolute)
/* call central d_r_dispatch routine */
/* for x64 linux we could optimize and avoid the "mov rdi, rdi" */
/* for ARM we use _noreturn to avoid storing to %lr */

/*
* REG_DCTXT holds the rebased dcontext d_r_dispatch expects the normal one
* so we should restore it.
*
* Currently only affects RISCV64
*/
#if (DCONTEXT_TLS_MIDPTR_OFFSET != 0)
if (absolute) {
dr_insert_call_noreturn((void *)dcontext, ilist, NULL /*append*/,
(void *)d_r_dispatch, 1,
OPND_CREATE_INTPTR((ptr_int_t)dcontext));
} else {
APP(ilist,
XINST_CREATE_add_2src(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_reg(REG_DCTXT),
OPND_CREATE_INT32(-DCONTEXT_TLS_MIDPTR_OFFSET)));
dr_insert_call_noreturn((void *)dcontext, ilist, NULL /*append*/,
(void *)d_r_dispatch, 1, opnd_create_reg(DR_REG_A0));
}
#else
dr_insert_call_noreturn(
(void *)dcontext, ilist, NULL /*append*/, (void *)d_r_dispatch, 1,
absolute ? OPND_CREATE_INTPTR((ptr_int_t)dcontext) : opnd_create_reg(REG_DCTXT));
#endif

/* d_r_dispatch() shouldn't return! */
insert_reachable_cti(dcontext, ilist, NULL, vmcode_get_start(),
Expand Down
28 changes: 20 additions & 8 deletions core/arch/mangle_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2010-2022 Google, Inc. All rights reserved.
* Copyright (c) 2010 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* Copyright (c) 2025 Foundation of Research and Technology, Hellas.
* ******************************************************************************/

/*
Expand Down Expand Up @@ -81,6 +82,12 @@ get_clean_call_temp_stack_size(void)
/* utility routines for inserting clean calls to an instrumentation routine
* strategy is very similar to fcache_enter/return
* FIXME: try to share code with fcache_enter/return?
* TODO i#3544: Return the correct mcontext base when DCONTEXT_TLS_MIDPTR_OFFSET is used.
* This will need calls like opnd_create_dcontext_field_via_reg_sz to be replaced
* with something else. Currently we work around that by assuming that we have the
* dcontext pointer (offseted) instead of the mcontext when DCONTEXT_TLS_MIDPTR_OFFSET is
* not zero. For that reason we substract DCONTEXT_TLS_MIDPTR_OFFSET in the offsets
* created at emit_fcache_enter_common().
*
* first swap stacks to DynamoRIO stack:
* SAVE_TO_UPCONTEXT %xsp,xsp_OFFSET
Expand Down Expand Up @@ -757,8 +764,9 @@ insert_meta_call_vargs(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
* We save it to dcontext.mcontext.x0.
*/
PRE(ilist, instr,
XINST_CREATE_store(dcontext, OPND_CREATE_MEMPTR(link_reg, 0),
opnd_create_reg(SCRATCH_REG0)));
XINST_CREATE_store(
dcontext, OPND_CREATE_MEMPTR(link_reg, -DCONTEXT_TLS_MIDPTR_OFFSET),
opnd_create_reg(SCRATCH_REG0)));
instrlist_insert_mov_immed_ptrsz(dcontext, (ptr_int_t)DR_WHERE_CLEAN_CALLEE,
opnd_create_reg(SCRATCH_REG0), ilist, instr,
NULL, NULL);
Expand All @@ -769,8 +777,9 @@ insert_meta_call_vargs(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
WHEREAMI_OFFSET));
/* Restore scratch_reg from dcontext.mcontext.x0. */
PRE(ilist, instr,
XINST_CREATE_load(dcontext, opnd_create_reg(SCRATCH_REG0),
OPND_CREATE_MEMPTR(link_reg, 0)));
XINST_CREATE_load(
dcontext, opnd_create_reg(SCRATCH_REG0),
OPND_CREATE_MEMPTR(link_reg, -DCONTEXT_TLS_MIDPTR_OFFSET)));
#else
/* SCRATCH_REG0 is dead here, because clean calls only support "cdecl",
* which specifies that the caller must save xax (and xcx and xdx).
Expand Down Expand Up @@ -823,8 +832,10 @@ insert_meta_call_vargs(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
* We save it to dcontext.mcontext.x0.
*/
PRE(ilist, instr,
XINST_CREATE_store(dcontext, OPND_CREATE_MEMPTR(SCRATCH_REG0, 0),
opnd_create_reg(SCRATCH_REG1)));
XINST_CREATE_store(
dcontext,
OPND_CREATE_MEMPTR(SCRATCH_REG0, -DCONTEXT_TLS_MIDPTR_OFFSET),
opnd_create_reg(SCRATCH_REG1)));
instrlist_insert_mov_immed_ptrsz(dcontext, (ptr_int_t)whereami,
opnd_create_reg(SCRATCH_REG1), ilist, instr,
NULL, NULL);
Expand All @@ -835,8 +846,9 @@ insert_meta_call_vargs(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
WHEREAMI_OFFSET));
/* Restore scratch_reg from dcontext.mcontext.x0. */
PRE(ilist, instr,
XINST_CREATE_load(dcontext, opnd_create_reg(SCRATCH_REG1),
OPND_CREATE_MEMPTR(SCRATCH_REG0, 0)));
XINST_CREATE_load(
dcontext, opnd_create_reg(SCRATCH_REG1),
OPND_CREATE_MEMPTR(SCRATCH_REG0, -DCONTEXT_TLS_MIDPTR_OFFSET)));
#else
PRE(ilist, instr,
instr_create_save_immed_to_dc_via_reg(dcontext, SCRATCH_REG0,
Expand Down
28 changes: 15 additions & 13 deletions core/arch/riscv64/emit_utils.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* **********************************************************
* Copyright (c) 2022 Rivos, Inc. All rights reserved.
* Copyright (c) 2024 Foundation of Research and Technology, Hellas.
* Copyright (c) 2024-2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -691,19 +691,20 @@ append_restore_simd_reg(dcontext_t *dcontext, instrlist_t *ilist, bool absolute)
}

if (proc_has_feature(FEATURE_VECTOR)) {
APP(ilist,
INSTR_CREATE_addi(
dcontext, opnd_create_reg(DR_REG_A1), opnd_create_reg(REG_DCXT),
opnd_create_immed_int(
DCONTEXT_ACTUAL_TO_TLS_OFFSET(VREG_OFFSET(DR_REG_VR0)), OPSZ_12b)));
memopnd = opnd_create_base_disp(DR_REG_A1, REG_NULL, 0, 0,
reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
/* ma: mask agnostic
* ta: tail agnostic
* sew: selected element width
* lmul: vector register group multiplier
*
* ma ta sew=8 lmul=8 */
vtypei = (0b1 << 7) | (0b1 << 6) | (0b000 << 3) | 0b011;
memopnd = opnd_create_dcontext_field_via_reg_sz(
dcontext, DR_REG_A1, 0, reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
APP(ilist,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A1),
opnd_create_reg(REG_DCXT),
opnd_create_immed_int(VREG_OFFSET(DR_REG_VR0), OPSZ_12b)));
/* For the following vector instructions, set the element width to 8b, and use 8
* registers as a group (lmul=8).
*/
Expand Down Expand Up @@ -828,19 +829,20 @@ append_save_simd_reg(dcontext_t *dcontext, instrlist_t *ilist, bool absolute)
}

if (proc_has_feature(FEATURE_VECTOR)) {
APP(ilist,
INSTR_CREATE_addi(
dcontext, opnd_create_reg(DR_REG_A1), opnd_create_reg(REG_DCXT),
opnd_create_immed_int(
DCONTEXT_ACTUAL_TO_TLS_OFFSET(VREG_OFFSET(DR_REG_VR0)), OPSZ_12b)));
memopnd = opnd_create_base_disp(DR_REG_A1, REG_NULL, 0, 0,
reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
/* ma: mask agnostic
* ta: tail agnostic
* sew: selected element width
* lmul: vector register group multiplier
*
* ma ta sew=8 lmul=8 */
vtypei = (0b1 << 7) | (0b1 << 6) | (0b000 << 3) | 0b011;
memopnd = opnd_create_dcontext_field_via_reg_sz(
dcontext, DR_REG_A1, 0, reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
APP(ilist,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A1),
opnd_create_reg(REG_DCXT),
opnd_create_immed_int(VREG_OFFSET(DR_REG_VR0), OPSZ_12b)));
/* For the following vector instructions, set the element width to 8b, and use 8
* registers as a group (lmul=8).
*/
Expand Down
26 changes: 13 additions & 13 deletions core/arch/riscv64/mangle.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* **********************************************************
* Copyright (c) 2022 Rivos, Inc. All rights reserved.
* Copyright (c) 2024 Foundation of Research and Technology, Hellas.
* Copyright (c) 2024-2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -223,19 +223,19 @@ insert_push_all_registers(dcontext_t *dcontext, clean_call_info_t *cci,

/* Push vector registers. */
if (proc_has_feature(FEATURE_VECTOR)) {
PRE(ilist, instr,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_SP),
opnd_create_immed_int(dstack_offs, OPSZ_12b)));
memopnd = opnd_create_base_disp(DR_REG_A0, REG_NULL, 0, 0,
reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
/* ma: mask agnostic
* ta: tail agnostic
* sew: selected element width
* lmul: vector register group multiplier
*
* ma ta sew=8 lmul=8 */
vtypei = (0b1 << 7) | (0b1 << 6) | (0b000 << 3) | 0b011;
memopnd = opnd_create_dcontext_field_via_reg_sz(
dcontext, DR_REG_A0, 0, reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
PRE(ilist, instr,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_SP),
opnd_create_immed_int(dstack_offs, OPSZ_12b)));
/* For the following vector instructions, set the element width to 8b, and use 8
* registers as a group (lmul=8).
*/
Expand Down Expand Up @@ -294,19 +294,19 @@ insert_pop_all_registers(dcontext_t *dcontext, clean_call_info_t *cci, instrlist
/* Pop vector registers. */
current_offs -= proc_num_simd_registers() * sizeof(dr_simd_t);
if (proc_has_feature(FEATURE_VECTOR)) {
PRE(ilist, instr,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_SP),
opnd_create_immed_int(current_offs, OPSZ_12b)));
memopnd = opnd_create_base_disp(DR_REG_A0, REG_NULL, 0, 0,
reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
/* ma: mask agnostic
* ta: tail agnostic
* sew: selected element width
* lmul: vector register group multiplier
*
* ma ta sew=8 lmul=8 */
vtypei = (0b1 << 7) | (0b1 << 6) | (0b000 << 3) | 0b011;
memopnd = opnd_create_dcontext_field_via_reg_sz(
dcontext, DR_REG_A0, 0, reg_get_size_lmul(DR_REG_VR0, RV64_LMUL_8));
PRE(ilist, instr,
INSTR_CREATE_addi(dcontext, opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_SP),
opnd_create_immed_int(current_offs, OPSZ_12b)));
/* For the following vector instructions, set the element width to 8b, and use 8
* registers as a group (lmul=8).
*/
Expand Down
4 changes: 3 additions & 1 deletion core/dispatch.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* **********************************************************
* Copyright (c) 2011-2023 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* Copyright (c) 2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -569,7 +570,8 @@ enter_fcache(dcontext_t *dcontext, fcache_enter_func_t entry, cache_pc pc)
* paths were missed?
*/
PTHREAD_JIT_READ();
(*entry)(dcontext);

(*entry)(DCONTEXT_ACTUAL_TO_TLS_PTR(dcontext));
IF_WINDOWS(ASSERT_NOT_REACHED()); /* returns for signals on unix */
}

Expand Down
10 changes: 7 additions & 3 deletions core/ir/opnd_shared.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* **********************************************************
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* Copyright (c) 2025 Foundation of Research and Technology, Hellas.
* **********************************************************/

/*
Expand Down Expand Up @@ -2898,14 +2899,16 @@ dcontext_opnd_common(dcontext_t *dcontext, bool absolute, reg_id_t basereg, int
absolute ? REG_NULL : (basereg == REG_NULL ? REG_DCXT_PROT : basereg),
REG_NULL, 0,
((int)(ptr_int_t)(absolute ? dcontext->upcontext.separate_upcontext : 0)) +
offs,
DCONTEXT_ACTUAL_TO_TLS_OFFSET(offs),
size);
} else {
if (offs >= sizeof(unprotected_context_t))
offs -= sizeof(unprotected_context_t);
return opnd_create_base_disp(
absolute ? REG_NULL : (basereg == REG_NULL ? REG_DCXT : basereg), REG_NULL, 0,
((int)(ptr_int_t)(absolute ? dcontext : 0)) + offs, size);
((int)(ptr_int_t)(absolute ? dcontext : 0)) +
DCONTEXT_ACTUAL_TO_TLS_OFFSET(offs),
size);
}
}

Expand Down Expand Up @@ -2950,7 +2953,8 @@ update_dcontext_address(opnd_t op, dcontext_t *old_dcontext, dcontext_t *new_dco
opnd_get_index(op) == REG_NULL,
"update_dcontext_address: invalid opnd");
IF_X64(ASSERT_NOT_IMPLEMENTED(false));
offs = opnd_get_disp(op) - (uint)(ptr_uint_t)old_dcontext;
offs =
opnd_get_disp(op) - (uint)(ptr_uint_t)old_dcontext + DCONTEXT_TLS_MIDPTR_OFFSET;
if (offs >= 0 && offs < sizeof(dcontext_t)) {
/* don't pass raw offset, add in upcontext size */
offs += sizeof(unprotected_context_t);
Expand Down
Loading

0 comments on commit cc7830f

Please sign in to comment.