FreeBSD/libexec/rtld-elf/amd64/reloc.c
/* Process the non-PLT relocations. */
Process the non-PLT relocations.
Process the non - PLT relocations .
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
    RtldLockState *lockstate)
{
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	SymCache *cache;
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr *where, symval;
	Elf32_Addr *where32;
	int r;
	r = -1;
	if (obj != obj_rtld) {
		cache = calloc(obj->dynsymcount, sizeof(SymCache));
	} else
		cache = NULL;
	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
	for (rela = obj->rela;  rela < relalim;  rela++) {
		switch (ELF_R_TYPE(rela->r_info)) {
		case R_X86_64_64:
		case R_X86_64_PC32:
		case R_X86_64_GLOB_DAT:
		case R_X86_64_TPOFF64:
		case R_X86_64_TPOFF32:
		case R_X86_64_DTPMOD64:
		case R_X86_64_DTPOFF64:
		case R_X86_64_DTPOFF32:
			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
			    &defobj, flags, cache, lockstate);
			if (def == NULL)
				goto done;
			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
				switch (ELF_R_TYPE(rela->r_info)) {
				case R_X86_64_64:
				case R_X86_64_PC32:
				case R_X86_64_GLOB_DAT:
					if ((flags & SYMLOOK_IFUNC) == 0) {
						obj->non_plt_gnu_ifunc = true;
						continue;
					}
					symval = (Elf_Addr)rtld_resolve_ifunc(
					    defobj, def);
					break;
				case R_X86_64_TPOFF64:
				case R_X86_64_TPOFF32:
				case R_X86_64_DTPMOD64:
				case R_X86_64_DTPOFF64:
				case R_X86_64_DTPOFF32:
					_rtld_error("%s: IFUNC for TLS reloc",
					    obj->path);
					goto done;
				}
			} else {
				if ((flags & SYMLOOK_IFUNC) != 0)
					continue;
				symval = (Elf_Addr)defobj->relocbase +
				    def->st_value;
			}
			break;
		default:
			if ((flags & SYMLOOK_IFUNC) != 0)
				continue;
			break;
		}
		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
		where32 = (Elf32_Addr *)where;
		switch (ELF_R_TYPE(rela->r_info)) {
		case R_X86_64_NONE:
			break;
		case R_X86_64_64:
			*where = symval + rela->r_addend;
			break;
		case R_X86_64_PC32:
			*where32 = (Elf32_Addr)(unsigned long)(symval +
		            rela->r_addend - (Elf_Addr)where);
			break;
		case R_X86_64_COPY:
			if (!obj->mainprog) {
				_rtld_error("%s: Unexpected R_X86_64_COPY "
				    "relocation in shared library", obj->path);
				goto done;
			}
			break;
		case R_X86_64_GLOB_DAT:
			*where = symval;
			break;
		case R_X86_64_TPOFF64:
			if (!defobj->tls_done) {
				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
					_rtld_error("%s: No space available "
					    "for static Thread Local Storage",
					    obj->path);
					goto done;
				}
			}
			*where = (Elf_Addr)(def->st_value - defobj->tlsoffset +
			    rela->r_addend);
			break;
		case R_X86_64_TPOFF32:
			if (!defobj->tls_done) {
				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
					_rtld_error("%s: No space available "
					    "for static Thread Local Storage",
					    obj->path);
					goto done;
				}
			}
			*where32 = (Elf32_Addr)(def->st_value -
			    defobj->tlsoffset + rela->r_addend);
			break;
		case R_X86_64_DTPMOD64:
			*where += (Elf_Addr)defobj->tlsindex;
			break;
		case R_X86_64_DTPOFF64:
			*where += (Elf_Addr)(def->st_value + rela->r_addend);
			break;
		case R_X86_64_DTPOFF32:
			*where32 += (Elf32_Addr)(def->st_value +
			    rela->r_addend);
			break;
		case R_X86_64_RELATIVE:
			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
			break;
		default:
			_rtld_error("%s: Unsupported relocation type %u"
			    " in non-PLT relocations\n", obj->path,
			    (unsigned int)ELF_R_TYPE(rela->r_info));
			goto done;
		}
	}
	r = 0;
done:
	free(cache);
	return (r);
}
int reloc_non_plt ( Obj_Entry * obj , Obj_Entry * obj_rtld , int flags , RtldLockState * lockstate ) { const Elf_Rela * relalim ; const Elf_Rela * rela ; SymCache * cache ; const Elf_Sym * def ; const Obj_Entry * defobj ; Elf_Addr * where , symval ; Elf32_Addr * where32 ; int r ; r = -1 ; if ( obj != obj_rtld ) { cache = calloc ( obj -> dynsymcount , sizeof ( SymCache ) ) ; } else cache = NULL ; relalim = ( const Elf_Rela * ) ( ( caddr_t ) obj -> rela + obj -> relasize ) ; for ( rela = obj -> rela ; rela < relalim ; rela ++ ) { switch ( ELF_R_TYPE ( rela -> r_info ) ) { case R_X86_64_64 : case R_X86_64_PC32 : case R_X86_64_GLOB_DAT : case R_X86_64_TPOFF64 : case R_X86_64_TPOFF32 : case R_X86_64_DTPMOD64 : case R_X86_64_DTPOFF64 : case R_X86_64_DTPOFF32 : def = find_symdef ( ELF_R_SYM ( rela -> r_info ) , obj , & defobj , flags , cache , lockstate ) ; if ( def == NULL ) goto done ; if ( ELF_ST_TYPE ( def -> st_info ) == STT_GNU_IFUNC ) { switch ( ELF_R_TYPE ( rela -> r_info ) ) { case R_X86_64_64 : case R_X86_64_PC32 : case R_X86_64_GLOB_DAT : if ( ( flags & SYMLOOK_IFUNC ) == 0 ) { obj -> non_plt_gnu_ifunc = true ; continue ; } symval = ( Elf_Addr ) rtld_resolve_ifunc ( defobj , def ) ; break ; case R_X86_64_TPOFF64 : case R_X86_64_TPOFF32 : case R_X86_64_DTPMOD64 : case R_X86_64_DTPOFF64 : case R_X86_64_DTPOFF32 : _rtld_error ( " " , obj -> path ) ; goto done ; } } else { if ( ( flags & SYMLOOK_IFUNC ) != 0 ) continue ; symval = ( Elf_Addr ) defobj -> relocbase + def -> st_value ; } break ; default : if ( ( flags & SYMLOOK_IFUNC ) != 0 ) continue ; break ; } where = ( Elf_Addr * ) ( obj -> relocbase + rela -> r_offset ) ; where32 = ( Elf32_Addr * ) where ; switch ( ELF_R_TYPE ( rela -> r_info ) ) { case R_X86_64_NONE : break ; case R_X86_64_64 : * where = symval + rela -> r_addend ; break ; case R_X86_64_PC32 : * where32 = ( Elf32_Addr ) ( unsigned long ) ( symval + rela -> r_addend - ( Elf_Addr ) where ) ; break ; case R_X86_64_COPY : if ( ! obj -> mainprog ) { _rtld_error ( " " " " , obj -> path ) ; goto done ; } break ; case R_X86_64_GLOB_DAT : * where = symval ; break ; case R_X86_64_TPOFF64 : if ( ! defobj -> tls_done ) { if ( ! allocate_tls_offset ( ( Obj_Entry * ) defobj ) ) { _rtld_error ( " " " " , obj -> path ) ; goto done ; } } * where = ( Elf_Addr ) ( def -> st_value - defobj -> tlsoffset + rela -> r_addend ) ; break ; case R_X86_64_TPOFF32 : if ( ! defobj -> tls_done ) { if ( ! allocate_tls_offset ( ( Obj_Entry * ) defobj ) ) { _rtld_error ( " " " " , obj -> path ) ; goto done ; } } * where32 = ( Elf32_Addr ) ( def -> st_value - defobj -> tlsoffset + rela -> r_addend ) ; break ; case R_X86_64_DTPMOD64 : * where += ( Elf_Addr ) defobj -> tlsindex ; break ; case R_X86_64_DTPOFF64 : * where += ( Elf_Addr ) ( def -> st_value + rela -> r_addend ) ; break ; case R_X86_64_DTPOFF32 : * where32 += ( Elf32_Addr ) ( def -> st_value + rela -> r_addend ) ; break ; case R_X86_64_RELATIVE : * where = ( Elf_Addr ) ( obj -> relocbase + rela -> r_addend ) ; break ; default : _rtld_error ( " " " \n " , obj -> path , ( unsigned int ) ELF_R_TYPE ( rela -> r_info ) ) ; goto done ; } } r = 0 ; done : free ( cache ) ; return ( r ) ; }
Process the non-PLT relocations.
Process the non - PLT relocations .
/*
	 * The dynamic loader may be called from a thread, we have
	 * limited amounts of stack available so we cannot use alloca().
	 */ /* No need to check for NULL here */ /*
		 * First, resolve symbol for relocations which
		 * reference symbols.
		 */ /*
			 * If symbol is IFUNC, only perform relocation
			 * when caller allowed it by passing
			 * SYMLOOK_IFUNC flag.  Skip the relocations
			 * otherwise.
			 *
			 * Also error out in case IFUNC relocations
			 * are specified for TLS, which cannot be
			 * usefully interpreted.
			 */ /*
			 * I don't think the dynamic linker should
			 * ever see this type of relocation.  But the
			 * binutils-2.6 tools sometimes generate it.
			 */ /* missing: R_X86_64_GOT32 R_X86_64_PLT32 */ /*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the COPY
			 * relocation is not in a shared library.  They are
			 * allowed only in executable files.
			 */ /*
			 * We lazily allocate offsets for static TLS
			 * as we see the first relocation that
			 * references the TLS block. This allows us to
			 * support (small amounts of) static TLS in
			 * dynamically loaded modules. If we run out
			 * of space, we generate an error.
			 */ /*
			 * We lazily allocate offsets for static TLS
			 * as we see the first relocation that
			 * references the TLS block. This allows us to
			 * support (small amounts of) static TLS in
			 * dynamically loaded modules. If we run out
			 * of space, we generate an error.
			 */ /*
		 * missing:
		 * R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16,
		 * R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8
		 */