*cough*

With actual attachment.

On Mon, Dec 02, 2013 at 11:53:31AM +0100, Leif Lindholm wrote:
> On Sun, Dec 01, 2013 at 07:06:32AM +0100, Vladimir 'φ-coder/phcoder' 
> Serbinenko wrote:
> > Current ARM relocation doesn't handle the cases when the relocation cant
> > be satisfied directly (like thumb call over 1M of distance or jump24 to
> > thumb mode. Attached patch adds missing tampoline and missing relocation
> > handling to EFI code (it didn't allow to use ARM (no-Thumb) binary with
> > EFI).
> > I couldn't test it on either arm-efi or ARM64
> 
> Amusingly, I wrote the attached on Saturday, based on a bug report
> from Jon Masters @ Red Hat. Although an unlikely corner case, it does
> probably need the addition of grub_arch_dl_get_tramp_got_size() from
> your implementation in order to ensure the "veneers"[1] don't end up
> in a heap region different to and too far away from the one the module
> is loaded into.
> 
> I'll have a look and a poke on both 32- and 64-bit stuff and respond..
> 
> I would say the modifications to grub-mkimage for arm64 are probably
> unnessecary: AArch64 relative branch range is +-128MB, and I don't
> think we'll see grub kernel images that big.
> 
> /
>     Leif
> 
> [1]
> ARM terminology - "trampolines" for ARM refers to something generated
> on the stack, which we don't see anymore since the nested functions were
> removed.
>From 8d7948641b864168acc67cf0a4834585b3242748 Mon Sep 17 00:00:00 2001
From: Leif Lindholm <[email protected]>
Date: Sat, 30 Nov 2013 13:05:34 +0000
Subject: [PATCH] arm64: dl: generate veneers for out-of-range relocations

Signed-off-by: Leif Lindholm <[email protected]>
---
 grub-core/kern/arm64/dl_helper.c |   45 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/grub-core/kern/arm64/dl_helper.c b/grub-core/kern/arm64/dl_helper.c
index ae4bce8..a473661 100644
--- a/grub-core/kern/arm64/dl_helper.c
+++ b/grub-core/kern/arm64/dl_helper.c
@@ -17,6 +17,7 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <grub/cache.h>
 #include <grub/dl.h>
 #include <grub/elf.h>
 #include <grub/misc.h>
@@ -32,6 +33,46 @@ sign_compress_offset (grub_ssize_t offset, int bitpos)
 }
 
 /*
+ * AArch64 relative branch offset range is +-128MB.
+ * Modules are loaded onto the heap, which may be further away from the
+ * kernel than this. The workaround for this is in ARM-terminology called
+ * a "veneer" - a short sequence of a literal load, a branch to register
+ * and immediately following: the literal (64-bit aligned) 64-bit value.
+ */
+#ifndef GRUB_UTIL
+#define VENEER_LOAD 0x58000050 /* LDR  x16, [PC + 8] */
+#define VENEER_JUMP 0xd61f0200 /* BR   x16  */
+struct veneer {
+  grub_uint32_t load;
+  grub_uint32_t jump;
+  Elf64_Addr target;
+};
+
+static grub_err_t
+add_veneer (grub_uint32_t *place, Elf64_Addr adjust)
+{
+  struct veneer *current;
+  grub_err_t retval;
+
+  current = grub_malloc (sizeof(struct veneer));
+  if (!current)
+    return GRUB_ERR_OUT_OF_MEMORY;
+
+  current->load = VENEER_LOAD;
+  current->jump = VENEER_JUMP;
+  current->target = adjust;
+
+  retval = grub_arm64_reloc_xxxx26 (place, (Elf64_Addr) current);
+  if (retval == GRUB_ERR_NONE)
+    grub_arch_sync_caches (current, sizeof(struct veneer));
+  else
+    grub_free (current);
+
+  return retval;
+}
+#endif
+
+/*
  * grub_arm64_reloc_xxxx26():
  *
  * JUMP26/CALL26 relocations for B and BL instructions.
@@ -54,8 +95,12 @@ grub_arm64_reloc_xxxx26 (grub_uint32_t *place, Elf64_Addr adjust)
 
   if ((offset < offset_low) || (offset > offset_high))
     {
+#ifndef GRUB_UTIL
+      return add_veneer (place, adjust);
+#else
       return grub_error (GRUB_ERR_BAD_MODULE,
 			 N_("CALL26 Relocation out of range"));
+#endif
     }
 
   grub_dprintf ("dl", "  reloc_xxxx64 %p %c= 0x%llx\n",
-- 
1.7.10.4

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to