diff --git a/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.c b/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.c
index f5903c27cebde17678869f611dc67b077a86ea81..9ef9071f298c9d468daabf7d1648fa5ed6093f0b 100644
--- a/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.c
+++ b/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.c
@@ -36,31 +36,38 @@ int eacsl_runtime_sound_verdict = 1;
 
 #ifndef E_ACSL_EXTERNAL_ASSERT
 /*! \brief Default implementation of E-ACSL runtime assertions */
-void eacsl_runtime_assert(int predicate, int blocking, const char *kind,
-                          const char *fct, const char *pred_txt,
-                          const char *file, int line) {
+void eacsl_runtime_assert(int predicate, eacsl_assert_data_t *data) {
   if (eacsl_runtime_sound_verdict) {
     if (!predicate) {
+      // clang-format off
       STDERR("%s: In function '%s'\n"
              "%s:%d: Error: %s failed:\n"
              "\tThe failing predicate is:\n"
              "\t%s.\n",
-             file, fct, file, line, kind, pred_txt);
-      if (blocking) {
+             data->file, data->fct,
+             data->file, data->line, data->kind,
+             data->pred_txt);
+      // clang-format on
+      if (data->blocking) {
 #  ifndef E_ACSL_NO_ASSERT_FAIL /* Do fail on assertions */
 #    ifdef E_ACSL_FAIL_EXITCODE /* Fail by exit with a given code */
         exit(E_ACSL_FAIL_EXITCODE);
 #    else
-        raise_abort(file, line); /* Raise abort signal */
+        raise_abort(data->file, data->line); /* Raise abort signal */
 #    endif
 #  endif
       }
     }
-  } else
+  } else {
+    // clang-format off
     STDERR("%s: In function '%s'\n"
            "%s:%d: Warning: no sound verdict for %s (guess: %s).\n"
            "\tthe considered predicate is:\n"
            "\t%s\n",
-           file, fct, file, line, kind, predicate ? "ok" : "FAIL", pred_txt);
+           data->file, data->fct,
+           data->file, data->line, data->kind, predicate ? "ok" : "FAIL",
+           data->pred_txt);
+    // clang-format on
+  }
 }
 #endif
diff --git a/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.h b/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.h
index 5a7dec8c2e9af58f59269a73abcc152cbddad4c3..b3ec636c80334f5e99908cb39109b585bdc50d3f 100644
--- a/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.h
+++ b/src/plugins/e-acsl/share/e-acsl/instrumentation_model/e_acsl_assert.h
@@ -31,6 +31,7 @@
 #include "../internals/e_acsl_alias.h"
 
 #define eacsl_runtime_sound_verdict export_alias(sound_verdict)
+#define eacsl_assert_data_t         export_alias(assert_data_t)
 #define eacsl_runtime_assert        export_alias(assert)
 
 /*! E-ACSL instrumentation automatically sets this global to 0 if its verdict
@@ -39,26 +40,38 @@
     For arithmetic properties, the verdict is always sound (?). */
 extern int __attribute__((FC_BUILTIN)) eacsl_runtime_sound_verdict;
 
+/*! Data holding context information for E-ACSL assertions. */
+typedef struct eacsl_assert_data_t {
+  /*! integer representing if the assertion is blocking or not */
+  int blocking;
+  /*! C string representing a kind of annotation (e.g., "Assertion") */
+  const char *kind;
+  /*! stringified predicate */
+  const char *pred_txt;
+  /*! un-instrumented file of predicate placement */
+  const char *file;
+  /*! function of predicate placement in the un-instrumented file */
+  const char *fct;
+  /*! line of predicate placement in the un-instrumented file */
+  int line;
+  /*! values contributing to the predicate */
+  void *values;
+} __attribute__((__FC_BUILTIN__)) eacsl_assert_data_t;
+
 /*! \brief Runtime assertion verifying a given predicate
- *  \param pred  integer code of a predicate
- *  \param blocking integer representing if the assertion is blocking or not
- *  \param kind  C string representing a kind of annotation (e.g., "Assertion")
- *  \param fct
- *  \param pred_txt  stringified predicate
- *  \param file un-instrumented file of predicate placement
- *  \param line line of predicate placement in the un-instrumented file */
-/*@ assigns \nothing;
+ *  \param predicate integer code of a predicate
+ *  \param data context data for the predicate. */
+/*@ requires \valid_read(data) && \initialized(data);
+  @ assigns \nothing;
   @ behavior blocking:
-  @   assumes blocking != 0;
-  @   requires pred != 0;
+  @   assumes data->blocking != 0;
+  @   requires predicate != 0;
   @ behavior non_blocking:
-  @   assumes blocking == 0;
-  @   check requires pred != 0;
+  @   assumes data->blocking == 0;
+  @   check requires predicate != 0;
   @ complete behaviors;
   @ disjoint behaviors; */
-void eacsl_runtime_assert(int pred, int blocking, const char *kind,
-                          const char *fct, const char *pred_txt,
-                          const char *file, int line)
+void eacsl_runtime_assert(int predicate, eacsl_assert_data_t *data)
     __attribute__((FC_BUILTIN));
 
 #endif // E_ACSL_ASSERT_H
diff --git a/src/plugins/e-acsl/src/code_generator/assert.ml b/src/plugins/e-acsl/src/code_generator/assert.ml
index 8be5d95be4be239351847fa5fe05151de1089ea0..6697390b0ee25494145821366952cb95823766ab 100644
--- a/src/plugins/e-acsl/src/code_generator/assert.ml
+++ b/src/plugins/e-acsl/src/code_generator/assert.ml
@@ -31,7 +31,10 @@ open Cil_types
 type data = {
   (** Indicates if some data have been registered in the context or not. *)
   data_registered: bool;
-  (* FIXME: fields added to hold information about the C variable in MR !3288 *)
+  (** [varinfo] representing the C variable for the assertion data. *)
+  data_vi: varinfo;
+  (** [exp] representing a pointer to the C variable for the assertion data. *)
+  data_ptr: exp;
 }
 
 (** External type representing the assertion context. Either [Some data] if we
@@ -40,10 +43,32 @@ type t = data option
 
 let no_data = None
 
+(** C type for the [assert_data_t] structure. *)
+let assert_data_ctyp_lazy =
+  lazy (Globals.Types.find_type
+          Logic_typing.Typedef (Functions.RTL.mk_api_name "assert_data_t"))
+
 let empty ~loc kf env =
-  (* FIXME: C variable created in MR !3288 *)
-  ignore (loc, kf);
-  let data = { data_registered = false } in
+  let assert_data_cty = Lazy.force assert_data_ctyp_lazy in
+  let data_vi, _, env =
+    Env.new_var
+      ~loc
+      ~name:"assert_data"
+      env
+      kf
+      None
+      assert_data_cty
+      (fun vi _ ->
+         [ Smart_stmt.struct_local_init
+             ~loc
+             vi
+             [ "values", Smart_exp.null ~loc ] ])
+  in
+  let data =
+    { data_registered = false;
+      data_vi;
+      data_ptr = Cil.mkAddrOfVi data_vi }
+  in
   Some data , env
 
 let with_data_from ~loc kf env from =
@@ -75,8 +100,8 @@ let register ~loc kf env ?(force=false) name e adata =
          The registration can be forced for expressions like [sizeof(int)] for
          instance that are [Const] values but not directly known. *)
       Some adata, env
-    | Some _adata, _ ->
-      let adata = { data_registered = true } in
+    | Some adata, _ ->
+      let adata = { adata with data_registered = true } in
       (* FIXME: value registered to [adata] in MR !3288 *)
       ignore (loc, kf, env, name);
       Some adata, env
@@ -108,7 +133,17 @@ let kind_to_string loc k =
      | Smart_stmt.Variant -> "Variant"
      | Smart_stmt.RTE -> "RTE")
 
-let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env e =
+let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env predicate_e =
+  let env = Env.push env in
+  let data_ptr, data_vi, env =
+    match adata with
+    | Some { data_ptr; data_vi } ->
+      data_ptr, data_vi, env
+    | None ->
+      let adata, env = empty ~loc kf env in
+      let adata = Option.get adata in
+      adata.data_ptr, adata.data_vi, env
+  in
   let blocking =
     match pred_kind with
     | Assert -> Cil.one ~loc
@@ -116,23 +151,33 @@ let runtime_check_with_msg ~adata ~loc msg ~pred_kind kind kf env e =
     | Admit ->
       Options.fatal "No runtime check should be generated for 'admit' clauses"
   in
+  let kind = kind_to_string loc kind in
+  let pred_txt = Cil.mkString ~loc msg in
   let start_pos = fst loc in
-  let file = start_pos.Filepath.pos_path in
-  let line = start_pos.Filepath.pos_lnum in
-  (* FIXME: [adata] support in MR !3288 *)
-  ignore adata;
-  let stmt =
-    Smart_stmt.rtl_call ~loc
-      "assert"
-      [ e;
-        blocking;
-        kind_to_string loc kind;
-        Cil.mkString ~loc (Functions.RTL.get_original_name kf);
-        Cil.mkString ~loc msg;
-        Cil.mkString ~loc (Filepath.Normalized.to_pretty_string file);
-        Cil.integer loc line ]
+  let file =
+    Cil.mkString
+      ~loc
+      (Filepath.Normalized.to_pretty_string start_pos.Filepath.pos_path)
+  in
+  let fct = Cil.mkString ~loc (Functions.RTL.get_original_name kf) in
+  let line = Cil.integer ~loc start_pos.Filepath.pos_lnum in
+  let stmts =
+    [ Smart_stmt.rtl_call ~loc "assert" [ predicate_e; data_ptr ];
+      Smart_stmt.assigns_field ~loc data_vi "line" line;
+      Smart_stmt.assigns_field ~loc data_vi "fct" fct;
+      Smart_stmt.assigns_field ~loc data_vi "file" file;
+      Smart_stmt.assigns_field ~loc data_vi "pred_txt" pred_txt;
+      Smart_stmt.assigns_field ~loc data_vi "kind" kind;
+      Smart_stmt.assigns_field ~loc data_vi "blocking" blocking ]
+  in
+  let block, env =
+    Env.pop_and_get
+      env
+      (Smart_stmt.block_from_stmts (List.rev stmts))
+      ~global_clear:false
+      Env.Middle
   in
-  stmt, env
+  Smart_stmt.block_stmt block, env
 
 let runtime_check ~adata ~pred_kind kind kf env e p =
   let loc = p.pred_loc in