linux/arch/ia64/kernel/module.c
<<
>>
Prefs
   1/*
   2 * IA-64-specific support for kernel module loader.
   3 *
   4 * Copyright (C) 2003 Hewlett-Packard Co
   5 *      David Mosberger-Tang <davidm@hpl.hp.com>
   6 *
   7 * Loosely based on patch by Rusty Russell.
   8 */
   9
  10/* relocs tested so far:
  11
  12   DIR64LSB
  13   FPTR64LSB
  14   GPREL22
  15   LDXMOV
  16   LDXMOV
  17   LTOFF22
  18   LTOFF22X
  19   LTOFF22X
  20   LTOFF_FPTR22
  21   PCREL21B     (for br.call only; br.cond is not supported out of modules!)
  22   PCREL60B     (for brl.cond only; brl.call is not supported for modules!)
  23   PCREL64LSB
  24   SECREL32LSB
  25   SEGREL64LSB
  26 */
  27
  28
  29#include <linux/kernel.h>
  30#include <linux/sched.h>
  31#include <linux/elf.h>
  32#include <linux/moduleloader.h>
  33#include <linux/string.h>
  34#include <linux/vmalloc.h>
  35
  36#include <asm/patch.h>
  37#include <asm/unaligned.h>
  38
  39#define ARCH_MODULE_DEBUG 0
  40
  41#if ARCH_MODULE_DEBUG
  42# define DEBUGP printk
  43# define inline
  44#else
  45# define DEBUGP(fmt , a...)
  46#endif
  47
  48#ifdef CONFIG_ITANIUM
  49# define USE_BRL        0
  50#else
  51# define USE_BRL        1
  52#endif
  53
  54#define MAX_LTOFF       ((uint64_t) (1 << 22))  /* max. allowable linkage-table offset */
  55
  56/* Define some relocation helper macros/types: */
  57
  58#define FORMAT_SHIFT    0
  59#define FORMAT_BITS     3
  60#define FORMAT_MASK     ((1 << FORMAT_BITS) - 1)
  61#define VALUE_SHIFT     3
  62#define VALUE_BITS      5
  63#define VALUE_MASK      ((1 << VALUE_BITS) - 1)
  64
  65enum reloc_target_format {
  66        /* direct encoded formats: */
  67        RF_NONE = 0,
  68        RF_INSN14 = 1,
  69        RF_INSN22 = 2,
  70        RF_INSN64 = 3,
  71        RF_32MSB = 4,
  72        RF_32LSB = 5,
  73        RF_64MSB = 6,
  74        RF_64LSB = 7,
  75
  76        /* formats that cannot be directly decoded: */
  77        RF_INSN60,
  78        RF_INSN21B,     /* imm21 form 1 */
  79        RF_INSN21M,     /* imm21 form 2 */
  80        RF_INSN21F      /* imm21 form 3 */
  81};
  82
  83enum reloc_value_formula {
  84        RV_DIRECT = 4,          /* S + A */
  85        RV_GPREL = 5,           /* @gprel(S + A) */
  86        RV_LTREL = 6,           /* @ltoff(S + A) */
  87        RV_PLTREL = 7,          /* @pltoff(S + A) */
  88        RV_FPTR = 8,            /* @fptr(S + A) */
  89        RV_PCREL = 9,           /* S + A - P */
  90        RV_LTREL_FPTR = 10,     /* @ltoff(@fptr(S + A)) */
  91        RV_SEGREL = 11,         /* @segrel(S + A) */
  92        RV_SECREL = 12,         /* @secrel(S + A) */
  93        RV_BDREL = 13,          /* BD + A */
  94        RV_LTV = 14,            /* S + A (like RV_DIRECT, except frozen at static link-time) */
  95        RV_PCREL2 = 15,         /* S + A - P */
  96        RV_SPECIAL = 16,        /* various (see below) */
  97        RV_RSVD17 = 17,
  98        RV_TPREL = 18,          /* @tprel(S + A) */
  99        RV_LTREL_TPREL = 19,    /* @ltoff(@tprel(S + A)) */
 100        RV_DTPMOD = 20,         /* @dtpmod(S + A) */
 101        RV_LTREL_DTPMOD = 21,   /* @ltoff(@dtpmod(S + A)) */
 102        RV_DTPREL = 22,         /* @dtprel(S + A) */
 103        RV_LTREL_DTPREL = 23,   /* @ltoff(@dtprel(S + A)) */
 104        RV_RSVD24 = 24,
 105        RV_RSVD25 = 25,
 106        RV_RSVD26 = 26,
 107        RV_RSVD27 = 27
 108        /* 28-31 reserved for implementation-specific purposes.  */
 109};
 110
 111#define N(reloc)        [R_IA64_##reloc] = #reloc
 112
 113static const char *reloc_name[256] = {
 114        N(NONE),                N(IMM14),               N(IMM22),               N(IMM64),
 115        N(DIR32MSB),            N(DIR32LSB),            N(DIR64MSB),            N(DIR64LSB),
 116        N(GPREL22),             N(GPREL64I),            N(GPREL32MSB),          N(GPREL32LSB),
 117        N(GPREL64MSB),          N(GPREL64LSB),          N(LTOFF22),             N(LTOFF64I),
 118        N(PLTOFF22),            N(PLTOFF64I),           N(PLTOFF64MSB),         N(PLTOFF64LSB),
 119        N(FPTR64I),             N(FPTR32MSB),           N(FPTR32LSB),           N(FPTR64MSB),
 120        N(FPTR64LSB),           N(PCREL60B),            N(PCREL21B),            N(PCREL21M),
 121        N(PCREL21F),            N(PCREL32MSB),          N(PCREL32LSB),          N(PCREL64MSB),
 122        N(PCREL64LSB),          N(LTOFF_FPTR22),        N(LTOFF_FPTR64I),       N(LTOFF_FPTR32MSB),
 123        N(LTOFF_FPTR32LSB),     N(LTOFF_FPTR64MSB),     N(LTOFF_FPTR64LSB),     N(SEGREL32MSB),
 124        N(SEGREL32LSB),         N(SEGREL64MSB),         N(SEGREL64LSB),         N(SECREL32MSB),
 125        N(SECREL32LSB),         N(SECREL64MSB),         N(SECREL64LSB),         N(REL32MSB),
 126        N(REL32LSB),            N(REL64MSB),            N(REL64LSB),            N(LTV32MSB),
 127        N(LTV32LSB),            N(LTV64MSB),            N(LTV64LSB),            N(PCREL21BI),
 128        N(PCREL22),             N(PCREL64I),            N(IPLTMSB),             N(IPLTLSB),
 129        N(COPY),                N(LTOFF22X),            N(LDXMOV),              N(TPREL14),
 130        N(TPREL22),             N(TPREL64I),            N(TPREL64MSB),          N(TPREL64LSB),
 131        N(LTOFF_TPREL22),       N(DTPMOD64MSB),         N(DTPMOD64LSB),         N(LTOFF_DTPMOD22),
 132        N(DTPREL14),            N(DTPREL22),            N(DTPREL64I),           N(DTPREL32MSB),
 133        N(DTPREL32LSB),         N(DTPREL64MSB),         N(DTPREL64LSB),         N(LTOFF_DTPREL22)
 134};
 135
 136#undef N
 137
 138/* Opaque struct for insns, to protect against derefs. */
 139struct insn;
 140
 141static inline uint64_t
 142bundle (const struct insn *insn)
 143{
 144        return (uint64_t) insn & ~0xfUL;
 145}
 146
 147static inline int
 148slot (const struct insn *insn)
 149{
 150        return (uint64_t) insn & 0x3;
 151}
 152
 153static int
 154apply_imm64 (struct module *mod, struct insn *insn, uint64_t val)
 155{
 156        if (slot(insn) != 2) {
 157                printk(KERN_ERR "%s: invalid slot number %d for IMM64\n",
 158                       mod->name, slot(insn));
 159                return 0;
 160        }
 161        ia64_patch_imm64((u64) insn, val);
 162        return 1;
 163}
 164
 165static int
 166apply_imm60 (struct module *mod, struct insn *insn, uint64_t val)
 167{
 168        if (slot(insn) != 2) {
 169                printk(KERN_ERR "%s: invalid slot number %d for IMM60\n",
 170                       mod->name, slot(insn));
 171                return 0;
 172        }
 173        if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) {
 174                printk(KERN_ERR "%s: value %ld out of IMM60 range\n", mod->name, (int64_t) val);
 175                return 0;
 176        }
 177        ia64_patch_imm60((u64) insn, val);
 178        return 1;
 179}
 180
 181static int
 182apply_imm22 (struct module *mod, struct insn *insn, uint64_t val)
 183{
 184        if (val + (1 << 21) >= (1 << 22)) {
 185                printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val);
 186                return 0;
 187        }
 188        ia64_patch((u64) insn, 0x01fffcfe000UL, (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
 189                                                 | ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
 190                                                 | ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
 191                                                 | ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
 192        return 1;
 193}
 194
 195static int
 196apply_imm21b (struct module *mod, struct insn *insn, uint64_t val)
 197{
 198        if (val + (1 << 20) >= (1 << 21)) {
 199                printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val);
 200                return 0;
 201        }
 202        ia64_patch((u64) insn, 0x11ffffe000UL, (  ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
 203                                                | ((val & 0x0fffffUL) << 13) /* bit  0 -> 13 */));
 204        return 1;
 205}
 206
 207#if USE_BRL
 208
 209struct plt_entry {
 210        /* Three instruction bundles in PLT. */
 211        unsigned char bundle[2][16];
 212};
 213
 214static const struct plt_entry ia64_plt_template = {
 215        {
 216                {
 217                        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
 218                        0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /*       movl gp=TARGET_GP */
 219                        0x00, 0x00, 0x00, 0x60
 220                },
 221                {
 222                        0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
 223                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*       brl.many gp=TARGET_GP */
 224                        0x08, 0x00, 0x00, 0xc0
 225                }
 226        }
 227};
 228
 229static int
 230patch_plt (struct module *mod, struct plt_entry *plt, long target_ip, unsigned long target_gp)
 231{
 232        if (apply_imm64(mod, (struct insn *) (plt->bundle[0] + 2), target_gp)
 233            && apply_imm60(mod, (struct insn *) (plt->bundle[1] + 2),
 234                           (target_ip - (int64_t) plt->bundle[1]) / 16))
 235                return 1;
 236        return 0;
 237}
 238
 239unsigned long
 240plt_target (struct plt_entry *plt)
 241{
 242        uint64_t b0, b1, *b = (uint64_t *) plt->bundle[1];
 243        long off;
 244
 245        b0 = b[0]; b1 = b[1];
 246        off = (  ((b1 & 0x00fffff000000000UL) >> 36)            /* imm20b -> bit 0 */
 247               | ((b0 >> 48) << 20) | ((b1 & 0x7fffffUL) << 36) /* imm39 -> bit 20 */
 248               | ((b1 & 0x0800000000000000UL) << 0));           /* i -> bit 59 */
 249        return (long) plt->bundle[1] + 16*off;
 250}
 251
 252#else /* !USE_BRL */
 253
 254struct plt_entry {
 255        /* Three instruction bundles in PLT. */
 256        unsigned char bundle[3][16];
 257};
 258
 259static const struct plt_entry ia64_plt_template = {
 260        {
 261                {
 262                        0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
 263                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*       movl r16=TARGET_IP */
 264                        0x02, 0x00, 0x00, 0x60
 265                },
 266                {
 267                        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
 268                        0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /*       movl gp=TARGET_GP */
 269                        0x00, 0x00, 0x00, 0x60
 270                },
 271                {
 272                        0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0 */
 273                        0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /*       mov b6=r16 */
 274                        0x60, 0x00, 0x80, 0x00              /*       br.few b6 */
 275                }
 276        }
 277};
 278
 279static int
 280patch_plt (struct module *mod, struct plt_entry *plt, long target_ip, unsigned long target_gp)
 281{
 282        if (apply_imm64(mod, (struct insn *) (plt->bundle[0] + 2), target_ip)
 283            && apply_imm64(mod, (struct insn *) (plt->bundle[1] + 2), target_gp))
 284                return 1;
 285        return 0;
 286}
 287
 288unsigned long
 289plt_target (struct plt_entry *plt)
 290{
 291        uint64_t b0, b1, *b = (uint64_t *) plt->bundle[0];
 292
 293        b0 = b[0]; b1 = b[1];
 294        return (  ((b1 & 0x000007f000000000) >> 36)             /* imm7b -> bit 0 */
 295                | ((b1 & 0x07fc000000000000) >> 43)             /* imm9d -> bit 7 */
 296                | ((b1 & 0x0003e00000000000) >> 29)             /* imm5c -> bit 16 */
 297                | ((b1 & 0x0000100000000000) >> 23)             /* ic -> bit 21 */
 298                | ((b0 >> 46) << 22) | ((b1 & 0x7fffff) << 40)  /* imm41 -> bit 22 */
 299                | ((b1 & 0x0800000000000000) <<  4));           /* i -> bit 63 */
 300}
 301
 302#endif /* !USE_BRL */
 303
 304void *
 305module_alloc (unsigned long size)
 306{
 307        if (!size)
 308                return NULL;
 309        return vmalloc(size);
 310}
 311
 312void
 313module_free (struct module *mod, void *module_region)
 314{
 315        if (mod && mod->arch.init_unw_table &&
 316            module_region == mod->module_init) {
 317                unw_remove_unwind_table(mod->arch.init_unw_table);
 318                mod->arch.init_unw_table = NULL;
 319        }
 320        vfree(module_region);
 321}
 322
 323/* Have we already seen one of these relocations? */
 324/* FIXME: we could look in other sections, too --RR */
 325static int
 326duplicate_reloc (const Elf64_Rela *rela, unsigned int num)
 327{
 328        unsigned int i;
 329
 330        for (i = 0; i < num; i++) {
 331                if (rela[i].r_info == rela[num].r_info && rela[i].r_addend == rela[num].r_addend)
 332                        return 1;
 333        }
 334        return 0;
 335}
 336
 337/* Count how many GOT entries we may need */
 338static unsigned int
 339count_gots (const Elf64_Rela *rela, unsigned int num)
 340{
 341        unsigned int i, ret = 0;
 342
 343        /* Sure, this is order(n^2), but it's usually short, and not
 344           time critical */
 345        for (i = 0; i < num; i++) {
 346                switch (ELF64_R_TYPE(rela[i].r_info)) {
 347                      case R_IA64_LTOFF22:
 348                      case R_IA64_LTOFF22X:
 349                      case R_IA64_LTOFF64I:
 350                      case R_IA64_LTOFF_FPTR22:
 351                      case R_IA64_LTOFF_FPTR64I:
 352                      case R_IA64_LTOFF_FPTR32MSB:
 353                      case R_IA64_LTOFF_FPTR32LSB:
 354                      case R_IA64_LTOFF_FPTR64MSB:
 355                      case R_IA64_LTOFF_FPTR64LSB:
 356                        if (!duplicate_reloc(rela, i))
 357                                ret++;
 358                        break;
 359                }
 360        }
 361        return ret;
 362}
 363
 364/* Count how many PLT entries we may need */
 365static unsigned int
 366count_plts (const Elf64_Rela *rela, unsigned int num)
 367{
 368        unsigned int i, ret = 0;
 369
 370        /* Sure, this is order(n^2), but it's usually short, and not
 371           time critical */
 372        for (i = 0; i < num; i++) {
 373                switch (ELF64_R_TYPE(rela[i].r_info)) {
 374                      case R_IA64_PCREL21B:
 375                      case R_IA64_PLTOFF22:
 376                      case R_IA64_PLTOFF64I:
 377                      case R_IA64_PLTOFF64MSB:
 378                      case R_IA64_PLTOFF64LSB:
 379                      case R_IA64_IPLTMSB:
 380                      case R_IA64_IPLTLSB:
 381                        if (!duplicate_reloc(rela, i))
 382                                ret++;
 383                        break;
 384                }
 385        }
 386        return ret;
 387}
 388
 389/* We need to create an function-descriptors for any internal function
 390   which is referenced. */
 391static unsigned int
 392count_fdescs (const Elf64_Rela *rela, unsigned int num)
 393{
 394        unsigned int i, ret = 0;
 395
 396        /* Sure, this is order(n^2), but it's usually short, and not time critical.  */
 397        for (i = 0; i < num; i++) {
 398                switch (ELF64_R_TYPE(rela[i].r_info)) {
 399                      case R_IA64_FPTR64I:
 400                      case R_IA64_FPTR32LSB:
 401                      case R_IA64_FPTR32MSB:
 402                      case R_IA64_FPTR64LSB:
 403                      case R_IA64_FPTR64MSB:
 404                      case R_IA64_LTOFF_FPTR22:
 405                      case R_IA64_LTOFF_FPTR32LSB:
 406                      case R_IA64_LTOFF_FPTR32MSB:
 407                      case R_IA64_LTOFF_FPTR64I:
 408                      case R_IA64_LTOFF_FPTR64LSB:
 409                      case R_IA64_LTOFF_FPTR64MSB:
 410                      case R_IA64_IPLTMSB:
 411                      case R_IA64_IPLTLSB:
 412                        /*
 413                         * Jumps to static functions sometimes go straight to their
 414                         * offset.  Of course, that may not be possible if the jump is
 415                         * from init -> core or vice. versa, so we need to generate an
 416                         * FDESC (and PLT etc) for that.
 417                         */
 418                      case R_IA64_PCREL21B:
 419                        if (!duplicate_reloc(rela, i))
 420                                ret++;
 421                        break;
 422                }
 423        }
 424        return ret;
 425}
 426
 427int
 428module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
 429                           struct module *mod)
 430{
 431        unsigned long core_plts = 0, init_plts = 0, gots = 0, fdescs = 0;
 432        Elf64_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
 433
 434        /*
 435         * To store the PLTs and function-descriptors, we expand the .text section for
 436         * core module-code and the .init.text section for initialization code.
 437         */
 438        for (s = sechdrs; s < sechdrs_end; ++s)
 439                if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
 440                        mod->arch.core_plt = s;
 441                else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
 442                        mod->arch.init_plt = s;
 443                else if (strcmp(".got", secstrings + s->sh_name) == 0)
 444                        mod->arch.got = s;
 445                else if (strcmp(".opd", secstrings + s->sh_name) == 0)
 446                        mod->arch.opd = s;
 447                else if (strcmp(".IA_64.unwind", secstrings + s->sh_name) == 0)
 448                        mod->arch.unwind = s;
 449
 450        if (!mod->arch.core_plt || !mod->arch.init_plt || !mod->arch.got || !mod->arch.opd) {
 451                printk(KERN_ERR "%s: sections missing\n", mod->name);
 452                return -ENOEXEC;
 453        }
 454
 455        /* GOT and PLTs can occur in any relocated section... */
 456        for (s = sechdrs + 1; s < sechdrs_end; ++s) {
 457                const Elf64_Rela *rels = (void *)ehdr + s->sh_offset;
 458                unsigned long numrels = s->sh_size/sizeof(Elf64_Rela);
 459
 460                if (s->sh_type != SHT_RELA)
 461                        continue;
 462
 463                gots += count_gots(rels, numrels);
 464                fdescs += count_fdescs(rels, numrels);
 465                if (strstr(secstrings + s->sh_name, ".init"))
 466                        init_plts += count_plts(rels, numrels);
 467                else
 468                        core_plts += count_plts(rels, numrels);
 469        }
 470
 471        mod->arch.core_plt->sh_type = SHT_NOBITS;
 472        mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
 473        mod->arch.core_plt->sh_addralign = 16;
 474        mod->arch.core_plt->sh_size = core_plts * sizeof(struct plt_entry);
 475        mod->arch.init_plt->sh_type = SHT_NOBITS;
 476        mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
 477        mod->arch.init_plt->sh_addralign = 16;
 478        mod->arch.init_plt->sh_size = init_plts * sizeof(struct plt_entry);
 479        mod->arch.got->sh_type = SHT_NOBITS;
 480        mod->arch.got->sh_flags = ARCH_SHF_SMALL | SHF_ALLOC;
 481        mod->arch.got->sh_addralign = 8;
 482        mod->arch.got->sh_size = gots * sizeof(struct got_entry);
 483        mod->arch.opd->sh_type = SHT_NOBITS;
 484        mod->arch.opd->sh_flags = SHF_ALLOC;
 485        mod->arch.opd->sh_addralign = 8;
 486        mod->arch.opd->sh_size = fdescs * sizeof(struct fdesc);
 487        DEBUGP("%s: core.plt=%lx, init.plt=%lx, got=%lx, fdesc=%lx\n",
 488               __func__, mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size,
 489               mod->arch.got->sh_size, mod->arch.opd->sh_size);
 490        return 0;
 491}
 492
 493static inline int
 494in_init (const struct module *mod, uint64_t addr)
 495{
 496        return addr - (uint64_t) mod->module_init < mod->init_size;
 497}
 498
 499static inline int
 500in_core (const struct module *mod, uint64_t addr)
 501{
 502        return addr - (uint64_t) mod->module_core < mod->core_size;
 503}
 504
 505static inline int
 506is_internal (const struct module *mod, uint64_t value)
 507{
 508        return in_init(mod, value) || in_core(mod, value);
 509}
 510
 511/*
 512 * Get gp-relative offset for the linkage-table entry of VALUE.
 513 */
 514static uint64_t
 515get_ltoff (struct module *mod, uint64_t value, int *okp)
 516{
 517        struct got_entry *got, *e;
 518
 519        if (!*okp)
 520                return 0;
 521
 522        got = (void *) mod->arch.got->sh_addr;
 523        for (e = got; e < got + mod->arch.next_got_entry; ++e)
 524                if (e->val == value)
 525                        goto found;
 526
 527        /* Not enough GOT entries? */
 528        if (e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size))
 529                BUG();
 530
 531        e->val = value;
 532        ++mod->arch.next_got_entry;
 533  found:
 534        return (uint64_t) e - mod->arch.gp;
 535}
 536
 537static inline int
 538gp_addressable (struct module *mod, uint64_t value)
 539{
 540        return value - mod->arch.gp + MAX_LTOFF/2 < MAX_LTOFF;
 541}
 542
 543/* Get PC-relative PLT entry for this value.  Returns 0 on failure. */
 544static uint64_t
 545get_plt (struct module *mod, const struct insn *insn, uint64_t value, int *okp)
 546{
 547        struct plt_entry *plt, *plt_end;
 548        uint64_t target_ip, target_gp;
 549
 550        if (!*okp)
 551                return 0;
 552
 553        if (in_init(mod, (uint64_t) insn)) {
 554                plt = (void *) mod->arch.init_plt->sh_addr;
 555                plt_end = (void *) plt + mod->arch.init_plt->sh_size;
 556        } else {
 557                plt = (void *) mod->arch.core_plt->sh_addr;
 558                plt_end = (void *) plt + mod->arch.core_plt->sh_size;
 559        }
 560
 561        /* "value" is a pointer to a function-descriptor; fetch the target ip/gp from it: */
 562        target_ip = ((uint64_t *) value)[0];
 563        target_gp = ((uint64_t *) value)[1];
 564
 565        /* Look for existing PLT entry. */
 566        while (plt->bundle[0][0]) {
 567                if (plt_target(plt) == target_ip)
 568                        goto found;
 569                if (++plt >= plt_end)
 570                        BUG();
 571        }
 572        *plt = ia64_plt_template;
 573        if (!patch_plt(mod, plt, target_ip, target_gp)) {
 574                *okp = 0;
 575                return 0;
 576        }
 577#if ARCH_MODULE_DEBUG
 578        if (plt_target(plt) != target_ip) {
 579                printk("%s: mistargeted PLT: wanted %lx, got %lx\n",
 580                       __func__, target_ip, plt_target(plt));
 581                *okp = 0;
 582                return 0;
 583        }
 584#endif
 585  found:
 586        return (uint64_t) plt;
 587}
 588
 589/* Get function descriptor for VALUE. */
 590static uint64_t
 591get_fdesc (struct module *mod, uint64_t value, int *okp)
 592{
 593        struct fdesc *fdesc = (void *) mod->arch.opd->sh_addr;
 594
 595        if (!*okp)
 596                return 0;
 597
 598        if (!value) {
 599                printk(KERN_ERR "%s: fdesc for zero requested!\n", mod->name);
 600                return 0;
 601        }
 602
 603        if (!is_internal(mod, value))
 604                /*
 605                 * If it's not a module-local entry-point, "value" already points to a
 606                 * function-descriptor.
 607                 */
 608                return value;
 609
 610        /* Look for existing function descriptor. */
 611        while (fdesc->ip) {
 612                if (fdesc->ip == value)
 613                        return (uint64_t)fdesc;
 614                if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)
 615                        BUG();
 616        }
 617
 618        /* Create new one */
 619        fdesc->ip = value;
 620        fdesc->gp = mod->arch.gp;
 621        return (uint64_t) fdesc;
 622}
 623
 624static inline int
 625do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
 626          Elf64_Shdr *sec, void *location)
 627{
 628        enum reloc_target_format format = (r_type >> FORMAT_SHIFT) & FORMAT_MASK;
 629        enum reloc_value_formula formula = (r_type >> VALUE_SHIFT) & VALUE_MASK;
 630        uint64_t val;
 631        int ok = 1;
 632
 633        val = sym->st_value + addend;
 634
 635        switch (formula) {
 636              case RV_SEGREL:   /* segment base is arbitrarily chosen to be 0 for kernel modules */
 637              case RV_DIRECT:
 638                break;
 639
 640              case RV_GPREL:      val -= mod->arch.gp; break;
 641              case RV_LTREL:      val = get_ltoff(mod, val, &ok); break;
 642              case RV_PLTREL:     val = get_plt(mod, location, val, &ok); break;
 643              case RV_FPTR:       val = get_fdesc(mod, val, &ok); break;
 644              case RV_SECREL:     val -= sec->sh_addr; break;
 645              case RV_LTREL_FPTR: val = get_ltoff(mod, get_fdesc(mod, val, &ok), &ok); break;
 646
 647              case RV_PCREL:
 648                switch (r_type) {
 649                      case R_IA64_PCREL21B:
 650                        if ((in_init(mod, val) && in_core(mod, (uint64_t)location)) ||
 651                            (in_core(mod, val) && in_init(mod, (uint64_t)location))) {
 652                                /*
 653                                 * Init section may have been allocated far away from core,
 654                                 * if the branch won't reach, then allocate a plt for it.
 655                                 */
 656                                uint64_t delta = ((int64_t)val - (int64_t)location) / 16;
 657                                if (delta + (1 << 20) >= (1 << 21)) {
 658                                        val = get_fdesc(mod, val, &ok);
 659                                        val = get_plt(mod, location, val, &ok);
 660                                }
 661                        } else if (!is_internal(mod, val))
 662                                val = get_plt(mod, location, val, &ok);
 663                        /* FALL THROUGH */
 664                      default:
 665                        val -= bundle(location);
 666                        break;
 667
 668                      case R_IA64_PCREL32MSB:
 669                      case R_IA64_PCREL32LSB:
 670                      case R_IA64_PCREL64MSB:
 671                      case R_IA64_PCREL64LSB:
 672                        val -= (uint64_t) location;
 673                        break;
 674
 675                }
 676                switch (r_type) {
 677                      case R_IA64_PCREL60B: format = RF_INSN60; break;
 678                      case R_IA64_PCREL21B: format = RF_INSN21B; break;
 679                      case R_IA64_PCREL21M: format = RF_INSN21M; break;
 680                      case R_IA64_PCREL21F: format = RF_INSN21F; break;
 681                      default: break;
 682                }
 683                break;
 684
 685              case RV_BDREL:
 686                val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);
 687                break;
 688
 689              case RV_LTV:
 690                /* can link-time value relocs happen here?  */
 691                BUG();
 692                break;
 693
 694              case RV_PCREL2:
 695                if (r_type == R_IA64_PCREL21BI) {
 696                        if (!is_internal(mod, val)) {
 697                                printk(KERN_ERR "%s: %s reloc against non-local symbol (%lx)\n",
 698                                       __func__, reloc_name[r_type], val);
 699                                return -ENOEXEC;
 700                        }
 701                        format = RF_INSN21B;
 702                }
 703                val -= bundle(location);
 704                break;
 705
 706              case RV_SPECIAL:
 707                switch (r_type) {
 708                      case R_IA64_IPLTMSB:
 709                      case R_IA64_IPLTLSB:
 710                        val = get_fdesc(mod, get_plt(mod, location, val, &ok), &ok);
 711                        format = RF_64LSB;
 712                        if (r_type == R_IA64_IPLTMSB)
 713                                format = RF_64MSB;
 714                        break;
 715
 716                      case R_IA64_SUB:
 717                        val = addend - sym->st_value;
 718                        format = RF_INSN64;
 719                        break;
 720
 721                      case R_IA64_LTOFF22X:
 722                        if (gp_addressable(mod, val))
 723                                val -= mod->arch.gp;
 724                        else
 725                                val = get_ltoff(mod, val, &ok);
 726                        format = RF_INSN22;
 727                        break;
 728
 729                      case R_IA64_LDXMOV:
 730                        if (gp_addressable(mod, val)) {
 731                                /* turn "ld8" into "mov": */
 732                                DEBUGP("%s: patching ld8 at %p to mov\n", __func__, location);
 733                                ia64_patch((u64) location, 0x1fff80fe000UL, 0x10000000000UL);
 734                        }
 735                        return 0;
 736
 737                      default:
 738                        if (reloc_name[r_type])
 739                                printk(KERN_ERR "%s: special reloc %s not supported",
 740                                       mod->name, reloc_name[r_type]);
 741                        else
 742                                printk(KERN_ERR "%s: unknown special reloc %x\n",
 743                                       mod->name, r_type);
 744                        return -ENOEXEC;
 745                }
 746                break;
 747
 748              case RV_TPREL:
 749              case RV_LTREL_TPREL:
 750              case RV_DTPMOD:
 751              case RV_LTREL_DTPMOD:
 752              case RV_DTPREL:
 753              case RV_LTREL_DTPREL:
 754                printk(KERN_ERR "%s: %s reloc not supported\n",
 755                       mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?");
 756                return -ENOEXEC;
 757
 758              default:
 759                printk(KERN_ERR "%s: unknown reloc %x\n", mod->name, r_type);
 760                return -ENOEXEC;
 761        }
 762
 763        if (!ok)
 764                return -ENOEXEC;
 765
 766        DEBUGP("%s: [%p]<-%016lx = %s(%lx)\n", __func__, location, val,
 767               reloc_name[r_type] ? reloc_name[r_type] : "?", sym->st_value + addend);
 768
 769        switch (format) {
 770              case RF_INSN21B:  ok = apply_imm21b(mod, location, (int64_t) val / 16); break;
 771              case RF_INSN22:   ok = apply_imm22(mod, location, val); break;
 772              case RF_INSN64:   ok = apply_imm64(mod, location, val); break;
 773              case RF_INSN60:   ok = apply_imm60(mod, location, (int64_t) val / 16); break;
 774              case RF_32LSB:    put_unaligned(val, (uint32_t *) location); break;
 775              case RF_64LSB:    put_unaligned(val, (uint64_t *) location); break;
 776              case RF_32MSB:    /* ia64 Linux is little-endian... */
 777              case RF_64MSB:    /* ia64 Linux is little-endian... */
 778              case RF_INSN14:   /* must be within-module, i.e., resolved by "ld -r" */
 779              case RF_INSN21M:  /* must be within-module, i.e., resolved by "ld -r" */
 780              case RF_INSN21F:  /* must be within-module, i.e., resolved by "ld -r" */
 781                printk(KERN_ERR "%s: format %u needed by %s reloc is not supported\n",
 782                       mod->name, format, reloc_name[r_type] ? reloc_name[r_type] : "?");
 783                return -ENOEXEC;
 784
 785              default:
 786                printk(KERN_ERR "%s: relocation %s resulted in unknown format %u\n",
 787                       mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?", format);
 788                return -ENOEXEC;
 789        }
 790        return ok ? 0 : -ENOEXEC;
 791}
 792
 793int
 794apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 795                    unsigned int relsec, struct module *mod)
 796{
 797        unsigned int i, n = sechdrs[relsec].sh_size / sizeof(Elf64_Rela);
 798        Elf64_Rela *rela = (void *) sechdrs[relsec].sh_addr;
 799        Elf64_Shdr *target_sec;
 800        int ret;
 801
 802        DEBUGP("%s: applying section %u (%u relocs) to %u\n", __func__,
 803               relsec, n, sechdrs[relsec].sh_info);
 804
 805        target_sec = sechdrs + sechdrs[relsec].sh_info;
 806
 807        if (target_sec->sh_entsize == ~0UL)
 808                /*
 809                 * If target section wasn't allocated, we don't need to relocate it.
 810                 * Happens, e.g., for debug sections.
 811                 */
 812                return 0;
 813
 814        if (!mod->arch.gp) {
 815                /*
 816                 * XXX Should have an arch-hook for running this after final section
 817                 *     addresses have been selected...
 818                 */
 819                uint64_t gp;
 820                if (mod->core_size > MAX_LTOFF)
 821                        /*
 822                         * This takes advantage of fact that SHF_ARCH_SMALL gets allocated
 823                         * at the end of the module.
 824                         */
 825                        gp = mod->core_size - MAX_LTOFF / 2;
 826                else
 827                        gp = mod->core_size / 2;
 828                gp = (uint64_t) mod->module_core + ((gp + 7) & -8);
 829                mod->arch.gp = gp;
 830                DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp);
 831        }
 832
 833        for (i = 0; i < n; i++) {
 834                ret = do_reloc(mod, ELF64_R_TYPE(rela[i].r_info),
 835                               ((Elf64_Sym *) sechdrs[symindex].sh_addr
 836                                + ELF64_R_SYM(rela[i].r_info)),
 837                               rela[i].r_addend, target_sec,
 838                               (void *) target_sec->sh_addr + rela[i].r_offset);
 839                if (ret < 0)
 840                        return ret;
 841        }
 842        return 0;
 843}
 844
 845int
 846apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 847                unsigned int relsec, struct module *mod)
 848{
 849        printk(KERN_ERR "module %s: REL relocs in section %u unsupported\n", mod->name, relsec);
 850        return -ENOEXEC;
 851}
 852
 853/*
 854 * Modules contain a single unwind table which covers both the core and the init text
 855 * sections but since the two are not contiguous, we need to split this table up such that
 856 * we can register (and unregister) each "segment" separately.  Fortunately, this sounds
 857 * more complicated than it really is.
 858 */
 859static void
 860register_unwind_table (struct module *mod)
 861{
 862        struct unw_table_entry *start = (void *) mod->arch.unwind->sh_addr;
 863        struct unw_table_entry *end = start + mod->arch.unwind->sh_size / sizeof (*start);
 864        struct unw_table_entry tmp, *e1, *e2, *core, *init;
 865        unsigned long num_init = 0, num_core = 0;
 866
 867        /* First, count how many init and core unwind-table entries there are.  */
 868        for (e1 = start; e1 < end; ++e1)
 869                if (in_init(mod, e1->start_offset))
 870                        ++num_init;
 871                else
 872                        ++num_core;
 873        /*
 874         * Second, sort the table such that all unwind-table entries for the init and core
 875         * text sections are nicely separated.  We do this with a stupid bubble sort
 876         * (unwind tables don't get ridiculously huge).
 877         */
 878        for (e1 = start; e1 < end; ++e1) {
 879                for (e2 = e1 + 1; e2 < end; ++e2) {
 880                        if (e2->start_offset < e1->start_offset) {
 881                                tmp = *e1;
 882                                *e1 = *e2;
 883                                *e2 = tmp;
 884                        }
 885                }
 886        }
 887        /*
 888         * Third, locate the init and core segments in the unwind table:
 889         */
 890        if (in_init(mod, start->start_offset)) {
 891                init = start;
 892                core = start + num_init;
 893        } else {
 894                core = start;
 895                init = start + num_core;
 896        }
 897
 898        DEBUGP("%s: name=%s, gp=%lx, num_init=%lu, num_core=%lu\n", __func__,
 899               mod->name, mod->arch.gp, num_init, num_core);
 900
 901        /*
 902         * Fourth, register both tables (if not empty).
 903         */
 904        if (num_core > 0) {
 905                mod->arch.core_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
 906                                                                core, core + num_core);
 907                DEBUGP("%s:  core: handle=%p [%p-%p)\n", __func__,
 908                       mod->arch.core_unw_table, core, core + num_core);
 909        }
 910        if (num_init > 0) {
 911                mod->arch.init_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
 912                                                                init, init + num_init);
 913                DEBUGP("%s:  init: handle=%p [%p-%p)\n", __func__,
 914                       mod->arch.init_unw_table, init, init + num_init);
 915        }
 916}
 917
 918int
 919module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
 920{
 921        DEBUGP("%s: init: entry=%p\n", __func__, mod->init);
 922        if (mod->arch.unwind)
 923                register_unwind_table(mod);
 924        return 0;
 925}
 926
 927void
 928module_arch_cleanup (struct module *mod)
 929{
 930        if (mod->arch.init_unw_table)
 931                unw_remove_unwind_table(mod->arch.init_unw_table);
 932        if (mod->arch.core_unw_table)
 933                unw_remove_unwind_table(mod->arch.core_unw_table);
 934}
 935
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.