svn commit: r229803 - head/sys/mips/mips

Oleksandr Tymoshenko gonzo at FreeBSD.org
Sun Jan 8 05:44:20 UTC 2012


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);
 }
 


More information about the svn-src-all mailing list