| OLD | NEW |
| 1 #include <stddef.h> | 1 #include <stddef.h> |
| 2 #include "dynlink.h" | 2 #include "dynlink.h" |
| 3 | 3 |
| 4 #ifndef START | 4 #ifndef START |
| 5 #define START "_dlstart" | 5 #define START "_dlstart" |
| 6 #endif | 6 #endif |
| 7 | 7 |
| 8 #include "crt_arch.h" | 8 #include "crt_arch.h" |
| 9 | 9 |
| 10 #ifndef GETFUNCSYM | 10 #ifndef GETFUNCSYM |
| 11 #define GETFUNCSYM(fp, sym, got) do { \ | 11 #define GETFUNCSYM(fp, sym, got) \ |
| 12 » __attribute__((__visibility__("hidden"))) void sym(); \ | 12 do { \ |
| 13 » static void (*static_func_ptr)() = sym; \ | 13 __attribute__((__visibility__("hidden"))) void sym(); \ |
| 14 » __asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \ | 14 static void (*static_func_ptr)() = sym; \ |
| 15 » *(fp) = static_func_ptr; } while(0) | 15 __asm__ __volatile__("" : "+m"(static_func_ptr) : : "memory"); \ |
| 16 *(fp) = static_func_ptr; \ |
| 17 } while (0) |
| 16 #endif | 18 #endif |
| 17 | 19 |
| 18 __attribute__((__visibility__("hidden"))) | 20 __attribute__((__visibility__("hidden"))) void _dlstart_c(size_t* sp, |
| 19 void _dlstart_c(size_t *sp, size_t *dynv) | 21 size_t* dynv) { |
| 20 { | 22 size_t i, aux[AUX_CNT], dyn[DYN_CNT]; |
| 21 » size_t i, aux[AUX_CNT], dyn[DYN_CNT]; | 23 size_t *rel, rel_size, base; |
| 22 » size_t *rel, rel_size, base; | |
| 23 | 24 |
| 24 » int argc = *sp; | 25 int argc = *sp; |
| 25 » char **argv = (void *)(sp+1); | 26 char** argv = (void*)(sp + 1); |
| 26 | 27 |
| 27 » for (i=argc+1; argv[i]; i++); | 28 for (i = argc + 1; argv[i]; i++) |
| 28 » size_t *auxv = (void *)(argv+i+1); | 29 ; |
| 30 size_t* auxv = (void*)(argv + i + 1); |
| 29 | 31 |
| 30 » for (i=0; i<AUX_CNT; i++) aux[i] = 0; | 32 for (i = 0; i < AUX_CNT; i++) |
| 31 » for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT) | 33 aux[i] = 0; |
| 32 » » aux[auxv[i]] = auxv[i+1]; | 34 for (i = 0; auxv[i]; i += 2) |
| 35 if (auxv[i] < AUX_CNT) |
| 36 aux[auxv[i]] = auxv[i + 1]; |
| 33 | 37 |
| 34 #if DL_FDPIC | 38 #if DL_FDPIC |
| 35 » struct fdpic_loadseg *segs, fakeseg; | 39 struct fdpic_loadseg *segs, fakeseg; |
| 36 » size_t j; | 40 size_t j; |
| 37 » if (dynv) { | 41 if (dynv) { |
| 38 » » /* crt_arch.h entry point asm is responsible for reserving | 42 /* crt_arch.h entry point asm is responsible for reserving |
| 39 » » * space and moving the extra fdpic arguments to the stack | 43 * space and moving the extra fdpic arguments to the stack |
| 40 » » * vector where they are easily accessible from C. */ | 44 * vector where they are easily accessible from C. */ |
| 41 » » segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->seg
s; | 45 segs = ((struct fdpic_loadmap*)(sp[-1] ? sp[-1] : sp[-2]))->segs; |
| 42 » } else { | 46 } else { |
| 43 » » /* If dynv is null, the entry point was started from loader | 47 /* If dynv is null, the entry point was started from loader |
| 44 » » * that is not fdpic-aware. We can assume normal fixed- | 48 * that is not fdpic-aware. We can assume normal fixed- |
| 45 » » * displacement ELF loading was performed, but when ldso was | 49 * displacement ELF loading was performed, but when ldso was |
| 46 » » * run as a command, finding the Ehdr is a heursitic: we | 50 * run as a command, finding the Ehdr is a heursitic: we |
| 47 » » * have to assume Phdrs start in the first 4k of the file. */ | 51 * have to assume Phdrs start in the first 4k of the file. */ |
| 48 » » base = aux[AT_BASE]; | 52 base = aux[AT_BASE]; |
| 49 » » if (!base) base = aux[AT_PHDR] & -4096; | 53 if (!base) |
| 50 » » segs = &fakeseg; | 54 base = aux[AT_PHDR] & -4096; |
| 51 » » segs[0].addr = base; | 55 segs = &fakeseg; |
| 52 » » segs[0].p_vaddr = 0; | 56 segs[0].addr = base; |
| 53 » » segs[0].p_memsz = -1; | 57 segs[0].p_vaddr = 0; |
| 54 » » Ehdr *eh = (void *)base; | 58 segs[0].p_memsz = -1; |
| 55 » » Phdr *ph = (void *)(base + eh->e_phoff); | 59 Ehdr* eh = (void*)base; |
| 56 » » size_t phnum = eh->e_phnum; | 60 Phdr* ph = (void*)(base + eh->e_phoff); |
| 57 » » size_t phent = eh->e_phentsize; | 61 size_t phnum = eh->e_phnum; |
| 58 » » while (phnum-- && ph->p_type != PT_DYNAMIC) | 62 size_t phent = eh->e_phentsize; |
| 59 » » » ph = (void *)((size_t)ph + phent); | 63 while (phnum-- && ph->p_type != PT_DYNAMIC) |
| 60 » » dynv = (void *)(base + ph->p_vaddr); | 64 ph = (void*)((size_t)ph + phent); |
| 61 » } | 65 dynv = (void*)(base + ph->p_vaddr); |
| 66 } |
| 62 #endif | 67 #endif |
| 63 | 68 |
| 64 » for (i=0; i<DYN_CNT; i++) dyn[i] = 0; | 69 for (i = 0; i < DYN_CNT; i++) |
| 65 » for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT) | 70 dyn[i] = 0; |
| 66 » » dyn[dynv[i]] = dynv[i+1]; | 71 for (i = 0; dynv[i]; i += 2) |
| 72 if (dynv[i] < DYN_CNT) |
| 73 dyn[dynv[i]] = dynv[i + 1]; |
| 67 | 74 |
| 68 #if DL_FDPIC | 75 #if DL_FDPIC |
| 69 » for (i=0; i<DYN_CNT; i++) { | 76 for (i = 0; i < DYN_CNT; i++) { |
| 70 » » if (i==DT_RELASZ || i==DT_RELSZ) continue; | 77 if (i == DT_RELASZ || i == DT_RELSZ) |
| 71 » » if (!dyn[i]) continue; | 78 continue; |
| 72 » » for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++); | 79 if (!dyn[i]) |
| 73 » » dyn[i] += segs[j].addr - segs[j].p_vaddr; | 80 continue; |
| 74 » } | 81 for (j = 0; dyn[i] - segs[j].p_vaddr >= segs[j].p_memsz; j++) |
| 75 » base = 0; | 82 ; |
| 83 dyn[i] += segs[j].addr - segs[j].p_vaddr; |
| 84 } |
| 85 base = 0; |
| 76 | 86 |
| 77 » const Sym *syms = (void *)dyn[DT_SYMTAB]; | 87 const Sym* syms = (void*)dyn[DT_SYMTAB]; |
| 78 | 88 |
| 79 » rel = (void *)dyn[DT_RELA]; | 89 rel = (void*)dyn[DT_RELA]; |
| 80 » rel_size = dyn[DT_RELASZ]; | 90 rel_size = dyn[DT_RELASZ]; |
| 81 » for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { | 91 for (; rel_size; rel += 3, rel_size -= 3 * sizeof(size_t)) { |
| 82 » » if (!IS_RELATIVE(rel[1], syms)) continue; | 92 if (!IS_RELATIVE(rel[1], syms)) |
| 83 » » for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++); | 93 continue; |
| 84 » » size_t *rel_addr = (void *) | 94 for (j = 0; rel[0] - segs[j].p_vaddr >= segs[j].p_memsz; j++) |
| 85 » » » (rel[0] + segs[j].addr - segs[j].p_vaddr); | 95 ; |
| 86 » » if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { | 96 size_t* rel_addr = (void*)(rel[0] + segs[j].addr - segs[j].p_vaddr); |
| 87 » » » *rel_addr += segs[rel_addr[1]].addr | 97 if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { |
| 88 » » » » - segs[rel_addr[1]].p_vaddr | 98 *rel_addr += segs[rel_addr[1]].addr - segs[rel_addr[1]].p_vaddr + |
| 89 » » » » + syms[R_SYM(rel[1])].st_value; | 99 syms[R_SYM(rel[1])].st_value; |
| 90 » » » rel_addr[1] = dyn[DT_PLTGOT]; | 100 rel_addr[1] = dyn[DT_PLTGOT]; |
| 91 » » } else { | 101 } else { |
| 92 » » » size_t val = syms[R_SYM(rel[1])].st_value; | 102 size_t val = syms[R_SYM(rel[1])].st_value; |
| 93 » » » for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++); | 103 for (j = 0; val - segs[j].p_vaddr >= segs[j].p_memsz; j++) |
| 94 » » » *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + va
l; | 104 ; |
| 95 » » } | 105 *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val; |
| 96 » } | 106 } |
| 107 } |
| 97 #else | 108 #else |
| 98 » /* If the dynamic linker is invoked as a command, its load | 109 /* If the dynamic linker is invoked as a command, its load |
| 99 » * address is not available in the aux vector. Instead, compute | 110 * address is not available in the aux vector. Instead, compute |
| 100 » * the load address as the difference between &_DYNAMIC and the | 111 * the load address as the difference between &_DYNAMIC and the |
| 101 » * virtual address in the PT_DYNAMIC program header. */ | 112 * virtual address in the PT_DYNAMIC program header. */ |
| 102 » base = aux[AT_BASE]; | 113 base = aux[AT_BASE]; |
| 103 » if (!base) { | 114 if (!base) { |
| 104 » » size_t phnum = aux[AT_PHNUM]; | 115 size_t phnum = aux[AT_PHNUM]; |
| 105 » » size_t phentsize = aux[AT_PHENT]; | 116 size_t phentsize = aux[AT_PHENT]; |
| 106 » » Phdr *ph = (void *)aux[AT_PHDR]; | 117 Phdr* ph = (void*)aux[AT_PHDR]; |
| 107 » » for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) { | 118 for (i = phnum; i--; ph = (void*)((char*)ph + phentsize)) { |
| 108 » » » if (ph->p_type == PT_DYNAMIC) { | 119 if (ph->p_type == PT_DYNAMIC) { |
| 109 » » » » base = (size_t)dynv - ph->p_vaddr; | 120 base = (size_t)dynv - ph->p_vaddr; |
| 110 » » » » break; | 121 break; |
| 111 » » » } | 122 } |
| 112 » » } | 123 } |
| 113 » } | 124 } |
| 114 | 125 |
| 115 » /* MIPS uses an ugly packed form for GOT relocations. Since we | 126 /* MIPS uses an ugly packed form for GOT relocations. Since we |
| 116 » * can't make function calls yet and the code is tiny anyway, | 127 * can't make function calls yet and the code is tiny anyway, |
| 117 » * it's simply inlined here. */ | 128 * it's simply inlined here. */ |
| 118 » if (NEED_MIPS_GOT_RELOCS) { | 129 if (NEED_MIPS_GOT_RELOCS) { |
| 119 » » size_t local_cnt = 0; | 130 size_t local_cnt = 0; |
| 120 » » size_t *got = (void *)(base + dyn[DT_PLTGOT]); | 131 size_t* got = (void*)(base + dyn[DT_PLTGOT]); |
| 121 » » for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO) | 132 for (i = 0; dynv[i]; i += 2) |
| 122 » » » local_cnt = dynv[i+1]; | 133 if (dynv[i] == DT_MIPS_LOCAL_GOTNO) |
| 123 » » for (i=0; i<local_cnt; i++) got[i] += base; | 134 local_cnt = dynv[i + 1]; |
| 124 » } | 135 for (i = 0; i < local_cnt; i++) |
| 136 got[i] += base; |
| 137 } |
| 125 | 138 |
| 126 » rel = (void *)(base+dyn[DT_REL]); | 139 rel = (void*)(base + dyn[DT_REL]); |
| 127 » rel_size = dyn[DT_RELSZ]; | 140 rel_size = dyn[DT_RELSZ]; |
| 128 » for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) { | 141 for (; rel_size; rel += 2, rel_size -= 2 * sizeof(size_t)) { |
| 129 » » if (!IS_RELATIVE(rel[1], 0)) continue; | 142 if (!IS_RELATIVE(rel[1], 0)) |
| 130 » » size_t *rel_addr = (void *)(base + rel[0]); | 143 continue; |
| 131 » » *rel_addr += base; | 144 size_t* rel_addr = (void*)(base + rel[0]); |
| 132 » } | 145 *rel_addr += base; |
| 146 } |
| 133 | 147 |
| 134 » rel = (void *)(base+dyn[DT_RELA]); | 148 rel = (void*)(base + dyn[DT_RELA]); |
| 135 » rel_size = dyn[DT_RELASZ]; | 149 rel_size = dyn[DT_RELASZ]; |
| 136 » for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { | 150 for (; rel_size; rel += 3, rel_size -= 3 * sizeof(size_t)) { |
| 137 » » if (!IS_RELATIVE(rel[1], 0)) continue; | 151 if (!IS_RELATIVE(rel[1], 0)) |
| 138 » » size_t *rel_addr = (void *)(base + rel[0]); | 152 continue; |
| 139 » » *rel_addr = base + rel[2]; | 153 size_t* rel_addr = (void*)(base + rel[0]); |
| 140 » } | 154 *rel_addr = base + rel[2]; |
| 155 } |
| 141 #endif | 156 #endif |
| 142 | 157 |
| 143 » stage2_func dls2; | 158 stage2_func dls2; |
| 144 » GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]); | 159 GETFUNCSYM(&dls2, __dls2, base + dyn[DT_PLTGOT]); |
| 145 » dls2((void *)base, sp); | 160 dls2((void*)base, sp); |
| 146 } | 161 } |
| OLD | NEW |