ia64: Add support for R_IA64_GPREL64I.
authorVladimir Serbinenko <phcoder@gmail.com>
Tue, 31 Jan 2017 11:39:01 +0000 (12:39 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Tue, 31 Jan 2017 11:39:01 +0000 (12:39 +0100)
Recent GCC generates those relocations, so we need to support them.

grub-core/kern/ia64/dl.c
grub-core/kern/ia64/dl_helper.c
include/grub/ia64/reloc.h
util/grub-mkimagexx.c
util/grub-module-verifier.c

index ad79eb5..082aebc 100644 (file)
@@ -104,6 +104,9 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
        case R_IA64_PCREL64LSB:
          *(grub_uint64_t *) addr += value - addr;
          break;
+       case R_IA64_GPREL64I:
+         grub_ia64_set_immu64 (addr, value - (grub_addr_t) mod->base);
+         break;
        case R_IA64_GPREL22:
          if ((value - (grub_addr_t) mod->base) & ~MASK20)
            return grub_error (GRUB_ERR_BAD_MODULE,
index c7e53a6..2436b75 100644 (file)
 #define MASK20 ((1 << 20) - 1)
 #define MASK3 (~(grub_addr_t) 3)
 
+void
+grub_ia64_set_immu64 (grub_addr_t addr, grub_uint64_t val)
+{
+  /* Copied from binutils.  */
+  grub_uint64_t *ptr = ((grub_uint64_t *) (addr & MASK3));
+  grub_uint64_t t0, t1;
+
+  t0 = grub_le_to_cpu64 (ptr[0]);
+  t1 = grub_le_to_cpu64 (ptr[1]);
+
+  /* tmpl/s: bits  0.. 5 in t0
+     slot 0: bits  5..45 in t0
+     slot 1: bits 46..63 in t0, bits 0..22 in t1
+     slot 2: bits 23..63 in t1 */
+
+  /* First, clear the bits that form the 64 bit constant.  */
+  t0 &= ~(0x3ffffLL << 46);
+  t1 &= ~(0x7fffffLL
+         | ((  (0x07fLL << 13) | (0x1ffLL << 27)
+               | (0x01fLL << 22) | (0x001LL << 21)
+               | (0x001LL << 36)) << 23));
+
+  t0 |= ((val >> 22) & 0x03ffffLL) << 46;              /* 18 lsbs of imm41 */
+  t1 |= ((val >> 40) & 0x7fffffLL) <<  0;              /* 23 msbs of imm41 */
+  t1 |= (  (((val >>  0) & 0x07f) << 13)               /* imm7b */
+          | (((val >>  7) & 0x1ff) << 27)              /* imm9d */
+          | (((val >> 16) & 0x01f) << 22)              /* imm5c */
+          | (((val >> 21) & 0x001) << 21)              /* ic */
+          | (((val >> 63) & 0x001) << 36)) << 23;      /* i */
+
+  ptr[0] = t0;
+  ptr[1] = t1;
+}
+
 void
 grub_ia64_add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
 {
index 4c02ab2..45c8fba 100644 (file)
@@ -26,6 +26,8 @@ grub_ia64_add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value);
 void
 grub_ia64_add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value);
 void
+grub_ia64_set_immu64 (grub_addr_t addr, grub_uint64_t value);
+void
 grub_ia64_make_trampoline (struct grub_ia64_trampoline *tr, grub_uint64_t addr);
 
 struct grub_ia64_trampoline
index 353a940..aa20b9a 100644 (file)
@@ -920,6 +920,10 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
                  grub_ia64_add_value_to_slot_21 ((grub_addr_t) target,
                                                  addend + sym_addr);
                  break;
+               case R_IA64_GPREL64I:
+                 grub_ia64_set_immu64 ((grub_addr_t) target,
+                                       addend + sym_addr);
+                 break;
                case R_IA64_PCREL64LSB:
                  *target = grub_host_to_target64 (grub_target_to_host64 (*target)
                                                   + addend + sym_addr
@@ -1286,6 +1290,7 @@ translate_relocation_pe (struct translate_context *ctx,
        case R_IA64_LTOFF22X:
        case R_IA64_LTOFF22:
        case R_IA64_GPREL22:
+       case R_IA64_GPREL64I:
        case R_IA64_SEGREL64LSB:
          break;
 
index 4234cfd..dd72d78 100644 (file)
@@ -60,6 +60,7 @@ struct grub_module_verifier_arch archs[] = {
       R_IA64_PCREL64LSB,
       R_IA64_LTOFF22X,
       R_IA64_LTOFF22,
+      R_IA64_GPREL64I,
       R_IA64_LTOFF_FPTR22,
       R_IA64_LDXMOV,
       -1