Home | History | Annotate | Line # | Download | only in powerpc
ppc_reloc.c revision 1.65
      1 /*	$NetBSD: ppc_reloc.c,v 1.65 2024/08/03 21:59:58 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (C) 1998	Tsubai Masanari
      5  * Portions copyright 2002 Charles M. Hannum <root (at) ihack.net>
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * Power ELF relocations.
     33  *
     34  * Reference:
     35  *
     36  *	Power Architecture(R) 32-bit
     37  *	Application Binary Interface Supplement 1.0 - Linux(R)
     38  *	http://web.archive.org/web/20120608163845/https://www.power.org/resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Linux.pdf
     39  *
     40  *	64-bit PowerPC ELF Application Binary Interface Supplement 1.9
     41  *	https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf
     42  */
     43 
     44 #include <sys/cdefs.h>
     45 #ifndef lint
     46 __RCSID("$NetBSD: ppc_reloc.c,v 1.65 2024/08/03 21:59:58 riastradh Exp $");
     47 #endif /* not lint */
     48 
     49 #include <stdarg.h>
     50 #include <stdio.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 #include <sys/types.h>
     54 #include <machine/cpu.h>
     55 
     56 #include "debug.h"
     57 #include "rtld.h"
     58 
     59 void _rtld_powerpc_pltcall(Elf_Word);
     60 void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word);
     61 
     62 #define __u64(x)	((uint64_t)(x))
     63 #define __u32(x)	((uint32_t)(x))
     64 #define __ha48		__u64(0xffffffff8000)
     65 #define __ha32		__u64(0xffff8000)
     66 #define __ha16		__u32(0x8000)
     67 #define __ha(x,n) ((((x) >> (n)) + (((x) & __ha##n) == __ha##n)) & 0xffff)
     68 #define __hi(x,n) (((x) >> (n)) & 0xffff)
     69 #ifdef __LP64
     70 #define highesta(x)	__ha(__u64(x), 48)
     71 #define highest(x)	__hi(__u64(x), 48)
     72 #define higher(x)	__ha(__u64(x), 32)
     73 #define higher(x)	__hi(__u64(x), 32)
     74 #endif
     75 #define ha(x)		__ha(__u32(x), 16)
     76 #define hi(x)		__hi(__u32(x), 16)
     77 #define lo(x)		(__u32(x) & 0xffff)
     78 
     79 #ifdef _LP64
     80 /* function descriptor for _rtld_bind_start */
     81 extern const uint64_t _rtld_bind_start[3];
     82 #else
     83 void _rtld_bind_bssplt_start(void);
     84 void _rtld_bind_secureplt_start(void);
     85 #endif
     86 Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word);
     87 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
     88 static int _rtld_relocate_plt_object(const Obj_Entry *,
     89     const Elf_Rela *, int, Elf_Addr *);
     90 
     91 /*
     92  * The PPC32 PLT format consists of three sections:
     93  * (1) The "pltcall" and "pltresolve" glue code.  This is always 18 words.
     94  * (2) The code part of the PLT entries.  There are 2 words per entry for
     95  *     up to 8192 entries, then 4 words per entry for any additional entries.
     96  * (3) The data part of the PLT entries, comprising a jump table.
     97  *     This section is half the size of the second section (ie. 1 or 2 words
     98  *     per entry).
     99  */
    100 
    101 void
    102 _rtld_setup_pltgot(const Obj_Entry *obj)
    103 {
    104 #ifdef _LP64
    105 	/*
    106 	 * For powerpc64, just copy the function descriptor to pltgot[0].
    107 	 */
    108 	if (obj->pltgot != NULL) {
    109 		obj->pltgot[0] = (Elf_Addr) _rtld_bind_start[0];
    110 		obj->pltgot[1] = (Elf_Addr) _rtld_bind_start[1];
    111 		obj->pltgot[2] = (Elf_Addr) obj;
    112 	}
    113 #else
    114 	/*
    115 	 * Secure-PLT is much more sane.
    116 	 */
    117 	if (obj->gotptr != NULL) {
    118 		obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
    119 		obj->gotptr[2] = (Elf_Addr) obj;
    120 		dbg(("obj %s secure-plt gotptr=%p start=%p obj=%p",
    121 		    obj->path, obj->gotptr,
    122 		    (void *) obj->gotptr[1], (void *) obj->gotptr[2]));
    123 	} else {
    124 /*
    125  * Setup the plt glue routines (for bss-plt).
    126  */
    127 #define BSSPLTCALL_SIZE		20
    128 #define BSSPLTRESOLVE_SIZE	24
    129 
    130 		Elf_Word *pltcall, *pltresolve;
    131 		Elf_Word *jmptab;
    132 		int N = obj->pltrelalim - obj->pltrela;
    133 
    134 		/* Entries beyond 8192 take twice as much space. */
    135 		if (N > 8192)
    136 			N += N-8192;
    137 
    138 		dbg(("obj %s bss-plt pltgot=%p jmptab=%u start=%p obj=%p",
    139 		    obj->path, obj->pltgot, 18 + N * 2,
    140 		    _rtld_bind_bssplt_start, obj));
    141 
    142 		pltcall = obj->pltgot;
    143 		jmptab = pltcall + 18 + N * 2;
    144 
    145 		memcpy(pltcall, _rtld_powerpc_pltcall, BSSPLTCALL_SIZE);
    146 		pltcall[1] |= ha(jmptab);
    147 		pltcall[2] |= lo(jmptab);
    148 
    149 		pltresolve = obj->pltgot + 8;
    150 
    151 		memcpy(pltresolve, _rtld_powerpc_pltresolve, BSSPLTRESOLVE_SIZE);
    152 		pltresolve[0] |= ha(_rtld_bind_bssplt_start);
    153 		pltresolve[1] |= lo(_rtld_bind_bssplt_start);
    154 		pltresolve[3] |= ha(obj);
    155 		pltresolve[4] |= lo(obj);
    156 
    157 		/*
    158 		 * Invalidate the icache for only the code part of the PLT
    159 		 * (and not the jump table at the end).
    160 		 */
    161 		__syncicache(pltcall, (char *)jmptab - (char *)pltcall);
    162 	}
    163 #endif
    164 }
    165 
    166 void
    167 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
    168 {
    169 	const Elf_Rela *rela = 0, *relalim;
    170 	Elf_Addr relasz = 0;
    171 	Elf_Addr *where;
    172 
    173 	for (; dynp->d_tag != DT_NULL; dynp++) {
    174 		switch (dynp->d_tag) {
    175 		case DT_RELA:
    176 			rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
    177 			break;
    178 		case DT_RELASZ:
    179 			relasz = dynp->d_un.d_val;
    180 			break;
    181 		}
    182 	}
    183 	relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
    184 	for (; rela < relalim; rela++) {
    185 		where = (Elf_Addr *)(relocbase + rela->r_offset);
    186 		*where = (Elf_Addr)(relocbase + rela->r_addend);
    187 	}
    188 }
    189 
    190 int
    191 _rtld_relocate_nonplt_objects(Obj_Entry *obj)
    192 {
    193 	const Elf_Rela *rela;
    194 	const Elf_Sym *def = NULL;
    195 	const Obj_Entry *defobj = NULL;
    196 	unsigned long last_symnum = ULONG_MAX;
    197 
    198 	for (rela = obj->rela; rela < obj->relalim; rela++) {
    199 		Elf_Addr        *where;
    200 		Elf_Addr         tmp;
    201 		unsigned long	 symnum;
    202 
    203 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
    204 		symnum = ELF_R_SYM(rela->r_info);
    205 
    206 		switch (ELF_R_TYPE(rela->r_info)) {
    207 #ifdef _LP64
    208 		case R_TYPE(ADDR64):	/* <address> S + A */
    209 #else
    210 		case R_TYPE(ADDR32):	/* <address> S + A */
    211 		case R_TYPE(UADDR32):	/* <address> S + A */
    212 #endif
    213 		case R_TYPE(GLOB_DAT):	/* <address> S + A */
    214 		case R_TYPE(ADDR16_LO):
    215 		case R_TYPE(ADDR16_HI):
    216 		case R_TYPE(ADDR16_HA):
    217 		case R_TYPE(DTPMOD):
    218 		case R_TYPE(DTPREL):
    219 		case R_TYPE(TPREL):
    220 			if (last_symnum != symnum) {
    221 				last_symnum = symnum;
    222 				def = _rtld_find_symdef(symnum, obj, &defobj,
    223 				    false);
    224 				if (def == NULL)
    225 					return -1;
    226 			}
    227 			break;
    228 		default:
    229 			break;
    230 		}
    231 
    232 		switch (ELF_R_TYPE(rela->r_info)) {
    233 #if 1 /* XXX Should not be necessary. */
    234 		case R_TYPE(JMP_SLOT):
    235 #endif
    236 		case R_TYPE(NONE):
    237 			break;
    238 
    239 #ifdef _LP64
    240 		case R_TYPE(ADDR64):	/* <address> S + A */
    241 #else
    242 		case R_TYPE(ADDR32):	/* <address> S + A */
    243 		case R_TYPE(UADDR32):	/* <address> S + A */
    244 #endif
    245 		case R_TYPE(GLOB_DAT):	/* <address> S + A */
    246 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
    247 			    rela->r_addend);
    248 			if (*where != tmp)
    249 				*where = tmp;
    250 			rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
    251 			    obj->strtab + obj->symtab[symnum].st_name,
    252 			    obj->path, (void *)*where, defobj->path));
    253 			break;
    254 
    255 		/*
    256 		 * Recent GNU ld does not resolve ADDR16_{LO,HI,HA} if
    257 		 * the reloc is in a writable section and the symbol
    258 		 * is not already referenced from text.
    259 		 */
    260 		case R_TYPE(ADDR16_LO): {
    261 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
    262 			    rela->r_addend);
    263 
    264 			uint16_t tmp16 = lo(tmp);
    265 
    266 			uint16_t *where16 = (uint16_t *)where;
    267 			if (*where16 != tmp16)
    268 				*where16 = tmp16;
    269 			rdbg(("ADDR16_LO %s in %s --> #lo(%p) = 0x%x in %s",
    270 			    obj->strtab + obj->symtab[symnum].st_name,
    271 			      obj->path, (void *)tmp, tmp16, defobj->path));
    272 			break;
    273 		}
    274 
    275 		case R_TYPE(ADDR16_HI):
    276 		case R_TYPE(ADDR16_HA): {
    277 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
    278 			    rela->r_addend);
    279 
    280 			uint16_t tmp16 = hi(tmp);
    281 			if (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HA)
    282 			    && (tmp & __ha16))
    283 				++tmp16; /* adjust to ha(tmp) */
    284 
    285 			uint16_t *where16 = (uint16_t *)where;
    286 			if (*where16 != tmp16)
    287 				*where16 = tmp16;
    288 			rdbg(("ADDR16_H%c %s in %s --> #h%c(%p) = 0x%x in %s",
    289 			      (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI)
    290 			           ? 'I' : 'A'),
    291 			      obj->strtab + obj->symtab[symnum].st_name,
    292 			      obj->path,
    293 			      (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI)
    294 			           ? 'i' : 'a'),
    295 			      (void *)tmp, tmp16, defobj->path));
    296 			break;
    297 		}
    298 
    299 		case R_TYPE(RELATIVE):	/* <address> B + A */
    300 			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
    301 			rdbg(("RELATIVE in %s --> %p", obj->path,
    302 			    (void *)*where));
    303 			break;
    304 
    305 		case R_TYPE(COPY):
    306 			/*
    307 			 * These are deferred until all other relocations have
    308 			 * been done.  All we do here is make sure that the
    309 			 * COPY relocation is not in a shared library.  They
    310 			 * are allowed only in executable files.
    311 			 */
    312 			if (obj->isdynamic) {
    313 				_rtld_error(
    314 			"%s: Unexpected R_COPY relocation in shared library",
    315 				    obj->path);
    316 				return -1;
    317 			}
    318 			rdbg(("COPY (avoid in main)"));
    319 			break;
    320 
    321 		case R_TYPE(DTPMOD):
    322 			*where = (Elf_Addr)defobj->tlsindex;
    323 			rdbg(("DTPMOD32 %s in %s --> %p in %s",
    324 			    obj->strtab + obj->symtab[symnum].st_name,
    325 			    obj->path, (void *)*where, defobj->path));
    326 			break;
    327 
    328 		case R_TYPE(DTPREL):
    329 			*where = (Elf_Addr)(def->st_value + rela->r_addend
    330 			    - TLS_DTV_OFFSET);
    331 			rdbg(("DTPREL32 %s in %s --> %p in %s",
    332 			    obj->strtab + obj->symtab[symnum].st_name,
    333 			    obj->path, (void *)*where, defobj->path));
    334 			break;
    335 
    336 		case R_TYPE(TPREL):
    337 			if (!defobj->tls_static &&
    338 			    _rtld_tls_offset_allocate(__UNCONST(defobj)))
    339 				return -1;
    340 
    341 			*where = (Elf_Addr)(def->st_value + rela->r_addend
    342 			    + defobj->tlsoffset - TLS_TP_OFFSET);
    343 			rdbg(("TPREL32 %s in %s --> %p in %s",
    344 			    obj->strtab + obj->symtab[symnum].st_name,
    345 			    obj->path, (void *)*where, defobj->path));
    346 			break;
    347 
    348 		case R_TYPE(IRELATIVE):
    349 			/* IFUNC relocations are handled in _rtld_call_ifunc */
    350 			if (obj->ifunc_remaining_nonplt == 0) {
    351 				obj->ifunc_remaining_nonplt =
    352 				    obj->relalim - rela;
    353 			}
    354 			break;
    355 
    356 		default:
    357 			rdbg(("sym = %lu, type = %lu, offset = %p, "
    358 			    "addend = %p, contents = %p, symbol = %s",
    359 			    (u_long)ELF_R_SYM(rela->r_info),
    360 			    (u_long)ELF_R_TYPE(rela->r_info),
    361 			    (void *)rela->r_offset, (void *)rela->r_addend,
    362 			    (void *)*where,
    363 			    obj->strtab + obj->symtab[symnum].st_name));
    364 			_rtld_error("%s: Unsupported relocation type %ld "
    365 			    "in non-PLT relocations",
    366 			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
    367 			return -1;
    368 		}
    369 	}
    370 	return 0;
    371 }
    372 
    373 int
    374 _rtld_relocate_plt_lazy(Obj_Entry *obj)
    375 {
    376 #ifdef _LP64
    377 	/*
    378 	 * For PowerPC64, the plt stubs handle an empty function descriptor
    379 	 * so there's nothing to do.
    380 	 */
    381 	/* XXX ifunc support */
    382 #else
    383 	Elf_Addr * const pltresolve = obj->pltgot + 8;
    384 	const Elf_Rela *rela;
    385 
    386 	for (rela = obj->pltrelalim; rela-- > obj->pltrela;) {
    387 		size_t reloff = rela - obj->pltrela;
    388 		Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
    389 
    390 		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT) ||
    391 		       ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE));
    392 
    393 		if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) {
    394 			/* No ifunc support for old-style insecure PLT. */
    395 			assert(obj->gotptr != NULL);
    396 			obj->ifunc_remaining = obj->pltrelalim - rela;
    397 		}
    398 
    399 		if (obj->gotptr != NULL) {
    400 			/*
    401 			 * For now, simply treat then as relative.
    402 			 */
    403 			*where += (Elf_Addr)obj->relocbase;
    404 		} else {
    405 			int distance;
    406 
    407 			if (reloff < 32768) {
    408 				/* li	r11,reloff */
    409 				*where++ = 0x39600000 | reloff;
    410 			} else {
    411 				/* lis  r11,ha(reloff) */
    412 				/* addi	r11,lo(reloff) */
    413 				*where++ = 0x3d600000 | ha(reloff);
    414 				*where++ = 0x396b0000 | lo(reloff);
    415 			}
    416 			/* b	pltresolve */
    417 			distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
    418 			*where++ = 0x48000000 | (distance & 0x03fffffc);
    419 
    420 			/*
    421 			 * Icache invalidation is not done for each entry here
    422 			 * because we sync the entire code part of the PLT once
    423 			 * in _rtld_setup_pltgot() after all the entries have been
    424 			 * initialized.
    425 			 */
    426 			/* __syncicache(where - 3, 12); */
    427 		}
    428 	}
    429 #endif /* !_LP64 */
    430 
    431 	return 0;
    432 }
    433 
    434 static int
    435 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp)
    436 {
    437 	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
    438 	Elf_Addr value;
    439 	const Elf_Sym *def;
    440 	const Obj_Entry *defobj;
    441 	unsigned long info = rela->r_info;
    442 
    443 	assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
    444 
    445 	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
    446 	if (__predict_false(def == NULL))
    447 		return -1;
    448 	if (__predict_false(def == &_rtld_sym_zero))
    449 		return 0;
    450 
    451 	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
    452 		if (tp == NULL)
    453 			return 0;
    454 		value = _rtld_resolve_ifunc(defobj, def);
    455 	} else {
    456 		value = (Elf_Addr)(defobj->relocbase + def->st_value);
    457 	}
    458 	rdbg(("bind now/fixup in %s --> new=%p",
    459 	    defobj->strtab + def->st_name, (void *)value));
    460 
    461 #ifdef _LP64
    462 	/*
    463 	 * For PowerPC64 we simply replace the function descriptor in the
    464 	 * PLTGOT with the one from source object.
    465 	 */
    466 	assert(where >= (Elf_Word *)obj->pltgot);
    467 	assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
    468 	const Elf_Addr * const fdesc = (Elf_Addr *) value;
    469 	where[0] = fdesc[0];
    470 	where[1] = fdesc[1];
    471 	where[2] = fdesc[2];
    472 #else
    473 	ptrdiff_t distance = value - (Elf_Addr)where;
    474 	if (obj->gotptr != NULL) {
    475 		/*
    476 		 * For Secure-PLT we simply replace the entry in GOT with the
    477 		 * address of the routine.
    478 		 */
    479 		assert(where >= (Elf_Word *)obj->pltgot);
    480 		assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
    481 		*where = value;
    482 	} else if (labs(distance) < 32*1024*1024) {	/* inside 32MB? */
    483 		/* b	value	# branch directly */
    484 		*where = 0x48000000 | (distance & 0x03fffffc);
    485 		__syncicache(where, 4);
    486 	} else {
    487 		Elf_Addr *pltcall, *jmptab;
    488 		int N = obj->pltrelalim - obj->pltrela;
    489 
    490 		/* Entries beyond 8192 take twice as much space. */
    491 		if (N > 8192)
    492 			N += N-8192;
    493 
    494 		pltcall = obj->pltgot;
    495 		jmptab = pltcall + 18 + N * 2;
    496 
    497 		jmptab[reloff] = value;
    498 
    499 		if (reloff < 32768) {
    500 			/* li	r11,reloff */
    501 			*where++ = 0x39600000 | reloff;
    502 		} else {
    503 #ifdef notyet
    504 			/* lis  r11,ha(value) */
    505 			/* addi	r11,lo(value) */
    506 			/* mtctr r11 */
    507 			/* bctr */
    508 			*where++ = 0x3d600000 | ha(value);
    509 			*where++ = 0x396b0000 | lo(value);
    510 			*where++ = 0x7d6903a6;
    511 			*where++ = 0x4e800420;
    512 #else
    513 			/* lis  r11,ha(reloff) */
    514 			/* addi	r11,lo(reloff) */
    515 			*where++ = 0x3d600000 | ha(reloff);
    516 			*where++ = 0x396b0000 | lo(reloff);
    517 #endif
    518 		}
    519 		/* b	pltcall	*/
    520 		distance = (Elf_Addr)pltcall - (Elf_Addr)where;
    521 		*where++ = 0x48000000 | (distance & 0x03fffffc);
    522 		__syncicache(where - 3, 12);
    523 	}
    524 #endif /* _LP64 */
    525 
    526 	if (tp)
    527 		*tp = value;
    528 	return 0;
    529 }
    530 
    531 Elf_Addr
    532 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
    533 {
    534 	const Elf_Rela *rela = obj->pltrela + reloff;
    535 	Elf_Addr new_value;
    536 	int err;
    537 
    538 	new_value = 0;	/* XXX gcc */
    539 
    540 	_rtld_shared_enter();
    541 	err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value);
    542 	if (err)
    543 		_rtld_die();
    544 	_rtld_shared_exit();
    545 
    546 #ifdef _LP64
    547 	return obj->glink;
    548 #else
    549 	return new_value;
    550 #endif
    551 }
    552 
    553 int
    554 _rtld_relocate_plt_objects(const Obj_Entry *obj)
    555 {
    556 	const Elf_Rela *rela;
    557 	int reloff;
    558 
    559 	for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) {
    560 		if (_rtld_relocate_plt_object(obj, rela, reloff, NULL) < 0)
    561 			return -1;
    562 	}
    563 	return 0;
    564 }
    565