home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / modutils / obj / obj_alpha.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-06  |  6.5 KB  |  279 lines

  1. /* Alpha specific support for Elf loading and relocation.
  2.    Copyright 1996, 1997 Linux International.
  3.  
  4.    Contributed by Richard Henderson <rth@tamu.edu>
  5.  
  6.    This file is part of the Linux modutils.
  7.  
  8.    This program is free software; you can redistribute it and/or modify it
  9.    under the terms of the GNU General Public License as published by the
  10.    Free Software Foundation; either version 2 of the License, or (at your
  11.    option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software Foundation,
  20.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  21.  
  22. #ident "$Id: obj_alpha.c,v 1.1.1.1 1998/01/06 20:51:08 ewt Exp $"
  23.  
  24. #include <string.h>
  25. #include <assert.h>
  26.  
  27. #include <module.h>
  28. #include <obj.h>
  29. #include <util.h>
  30.  
  31. /*======================================================================*/
  32.  
  33. struct alpha_got_entry
  34. {
  35.   struct alpha_got_entry *next;
  36.   ElfW(Addr) addend;
  37.   int offset;
  38.   int reloc_done;
  39. };
  40.  
  41. struct alpha_file
  42. {
  43.   struct obj_file root;
  44.   struct obj_section *got;
  45. };
  46.  
  47. struct alpha_symbol
  48. {
  49.   struct obj_symbol root;
  50.   struct alpha_got_entry *got_entries;
  51. };
  52.  
  53.  
  54. /*======================================================================*/
  55.  
  56. struct obj_file *
  57. arch_new_file (void)
  58. {
  59.   struct alpha_file *f;
  60.   f = xmalloc(sizeof(*f));
  61.   f->got = NULL;
  62.   return &f->root;
  63. }
  64.  
  65. struct obj_section *
  66. arch_new_section (void)
  67. {
  68.   return xmalloc(sizeof(struct obj_section));
  69. }
  70.  
  71. struct obj_symbol *
  72. arch_new_symbol (void)
  73. {
  74.   struct alpha_symbol *sym;
  75.   sym = xmalloc(sizeof(*sym));
  76.   sym->got_entries = NULL;
  77.   return &sym->root;
  78. }
  79.  
  80. enum obj_reloc
  81. arch_apply_relocation (struct obj_file *f,
  82.                struct obj_section *targsec,
  83.                struct obj_section *symsec,
  84.                struct obj_symbol *sym,
  85.                Elf64_Rela *rel,
  86.                Elf64_Addr v)
  87. {
  88.   struct alpha_file *af = (struct alpha_file *)f;
  89.   struct alpha_symbol *asym = (struct alpha_symbol *)sym;
  90.  
  91.   unsigned long *lloc = (unsigned long *)(targsec->contents + rel->r_offset);
  92.   unsigned int *iloc = (unsigned int *)lloc;
  93.   Elf64_Addr dot = targsec->header.sh_addr + rel->r_offset;
  94.   Elf64_Addr gp = af->got->header.sh_addr + 0x8000;
  95.  
  96.   enum obj_reloc ret = obj_reloc_ok;
  97.  
  98.   switch (ELF64_R_TYPE(rel->r_info))
  99.     {
  100.     case R_ALPHA_NONE:
  101.     case R_ALPHA_LITUSE:
  102.       break;
  103.  
  104.     case R_ALPHA_REFQUAD:
  105.       *lloc += v;
  106.       break;
  107.  
  108.     case R_ALPHA_GPREL32:
  109.       v -= gp;
  110.       if ((Elf64_Sxword)v > 0x7fffffff
  111.       || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
  112.     ret = obj_reloc_overflow;
  113.       *iloc = v;
  114.       break;
  115.  
  116.     case R_ALPHA_LITERAL:
  117.       {
  118.     struct alpha_got_entry *gotent;
  119.  
  120.     assert(asym != NULL);
  121.     gotent = asym->got_entries;
  122.     while (gotent->addend != rel->r_addend)
  123.       gotent = gotent->next;
  124.  
  125.     if (!gotent->reloc_done)
  126.       {
  127.         *(unsigned long *)(af->got->contents + gotent->offset) = v;
  128.         gotent->reloc_done = 1;
  129.       }
  130.  
  131.     *iloc = (*iloc & ~0xffff) | ((gotent->offset - 0x8000) & 0xffff);
  132.       }
  133.     break;
  134.  
  135.     case R_ALPHA_GPDISP:
  136.       {
  137.     unsigned int *p_ldah, *p_lda;
  138.     unsigned int i_ldah, i_lda, hi, lo;
  139.  
  140.     p_ldah = iloc;
  141.     p_lda = (unsigned int *)((char *)iloc + rel->r_addend);
  142.     i_ldah = *p_ldah;
  143.     i_lda = *p_lda;
  144.  
  145.     /* Make sure the instructions are righteous.  */
  146.     if ((i_ldah >> 26) != 9 || (i_lda >> 26) != 8)
  147.       ret = obj_reloc_dangerous;
  148.  
  149.     /* Extract the existing addend.  */
  150.     v = (i_ldah & 0xffff) << 16 | (i_lda & 0xffff);
  151.     v = (v ^ 0x80008000) - 0x80008000;
  152.  
  153.     v += gp - dot;
  154.  
  155.     if ((Elf64_Sxword)v >= 0x7fff8000
  156.         || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
  157.       ret = obj_reloc_overflow;
  158.  
  159.     /* Modify the instructions and finish up.  */
  160.     lo = v & 0xffff;
  161.     hi = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
  162.  
  163.     *p_ldah = (i_ldah & 0xffff0000) | hi;
  164.     *p_lda = (i_lda & 0xffff0000) | lo;
  165.       }
  166.     break;
  167.  
  168.     case R_ALPHA_BRADDR:
  169.       v -= dot + 4;
  170.       if (v % 4)
  171.     ret = obj_reloc_dangerous;
  172.       else if ((Elf64_Sxword)v > 0x3fffff
  173.            || (Elf64_Sxword)v < -(Elf64_Sxword)0x400000)
  174.     ret = obj_reloc_overflow;
  175.       v /= 4;
  176.  
  177.       *iloc = (*iloc & ~0x1fffff) | (v & 0x1fffff);
  178.       break;
  179.  
  180.     case R_ALPHA_HINT:
  181.       v -= dot + 4;
  182.       if (v % 4)
  183.     ret = obj_reloc_dangerous;
  184.       v /= 4;
  185.  
  186.       *iloc = (*iloc & ~0x3fff) | (v & 0x3fff);
  187.       break;
  188.  
  189.     default:
  190.       ret = obj_reloc_unhandled;
  191.       break;
  192.     }
  193.  
  194.   return ret;
  195. }
  196.  
  197. int
  198. arch_create_got (struct obj_file *f)
  199. {
  200.   struct alpha_file *af = (struct alpha_file *)f;
  201.   int i, n, offset = 0;
  202.  
  203.   n = af->root.header.e_shnum;
  204.   for (i = 0; i < n; ++i)
  205.     {
  206.       struct obj_section *relsec, *symsec, *strsec;
  207.       Elf64_Rela *rel, *relend;
  208.       Elf64_Sym *symtab;
  209.       const char *strtab;
  210.  
  211.       relsec = af->root.sections[i];
  212.       if (relsec->header.sh_type != SHT_RELA)
  213.     continue;
  214.  
  215.       symsec = af->root.sections[relsec->header.sh_link];
  216.       strsec = af->root.sections[symsec->header.sh_link];
  217.  
  218.       rel = (Elf64_Rela *)relsec->contents;
  219.       relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
  220.       symtab = (Elf64_Sym *)symsec->contents;
  221.       strtab = (const char *)strsec->contents;
  222.  
  223.       for (; rel < relend; ++rel)
  224.     {
  225.       struct alpha_got_entry *ent;
  226.       Elf64_Sym *extsym;
  227.       struct alpha_symbol *intsym;
  228.       const char *name;
  229.  
  230.       if (ELF64_R_TYPE(rel->r_info) != R_ALPHA_LITERAL)
  231.         continue;
  232.  
  233.       extsym = &symtab[ELF64_R_SYM(rel->r_info)];
  234.       if (extsym->st_name)
  235.         name = strtab + extsym->st_name;
  236.       else
  237.         name = f->sections[extsym->st_shndx]->name;
  238.       intsym = (struct alpha_symbol *)obj_find_symbol(&af->root, name);
  239.  
  240.       for (ent = intsym->got_entries; ent ; ent = ent->next)
  241.         if (ent->addend == rel->r_addend)
  242.           goto found;
  243.  
  244.       ent = xmalloc(sizeof(*ent));
  245.       ent->addend = rel->r_addend;
  246.       ent->offset = offset;
  247.       ent->reloc_done = 0;
  248.       ent->next = intsym->got_entries;
  249.       intsym->got_entries = ent;
  250.       offset += 8;
  251.  
  252.     found:;
  253.     }
  254.     }
  255.  
  256.   if (offset > 0x10000)
  257.     {
  258.       error(".got section overflow: %#x > 0x10000", offset);
  259.       return 0;
  260.     }
  261.  
  262.   /* We always want a .got section so that we always have a GP for
  263.      use with GPDISP and GPREL32 relocs.  Besides, if the section
  264.      is empty we don't use up space anyway.  */
  265.   af->got = obj_create_alloced_section(&af->root, ".got", 8, offset);
  266.  
  267.   return 1;
  268. }
  269.  
  270. int
  271. arch_init_module (struct obj_file *f, struct new_module *mod)
  272. {
  273.   struct alpha_file *af = (struct alpha_file *)f;
  274.  
  275.   mod->gp = af->got->header.sh_addr + 0x8000;
  276.  
  277.   return 1;
  278. }
  279.