VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / ia64 / kernel / module.c
index e8ea942..2ee61a2 100644 (file)
@@ -656,8 +656,18 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
              case RV_PCREL:
                switch (r_type) {
                      case R_IA64_PCREL21B:
-                       /* special because it can cross into other module/kernel-core.  */
-                       if (!is_internal(mod, val))
+                       if ((in_init(mod, val) && in_core(mod, (uint64_t)location)) ||
+                           (in_core(mod, val) && in_init(mod, (uint64_t)location))) {
+                               /*
+                                * Init section may have been allocated far away from core,
+                                * if the branch won't reach, then allocate a plt for it.
+                                */
+                               uint64_t delta = ((int64_t)val - (int64_t)location) / 16;
+                               if (delta + (1 << 20) >= (1 << 21)) {
+                                       val = get_fdesc(mod, val, &ok);
+                                       val = get_plt(mod, location, val, &ok);
+                               }
+                       } else if (!is_internal(mod, val))
                                val = get_plt(mod, location, val, &ok);
                        /* FALL THROUGH */
                      default: