/* Support for relocating static PIE.
Copyright (C) 2017-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
. */
#define IS_IN_rtld // force inline function calls
#include
#include
#include
#include
#if defined(__mips__) || defined(__xtensa__)
#include
#endif
extern ElfW(Addr) _dl_load_base;
void
reloc_static_pie (ElfW(Addr) load_addr);
void
reloc_static_pie(ElfW(Addr) load_addr)
{
int indx;
ElfW(Addr) got;
ElfW(Dyn) *dpnt;
struct elf_resolve tpnt_tmp;
struct elf_resolve *tpnt = &tpnt_tmp;
DL_BOOT_COMPUTE_GOT(got);
DL_BOOT_COMPUTE_DYN(dpnt, got, (DL_LOADADDR_TYPE)load_addr);
_dl_memset(tpnt, 0, sizeof(struct elf_resolve));
tpnt->loadaddr = load_addr;
tpnt->dynamic_addr = dpnt;
__dl_parse_dynamic_info(dpnt, tpnt->dynamic_info, NULL, load_addr);
#if defined(PERFORM_BOOTSTRAP_GOT)
/* some arches (like MIPS) we have to tweak the GOT before relocations */
PERFORM_BOOTSTRAP_GOT(tpnt);
#endif
#if !defined(__FDPIC__)
DL_RELOCATE_RELR(tpnt);
#endif
#if defined(ELF_MACHINE_PLTREL_OVERLAP)
# define INDX_MAX 1
#else
# define INDX_MAX 2
#endif
for (indx = 0; indx < INDX_MAX; indx++) {
unsigned long rel_addr, rel_size;
ElfW(Word) relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] :
tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]);
rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] :
tpnt->dynamic_info[DT_RELOC_TABLE_SIZE]);
if (!rel_addr)
continue;
if((0 == indx) && relative_count) {
rel_size -= relative_count * sizeof(ELF_RELOC);
elf_machine_relative(load_addr, rel_addr, relative_count);
rel_addr += relative_count * sizeof(ELF_RELOC);
}
#ifdef ARCH_NEEDS_BOOTSTRAP_RELOCS
{
ELF_RELOC *rpnt;
unsigned int i;
ElfW(Sym) *sym;
unsigned long symbol_addr;
int symtab_index;
unsigned long *reloc_addr;
/* Now parse the relocation information */
rpnt = (ELF_RELOC *) rel_addr;
for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
reloc_addr = (unsigned long *) DL_RELOC_ADDR(load_addr, (unsigned long)rpnt->r_offset);
symtab_index = ELF_R_SYM(rpnt->r_info);
symbol_addr = 0;
sym = NULL;
if (symtab_index) {
ElfW(Sym) *symtab;
symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
sym = &symtab[symtab_index];
symbol_addr = (unsigned long) DL_RELOC_ADDR(load_addr, sym->st_value);
}
/* Use this machine-specific macro to perform the actual relocation. */
PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, sym);
}
}
#endif
}
_dl_load_base = load_addr;
}