int _dl_md_reloc_got(elf_object_t *object, int lazy) { extern void _dl_bind_start(void); /* XXX */ int fails = 0; Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; int i, num; Elf_RelA *rel; if (pltgot == NULL) return (0); /* it is possible to have no PLT/GOT relocations */ if (object->Dyn.info[DT_PLTREL] != DT_RELA) return (0); if (object->traced) lazy = 1; if (__predict_false(!lazy)) { fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); } else { pltgot[1] = (Elf_Addr)object; pltgot[2] = (Elf_Addr)&_dl_bind_start; rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); num = (object->Dyn.info[DT_PLTRELSZ]); for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { Elf_Addr *where; where = (Elf_Addr *)(rel->r_offset + object->obj_base); *where += object->obj_base; } } /* mprotect the GOT */ _dl_protect_segment(object, 0, "__got_start", "__got_end", PROT_READ); return (fails); }
/* * Relocate the Global Offset Table (GOT). */ int _dl_md_reloc_got(elf_object_t *object, int lazy) { int fails = 0; Elf_Addr *pltgot; extern void _dl_bind_start(void); /* XXX */ Elf_Addr ooff; Elf_Addr plt_addr; const Elf_Sym *this; pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; object->got_addr = 0; object->got_size = 0; this = NULL; ooff = _dl_find_symbol("__got_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->got_addr = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__got_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->got_size = ooff + this->st_value - object->got_addr; plt_addr = 0; object->plt_size = 0; this = NULL; ooff = _dl_find_symbol("__plt_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) plt_addr = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__plt_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->plt_size = ooff + this->st_value - plt_addr; if (object->got_addr == 0) object->got_start = 0; else { object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); object->got_size += object->got_addr - object->got_start; object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); } if (plt_addr == 0) object->plt_start = 0; else { object->plt_start = ELF_TRUNC(plt_addr, _dl_pagesz); object->plt_size += plt_addr - object->plt_start; object->plt_size = ELF_ROUND(object->plt_size, _dl_pagesz); } if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) { fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); } else { if (object->obj_base != 0) { int i, size; Elf_Addr *addr; Elf_RelA *rela; size = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA); rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); for (i = 0; i < size; i++) { addr = (Elf_Addr *)(object->obj_base + rela[i].r_offset); *addr += object->obj_base; } } } if (pltgot != NULL) { pltgot[2] = (Elf_Addr)_dl_bind_start; pltgot[3] = (Elf_Addr)object; } if (object->got_size != 0) _dl_mprotect((void*)object->got_start, object->got_size, PROT_READ); if (object->plt_size != 0) _dl_mprotect((void*)object->plt_start, object->plt_size, PROT_READ|PROT_EXEC); return (fails); }
int _dl_md_reloc_got(elf_object_t *object, int lazy) { Elf_RelA *rela; Elf_Addr ooff; int i, numrela, fails = 0; const Elf_Sym *this; if (object->dyn.pltrel != DT_RELA) return (0); object->got_addr = 0; object->got_size = 0; this = NULL; ooff = _dl_find_symbol("__got_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL ); if (this != NULL) object->got_addr = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__got_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->got_size = ooff + this->st_value - object->got_addr; if (object->got_addr == 0) object->got_start = 0; else { object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); object->got_size += object->got_addr - object->got_start; object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); } if (object->traced) lazy = 1; if (!lazy) { fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); } else { register Elf_Addr ltp __asm ("%r19"); Elf_Addr *got = NULL; rela = (Elf_RelA *)(object->dyn.jmprel); numrela = object->dyn.pltrelsz / sizeof(Elf_RelA); ooff = object->obj_base; /* * Find the PLT stub by looking at all the * relocations. The PLT stub should be at the end of * the .plt section so we start with the last * relocation, since the linker should have emitted * them in order. */ for (i = numrela - 1; i >= 0; i--) { got = (Elf_Addr *)(ooff + rela[i].r_offset + PLT_ENTRY_SIZE + PLT_STUB_SIZE); if (got[-2] == PLT_STUB_MAGIC1 || got[-1] == PLT_STUB_MAGIC2) break; got = NULL; } if (got == NULL) return (1); /* * Patch up the PLT stub such that it doesn't clobber * %r22, which is used to pass on the errno values * from failed system calls to __cerrno() in libc. */ got[-7] = PLT_STUB_INSN1; got[-6] = PLT_STUB_INSN2; __asm volatile("fdc 0(%0)" :: "r" (&got[-7])); __asm volatile("fdc 0(%0)" :: "r" (&got[-6])); __asm volatile("sync"); __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-7])); __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-6])); __asm volatile("sync"); /* * Fill in the PLT stub such that it invokes the * _dl_bind_start() trampoline to fix up the * relocation. */ got[1] = (Elf_Addr)object; got[-2] = (Elf_Addr)&_dl_bind_start; got[-1] = ltp; /* * Even though we didn't modify any instructions it * seems we still need to syncronize the caches. * There may be instructions in the same cache line * and they end up being corrupted otherwise. */ __asm volatile("fdc 0(%0)" :: "r" (&got[-2])); __asm volatile("fdc 0(%0)" :: "r" (&got[-1])); __asm volatile("sync"); __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-2])); __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-1])); __asm volatile("sync"); for (i = 0; i < numrela; i++, rela++) { Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset); if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) { _dl_printf("unexpected reloc 0x%x\n", ELF_R_TYPE(rela->r_info)); return (1); } if (ELF_R_SYM(rela->r_info)) { r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF; r_addr[1] = (Elf_Addr) (rela - (Elf_RelA *)object->dyn.jmprel); } else { r_addr[0] = ooff + rela->r_addend; r_addr[1] = (Elf_Addr)object->dyn.pltgot; } } } if (object->got_size != 0) _dl_mprotect((void *)object->got_start, object->got_size, GOT_PERMS|PROT_EXEC); return (fails); }
/* * Relocate the Global Offset Table (GOT). * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, * otherwise the lazy binding plt initialization is performed. */ int _dl_md_reloc_got(elf_object_t *object, int lazy) { extern void _dl_bind_start(void); /* XXX */ int fails = 0; Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; Elf_Addr ooff; const Elf_Sym *this; if (pltgot == NULL) return (0); pltgot[1] = (Elf_Addr)object; pltgot[2] = (Elf_Addr)_dl_bind_start; if (object->Dyn.info[DT_PLTREL] != DT_RELA) return (0); object->got_addr = 0; object->got_size = 0; this = NULL; ooff = _dl_find_symbol("__got_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->got_addr = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__got_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->got_size = ooff + this->st_value - object->got_addr; #if 0 plt_addr = 0; object->plt_size = 0; this = NULL; ooff = _dl_find_symbol("__plt_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) plt_addr = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__plt_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) object->plt_size = ooff + this->st_value - plt_addr; #endif if (object->got_addr == 0) object->got_start = 0; else { object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); object->got_size += object->got_addr - object->got_start; object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); } #if 0 if (plt_addr == 0) object->plt_start = 0; else { object->plt_start = ELF_TRUNC(plt_addr, _dl_pagesz); object->plt_size += plt_addr - object->plt_start; object->plt_size = ELF_ROUND(object->plt_size, _dl_pagesz); } #endif if (object->traced) lazy = 1; if (!lazy) { fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); } else { if (object->obj_base != 0) { int i, size; Elf_Addr *addr; Elf_RelA *rela; size = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA); rela = (Elf_RelA *)object->Dyn.info[DT_JMPREL]; for (i = 0; i < size; i++) { addr = (Elf_Addr *)(object->obj_base + rela[i].r_offset); *addr += object->obj_base; } } } if (object->got_size != 0) { _dl_mprotect((void*)object->got_start, object->got_size, PROT_READ); } /* PLT is already RO, no point in mprotecting it, just do GOT */ #if 0 if (object->plt_size != 0) _dl_mprotect((void*)object->plt_start, object->plt_size, PROT_READ|PROT_EXEC); #endif return (fails); }