Author: gonzo
Date: Sun Jan  8 05:44:19 2012
New Revision: 229803
URL: http://svn.freebsd.org/changeset/base/229803

Log:
  Fix relocations for MIPS64:
      - Use Elf32_Addr as default, the only field that is
          64 bitw wide is R_MIPS_64
      - Add R_MIPS_HIGHER and R_MIPS_HGHEST handlers
      - Handle R_MIPS_HI16 and R_MIPS_LO16 for both .rel and
          .rela sections

Modified:
  head/sys/mips/mips/elf_machdep.c

Modified: head/sys/mips/mips/elf_machdep.c
==============================================================================
--- head/sys/mips/mips/elf_machdep.c    Sun Jan  8 01:54:46 2012        
(r229802)
+++ head/sys/mips/mips/elf_machdep.c    Sun Jan  8 05:44:19 2012        
(r229803)
@@ -168,25 +168,41 @@ static int
 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
     int type, int local, elf_lookup_fn lookup)
 {
-       Elf_Addr *where = (Elf_Addr *)NULL;
+       Elf32_Addr *where = (Elf32_Addr *)NULL;
        Elf_Addr addr;
        Elf_Addr addend = (Elf_Addr)0;
        Elf_Word rtype = (Elf_Word)0, symidx;
-       const Elf_Rel *rel;
+       const Elf_Rel *rel = NULL;
+       const Elf_Rela *rela = NULL;
 
        /*
         * Stash R_MIPS_HI16 info so we can use it when processing R_MIPS_LO16
         */
        static Elf_Addr ahl;
-       static Elf_Addr *where_hi16;
+       static Elf32_Addr *where_hi16;
 
        switch (type) {
        case ELF_RELOC_REL:
                rel = (const Elf_Rel *)data;
-               where = (Elf_Addr *) (relocbase + rel->r_offset);
-               addend = *where;
+               where = (Elf32_Addr *) (relocbase + rel->r_offset);
                rtype = ELF_R_TYPE(rel->r_info);
                symidx = ELF_R_SYM(rel->r_info);
+               switch (rtype) {
+               case R_MIPS_64:
+                       addend = *(Elf64_Addr *)where;
+                       break;
+               default:
+                       addend = *where;
+                       break;
+               }
+
+               break;
+       case ELF_RELOC_RELA:
+               rela = (const Elf_Rela *)data;
+               where = (Elf32_Addr *) (relocbase + rela->r_offset);
+               addend = rela->r_addend;
+               rtype = ELF_R_TYPE(rela->r_info);
+               symidx = ELF_R_SYM(rela->r_info);
                break;
        default:
                panic("unknown reloc type %d\n", type);
@@ -202,7 +218,7 @@ elf_reloc_internal(linker_file_t lf, Elf
                        return (-1);
                addr += addend;
                if (*where != addr)
-                       *where = addr;
+                       *where = (Elf32_Addr)addr;
                break;
 
        case R_MIPS_26:         /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */
@@ -220,25 +236,73 @@ elf_reloc_internal(linker_file_t lf, Elf
                *where |= addr & 0x03ffffff;
                break;
 
+       case R_MIPS_64:         /* S + A */
+               addr = lookup(lf, symidx, 1);
+               if (addr == 0)
+                       return (-1);
+               addr += addend;
+               if (*(Elf64_Addr*)where != addr)
+                       *(Elf64_Addr*)where = addr;
+               break;
+
        case R_MIPS_HI16:       /* ((AHL + S) - ((short)(AHL + S)) >> 16 */
-               ahl = addend << 16;
-               where_hi16 = where;
+               if (rela != NULL) {
+                       addr = lookup(lf, symidx, 1);
+                       if (addr == 0)
+                               return (-1);
+                       addr += addend;
+                       *where &= 0xffff0000;
+                       *where |= ((((long long) addr + 0x8000LL) >> 16) & 
0xffff);
+               }
+               else {
+                       ahl = addend << 16;
+                       where_hi16 = where;
+               }
                break;
 
        case R_MIPS_LO16:       /* AHL + S */
-               ahl += (int16_t)addend;
+               if (rela != NULL) {
+                       addr = lookup(lf, symidx, 1);
+                       if (addr == 0)
+                               return (-1);
+                       addr += addend;
+                       *where &= 0xffff0000;
+                       *where |= addr & 0xffff;
+               }
+               else {
+                       ahl += (int16_t)addend;
+                       addr = lookup(lf, symidx, 1);
+                       if (addr == 0)
+                               return (-1);
+
+                       addend &= 0xffff0000;
+                       addend |= (uint16_t)(ahl + addr);
+                       *where = addend;
+
+                       addend = *where_hi16;
+                       addend &= 0xffff0000;
+                       addend |= ((ahl + addr) - (int16_t)(ahl + addr)) >> 16;
+                       *where_hi16 = addend;
+               }
+
+               break;
+
+       case R_MIPS_HIGHER:     /* %higher(A+S) */
                addr = lookup(lf, symidx, 1);
                if (addr == 0)
                        return (-1);
+               addr += addend;
+               *where &= 0xffff0000;
+               *where |= (((long long)addr + 0x80008000LL) >> 32) & 0xffff;
+               break;
 
-               addend &= 0xffff0000;
-               addend |= (uint16_t)(ahl + addr);
-               *where = addend;
-
-               addend = *where_hi16;
-               addend &= 0xffff0000;
-               addend |= ((ahl + addr) - (int16_t)(ahl + addr)) >> 16;
-               *where_hi16 = addend;
+       case R_MIPS_HIGHEST:    /* %highest(A+S) */
+               addr = lookup(lf, symidx, 1);
+               if (addr == 0)
+                       return (-1);
+               addr += addend;
+               *where &= 0xffff0000;
+               *where |= (((long long)addr + 0x800080008000LL) >> 48) & 0xffff;
                break;
 
        default:
@@ -246,6 +310,7 @@ elf_reloc_internal(linker_file_t lf, Elf
                        rtype);
                return (-1);
        }
+
        return(0);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to