diff --git a/include/lib/utils.h b/include/lib/utils.h
index d46d8461dfaedce858b9ac282d580e3032e74bcc..f324a990916b5e98bdb71cc4259347ab9802174b 100644
--- a/include/lib/utils.h
+++ b/include/lib/utils.h
@@ -67,6 +67,29 @@ void zero_normalmem(void *mem, u_register_t length);
  *       zeroing.
  */
 void zeromem(void *mem, u_register_t length);
+
+/*
+ * Utility function to return the address of a symbol. By default, the
+ * compiler generates adr/adrp instruction pair to return the reference
+ * to the symbol and this utility is used to override this compiler
+ * generated to code to use `ldr` instruction.
+ *
+ * This helps when Position Independent Executable needs to reference a symbol
+ * which is constant and does not depend on the execute address of the binary.
+ */
+#define DEFINE_LOAD_SYM_ADDR(_name)		\
+static inline u_register_t load_addr_## _name(void)		\
+{								\
+	u_register_t v;						\
+	/* Create a void reference to silence compiler */	\
+	(void) _name;						\
+	__asm__ volatile ("ldr %0, =" #_name : "=r" (v));	\
+	return v;						\
+}
+
+/* Helper to invoke the function defined by DEFINE_LOAD_SYM_ADDR() */
+#define LOAD_ADDR_OF(_name)	(typeof(_name) *) load_addr_## _name()
+
 #endif /* !(defined(__LINKER__) || defined(__ASSEMBLY__)) */
 
 #endif /* __UTILS_H__ */
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index e9e8a74d924f14fd6a43fc869b81d871ce15a7a5..a43bff3d4837c2449e11dbd320305f39b6749793 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -10,6 +10,7 @@
 #include <plat_arm.h>
 #include <platform.h>
 #include <platform_def.h>
+#include <utils.h>
 
 /******************************************************************************
  * The following functions are defined as weak to allow a platform to override
@@ -33,10 +34,16 @@ static const interrupt_prop_t arm_interrupt_props[] = {
 
 /*
  * We save and restore the GICv3 context on system suspend. Allocate the
- * data in the designated EL3 Secure carve-out memory
+ * data in the designated EL3 Secure carve-out memory. The `volatile`
+ * is used to prevent the compiler from removing the gicv3 contexts even
+ * though the DEFINE_LOAD_SYM_ADDR creates a dummy reference to it.
  */
-static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
-static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+static volatile gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+static volatile gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+/* Define accessor function to get reference to the GICv3 context */
+DEFINE_LOAD_SYM_ADDR(rdist_ctx)
+DEFINE_LOAD_SYM_ADDR(dist_ctx)
 
 /*
  * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
@@ -134,6 +141,10 @@ void plat_arm_gic_redistif_off(void)
  *****************************************************************************/
 void plat_arm_gic_save(void)
 {
+	gicv3_redist_ctx_t * const rdist_context =
+			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+	gicv3_dist_ctx_t * const dist_context =
+			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
 
 	/*
 	 * If an ITS is available, save its context before
@@ -149,10 +160,10 @@ void plat_arm_gic_save(void)
 	 * we only need to save the context of the CPU that is issuing
 	 * the SYSTEM SUSPEND call, i.e. the current CPU.
 	 */
-	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+	gicv3_rdistif_save(plat_my_core_pos(), rdist_context);
 
 	/* Save the GIC Distributor context */
-	gicv3_distif_save(&dist_ctx);
+	gicv3_distif_save(dist_context);
 
 	/*
 	 * From here, all the components of the GIC can be safely powered down
@@ -163,8 +174,13 @@ void plat_arm_gic_save(void)
 
 void plat_arm_gic_resume(void)
 {
+	const gicv3_redist_ctx_t *rdist_context =
+			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+	const gicv3_dist_ctx_t *dist_context =
+			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
+
 	/* Restore the GIC Distributor context */
-	gicv3_distif_init_restore(&dist_ctx);
+	gicv3_distif_init_restore(dist_context);
 
 	/*
 	 * Restore the GIC Redistributor and ITS contexts after the
@@ -172,7 +188,7 @@ void plat_arm_gic_resume(void)
 	 * we only need to restore the context of the CPU that issued
 	 * the SYSTEM SUSPEND call.
 	 */
-	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+	gicv3_rdistif_init_restore(plat_my_core_pos(), rdist_context);
 
 	/*
 	 * If an ITS is available, restore its context after