diff options
Diffstat (limited to 'libexec/ld.so/boot.c')
-rw-r--r-- | libexec/ld.so/boot.c | 190 |
1 files changed, 75 insertions, 115 deletions
diff --git a/libexec/ld.so/boot.c b/libexec/ld.so/boot.c index ca51e80be22..30e646cb22f 100644 --- a/libexec/ld.so/boot.c +++ b/libexec/ld.so/boot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: boot.c,v 1.5 2015/01/16 16:18:07 deraadt Exp $ */ +/* $OpenBSD: boot.c,v 1.6 2015/12/06 23:36:12 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -44,14 +44,33 @@ #include "syscall.h" #include "archdep.h" -#include "path.h" -#include "resolve.h" -#include "sod.h" #include "stdlib.h" -#include "dl_prebind.h" #include "../../lib/csu/os-note-elf.h" +#if RELOC_TAG == DT_RELA +typedef Elf_RelA RELOC_TYPE; +#elif RELOC_TAG == DT_REL +typedef Elf_Rel RELOC_TYPE; +#else +# error "unknown RELOC_TAG" +#endif + +/* The set of dynamic tags that we're interested in for bootstrapping */ +struct boot_dyn { + RELOC_TYPE *dt_reloc; /* DT_RELA or DT_REL */ + Elf_Addr dt_relocsz; /* DT_RELASZ or DT_RELSZ */ + Elf_Addr *dt_pltgot; + Elf_Addr dt_pltrelsz; + const Elf_Sym *dt_symtab; +#ifdef HAVE_JMPREL + RELOC_TYPE *dt_jmprel; +#endif +#if DT_PROCNUM > 0 + u_long dt_proc[DT_PROCNUM]; +#endif +}; + /* * Local decls. */ @@ -60,13 +79,15 @@ void _dl_boot_bind(const long, long *, Elf_Dyn *); void _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) { - struct elf_object dynld; /* Resolver data for the loader */ + struct boot_dyn dynld; /* Resolver data for the loader */ AuxInfo *auxstack; long *stack; Elf_Dyn *dynp; int n, argc; - char **argv, **envp; - long loff; + char **argv, **envp; + long loff; + Elf_Addr i; + RELOC_TYPE *rp; /* * Scan argument and environment vectors. Find dynamic @@ -114,124 +135,63 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) #else dynp = (Elf_Dyn *)((long)_DYNAMIC + loff); #endif - _dl_memset(dynld.Dyn.info, 0, sizeof(dynld.Dyn.info)); - while (dynp != NULL && dynp->d_tag != DT_NULL) { - if (dynp->d_tag < DT_NUM) - dynld.Dyn.info[dynp->d_tag] = dynp->d_un.d_val; + + _dl_memset(&dynld, 0, sizeof(dynld)); + while (dynp->d_tag != DT_NULL) { + /* first the tags that are pointers to be relocated */ + if (dynp->d_tag == DT_PLTGOT) + dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff); + else if (dynp->d_tag == DT_SYMTAB) + dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff); + else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */ + dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff); +#ifdef HAVE_JMPREL + else if (dynp->d_tag == DT_JMPREL) + dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff); +#endif + + /* Now for the tags that are just sizes or counts */ + else if (dynp->d_tag == DT_PLTRELSZ) + dynld.dt_pltrelsz = dynp->d_un.d_val; + else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */ + dynld.dt_relocsz = dynp->d_un.d_val; +#if DT_PROCNUM > 0 else if (dynp->d_tag >= DT_LOPROC && dynp->d_tag < DT_LOPROC + DT_PROCNUM) - dynld.Dyn.info[dynp->d_tag - DT_LOPROC + DT_NUM] = + dynld.dt_proc[dynp->d_tag - DT_LOPROC] = dynp->d_un.d_val; - if (dynp->d_tag == DT_TEXTREL) - dynld.dyn.textrel = 1; +#endif /* DT_PROCNUM */ dynp++; } - /* - * Do the 'bootstrap relocation'. This is really only needed if - * the code was loaded at another location than it was linked to. - * We don't do undefined symbols resolving (to difficult..) - */ - - /* "relocate" dyn.X values if they represent addresses */ - { - int i, val; - /* must be code, not pic data */ - int table[20]; - - i = 0; - table[i++] = DT_PLTGOT; - table[i++] = DT_HASH; - table[i++] = DT_STRTAB; - table[i++] = DT_SYMTAB; - table[i++] = DT_RELA; - table[i++] = DT_INIT; - table[i++] = DT_FINI; - table[i++] = DT_REL; - table[i++] = DT_JMPREL; - /* other processors insert their extras here */ - table[i++] = DT_NULL; - for (i = 0; table[i] != DT_NULL; i++) { - val = table[i]; - if (val >= DT_LOPROC && val < DT_LOPROC + DT_PROCNUM) - val = val - DT_LOPROC + DT_NUM; - else if (val >= DT_NUM) - continue; - if (dynld.Dyn.info[val] != 0) - dynld.Dyn.info[val] += loff; - } - } - - { - u_int32_t rs; - Elf_Rel *rp; - int i; - - rp = (Elf_Rel *)(dynld.Dyn.info[DT_REL]); - rs = dynld.dyn.relsz; +#ifdef HAVE_JMPREL + rp = dynld.dt_jmprel; + for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) { + Elf_Addr *ra; + const Elf_Sym *sp; - for (i = 0; i < rs; i += sizeof (Elf_Rel)) { - Elf_Addr *ra; - const Elf_Sym *sp; + sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); + if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) + _dl_exit(5); - sp = dynld.dyn.symtab; - sp += ELF_R_SYM(rp->r_info); - - if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) { -#if 0 -/* cannot printf in this function */ - _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); - _dl_wrstderr("Undefined symbol: "); - _dl_wrstderr((char *)dynld.dyn.strtab + - sp->st_name); -#endif - _dl_exit(5); - } - - ra = (Elf_Addr *)(rp->r_offset + loff); - RELOC_REL(rp, sp, ra, loff); - rp++; - } + ra = (Elf_Addr *)(rp->r_offset + loff); + RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot); + rp++; } +#endif /* HAVE_JMPREL */ - for (n = 0; n < 2; n++) { - unsigned long rs; - Elf_RelA *rp; - int i; - - switch (n) { - case 0: - rp = (Elf_RelA *)(dynld.Dyn.info[DT_JMPREL]); - rs = dynld.dyn.pltrelsz; - break; - case 1: - rp = (Elf_RelA *)(dynld.Dyn.info[DT_RELA]); - rs = dynld.dyn.relasz; - break; - default: - rp = NULL; - rs = 0; - } - for (i = 0; i < rs; i += sizeof (Elf_RelA)) { - Elf_Addr *ra; - const Elf_Sym *sp; - - sp = dynld.dyn.symtab; - sp += ELF_R_SYM(rp->r_info); - if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) { -#if 0 - _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); - _dl_wrstderr("Undefined symbol: "); - _dl_wrstderr((char *)dynld.dyn.strtab + - sp->st_name); -#endif - _dl_exit(6); - } + rp = dynld.dt_reloc; + for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) { + Elf_Addr *ra; + const Elf_Sym *sp; + + sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); + if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) + _dl_exit(6); - ra = (Elf_Addr *)(rp->r_offset + loff); - RELOC_RELA(rp, sp, ra, loff, dynld.dyn.pltgot); - rp++; - } + ra = (Elf_Addr *)(rp->r_offset + loff); + RELOC_DYN(rp, sp, ra, loff); + rp++; } RELOC_GOT(&dynld, loff); |