FreeBSD/sys/amd64/amd64/elf_machdep.c
/* Process one elf relocation with addend. */
Process one elf relocation with addend.
Process one elf relocation with addend .
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
    int type, int local, elf_lookup_fn lookup)
{
	Elf64_Addr *where, val;
	Elf32_Addr *where32, val32;
	Elf_Addr addr;
	Elf_Addr addend;
	Elf_Size rtype, symidx;
	const Elf_Rel *rel;
	const Elf_Rela *rela;
	int error;
	switch (type) {
	case ELF_RELOC_REL:
		rel = (const Elf_Rel *)data;
		where = (Elf_Addr *) (relocbase + rel->r_offset);
		rtype = ELF_R_TYPE(rel->r_info);
		symidx = ELF_R_SYM(rel->r_info);
		switch (rtype) {
		case R_X86_64_PC32:
		case R_X86_64_32S:
			addend = *(Elf32_Addr *)where;
			break;
		default:
			addend = *where;
			break;
		}
		break;
	case ELF_RELOC_RELA:
		rela = (const Elf_Rela *)data;
		where = (Elf_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);
	}
	switch (rtype) {
		case R_X86_64_NONE:	
			break;
		case R_X86_64_64:		
			error = lookup(lf, symidx, 1, &addr);
			val = addr + addend;
			if (error != 0)
				return -1;
			if (*where != val)
				*where = val;
			break;
		case R_X86_64_PC32:	
			error = lookup(lf, symidx, 1, &addr);
			where32 = (Elf32_Addr *)where;
			val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where);
			if (error != 0)
				return -1;
			if (*where32 != val32)
				*where32 = val32;
			break;
		case R_X86_64_32S:	
			error = lookup(lf, symidx, 1, &addr);
			val32 = (Elf32_Addr)(addr + addend);
			where32 = (Elf32_Addr *)where;
			if (error != 0)
				return -1;
			if (*where32 != val32)
				*where32 = val32;
			break;
		case R_X86_64_COPY:	
			printf("kldload: unexpected R_COPY relocation\n");
			return -1;
			break;
		case R_X86_64_GLOB_DAT:	
		case R_X86_64_JMP_SLOT:	
			error = lookup(lf, symidx, 1, &addr);
			if (error != 0)
				return -1;
			if (*where != addr)
				*where = addr;
			break;
		case R_X86_64_RELATIVE:	
			addr = relocbase + addend;
			val = addr;
			if (*where != val)
				*where = val;
			break;
		default:
			printf("kldload: unexpected relocation type %ld\n",
			       rtype);
			return -1;
	}
	return(0);
}
static int elf_reloc_internal ( linker_file_t lf , Elf_Addr relocbase , const void * data , int type , int local , elf_lookup_fn lookup ) { Elf64_Addr * where , val ; Elf32_Addr * where32 , val32 ; Elf_Addr addr ; Elf_Addr addend ; Elf_Size rtype , symidx ; const Elf_Rel * rel ; const Elf_Rela * rela ; int error ; switch ( type ) { case ELF_RELOC_REL : rel = ( const Elf_Rel * ) data ; where = ( Elf_Addr * ) ( relocbase + rel -> r_offset ) ; rtype = ELF_R_TYPE ( rel -> r_info ) ; symidx = ELF_R_SYM ( rel -> r_info ) ; switch ( rtype ) { case R_X86_64_PC32 : case R_X86_64_32S : addend = * ( Elf32_Addr * ) where ; break ; default : addend = * where ; break ; } break ; case ELF_RELOC_RELA : rela = ( const Elf_Rela * ) data ; where = ( Elf_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 ( " \n " , type ) ; } switch ( rtype ) { case R_X86_64_NONE : break ; case R_X86_64_64 : error = lookup ( lf , symidx , 1 , & addr ) ; val = addr + addend ; if ( error != 0 ) return -1 ; if ( * where != val ) * where = val ; break ; case R_X86_64_PC32 : error = lookup ( lf , symidx , 1 , & addr ) ; where32 = ( Elf32_Addr * ) where ; val32 = ( Elf32_Addr ) ( addr + addend - ( Elf_Addr ) where ) ; if ( error != 0 ) return -1 ; if ( * where32 != val32 ) * where32 = val32 ; break ; case R_X86_64_32S : error = lookup ( lf , symidx , 1 , & addr ) ; val32 = ( Elf32_Addr ) ( addr + addend ) ; where32 = ( Elf32_Addr * ) where ; if ( error != 0 ) return -1 ; if ( * where32 != val32 ) * where32 = val32 ; break ; case R_X86_64_COPY : printf ( " \n " ) ; return -1 ; break ; case R_X86_64_GLOB_DAT : case R_X86_64_JMP_SLOT : error = lookup ( lf , symidx , 1 , & addr ) ; if ( error != 0 ) return -1 ; if ( * where != addr ) * where = addr ; break ; case R_X86_64_RELATIVE : addr = relocbase + addend ; val = addr ; if ( * where != val ) * where = val ; break ; default : printf ( " \n " , rtype ) ; return -1 ; } return ( 0 ) ; }
Process one elf relocation with addend.
Process one elf relocation with addend .
/* Addend is 32 bit on 32 bit relocs */ /* none */ /* S + A */ /* S + A - P */ /* S + A sign extend */ /* none */ /*
			 * There shouldn't be copy relocations in kernel
			 * objects.
			 */ /* S */ /* XXX need addend + offset */ /* B + A */