diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index a107da6b0a6a..1abca263497b 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -168,11 +168,13 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) */ static int reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, - const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) + const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate, + Elf_Addr **wherep) { const Elf_Sym *def = NULL; const Obj_Entry *defobj; - Elf_Addr *where, symval = 0; + Elf_Addr symval = 0; + Elf_Addr *where; /* * First, resolve symbol for relocations which @@ -235,6 +237,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, switch (ELF_R_TYPE(rela->r_info)) { case R_PPC_NONE: + *wherep = NULL; break; case R_PPC64_UADDR64: case R_PPC64_ADDR64: @@ -243,9 +246,11 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, if (*where != symval + rela->r_addend) { *where = symval + rela->r_addend; } + *wherep = where; break; case R_PPC64_DTPMOD64: *where = (Elf_Addr) defobj->tlsindex; + *wherep = where; break; case R_PPC64_TPREL64: /* @@ -268,10 +273,12 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, *(Elf_Addr **)where = *where * sizeof(Elf_Addr) + (Elf_Addr *)(def->st_value + rela->r_addend + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); + *wherep = where; break; case R_PPC64_DTPREL64: *where += (Elf_Addr)(def->st_value + rela->r_addend - TLS_DTV_OFFSET); + *wherep = where; break; case R_PPC_RELATIVE: /* doubleword64 B + A */ symval = (Elf_Addr)(obj->relocbase + rela->r_addend); @@ -280,6 +287,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, if (*where != symval) { *where = symval; } + *wherep = where; break; case R_PPC_COPY: /* @@ -295,17 +303,20 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, obj->path); return (-1); } + *wherep = NULL; break; case R_PPC_IRELATIVE: /* * These will be handled by reloc_iresolve(). */ obj->irelative = true; + *wherep = NULL; break; case R_PPC_JMP_SLOT: /* * These will be handled by the plt/jmpslot routines */ + *wherep = NULL; break; default: @@ -314,9 +325,37 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, ELF_R_TYPE(rela->r_info)); return (-1); } + *wherep = where; return (0); } +static void +phdr_syncicache(Obj_Entry *obj, const Elf_Phdr *phdr) +{ + if ((phdr->p_flags & PF_X) != 0) + __syncicache(obj->relocbase + phdr->p_vaddr, phdr->p_memsz); +} + +static bool +is_addr_in_phdr(Obj_Entry *obj, const Elf_Phdr *phdr, Elf_Addr addr) +{ + return (obj->relocbase + phdr->p_vaddr >= (caddr_t) addr && + (caddr_t) addr < obj->relocbase + phdr->p_vaddr + phdr->p_memsz); +} + +static const Elf_Phdr * +find_phdr_from_addr(Obj_Entry *obj, Elf_Addr addr) +{ + const Elf_Phdr *phdr = NULL; + size_t c; + + for (c = 0, phdr = obj->phdr; c < obj->phnum; c--, phdr++) { + if (phdr->p_type == PT_LOAD && + is_addr_in_phdr(obj, phdr, addr)) + return (phdr); + } + return (NULL); +} /* * Process non-PLT relocations @@ -327,7 +366,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, { const Elf_Rela *relalim; const Elf_Rela *rela; - const Elf_Phdr *phdr; + const Elf_Phdr *phdr = NULL; + Elf_Addr *where; SymCache *cache; int bytes = obj->dynsymcount * sizeof(SymCache); int r = -1; @@ -352,11 +392,24 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); for (rela = obj->rela; rela < relalim; rela++) { if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, - lockstate) < 0) + lockstate, &where) < 0) goto done; + if (where != NULL) { + if (phdr != NULL && + !is_addr_in_phdr(obj, phdr, (Elf_Addr)where)) { + phdr_syncicache(obj, phdr); + phdr = NULL; + } + if (phdr == NULL) { + phdr = find_phdr_from_addr(obj, + (Elf_Addr)where); + } + } } r = 0; done: + if (phdr != NULL) + phdr_syncicache(obj, phdr); if (cache) munmap(cache, bytes); @@ -366,8 +419,6 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, */ for (phdr = obj->phdr; phdr < obj->phdr + obj->phnum; phdr++) { if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) { - __syncicache(obj->relocbase + phdr->p_vaddr, - phdr->p_memsz); } }