b       stext                           // branch to kernel start, magic
        .long   0                               // reserved
 #endif
-       .quad   _kernel_offset_le               // Image load offset from start of RAM, little-endian
-       .quad   _kernel_size_le                 // Effective size of kernel image, little-endian
-       .quad   _kernel_flags_le                // Informative flags, little-endian
+       le64sym _kernel_offset_le               // Image load offset from start of RAM, little-endian
+       le64sym _kernel_size_le                 // Effective size of kernel image, little-endian
+       le64sym _kernel_flags_le                // Informative flags, little-endian
        .quad   0                               // reserved
        .quad   0                               // reserved
        .quad   0                               // reserved
 
  * There aren't any ELF relocations we can use to endian-swap values known only
  * at link time (e.g. the subtraction of two symbol addresses), so we must get
  * the linker to endian-swap certain values before emitting them.
+ *
+ * Note that, in order for this to work when building the ELF64 PIE executable
+ * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
+ * relocations, since these are fixed up at runtime rather than at build time
+ * when PIE is in effect. So we need to split them up in 32-bit high and low
+ * words.
  */
 #ifdef CONFIG_CPU_BIG_ENDIAN
-#define DATA_LE64(data)                                        \
-       ((((data) & 0x00000000000000ff) << 56) |        \
-        (((data) & 0x000000000000ff00) << 40) |        \
-        (((data) & 0x0000000000ff0000) << 24) |        \
-        (((data) & 0x00000000ff000000) << 8)  |        \
-        (((data) & 0x000000ff00000000) >> 8)  |        \
-        (((data) & 0x0000ff0000000000) >> 24) |        \
-        (((data) & 0x00ff000000000000) >> 40) |        \
-        (((data) & 0xff00000000000000) >> 56))
+#define DATA_LE32(data)                                \
+       ((((data) & 0x000000ff) << 24) |        \
+        (((data) & 0x0000ff00) << 8)  |        \
+        (((data) & 0x00ff0000) >> 8)  |        \
+        (((data) & 0xff000000) >> 24))
 #else
-#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
+#define DATA_LE32(data) ((data) & 0xffffffff)
 #endif
 
+#define DEFINE_IMAGE_LE64(sym, data)                           \
+       sym##_lo32 = DATA_LE32((data) & 0xffffffff);            \
+       sym##_hi32 = DATA_LE32((data) >> 32)
+
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define __HEAD_FLAG_BE         1
 #else
  * endian swapped in head.S, all are done here for consistency.
  */
 #define HEAD_SYMBOLS                                           \
-       _kernel_size_le         = DATA_LE64(_end - _text);      \
-       _kernel_offset_le       = DATA_LE64(TEXT_OFFSET);       \
-       _kernel_flags_le        = DATA_LE64(__HEAD_FLAGS);
+       DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);       \
+       DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
+       DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
 
 #ifdef CONFIG_EFI