Path: blob/main/system/lib/libc/musl/ldso/dlstart.c
6174 views
#include <stddef.h>1#include "dynlink.h"2#include "libc.h"34#ifndef START5#define START "_dlstart"6#endif78#define SHARED910#include "crt_arch.h"1112#ifndef GETFUNCSYM13#define GETFUNCSYM(fp, sym, got) do { \14hidden void sym(); \15static void (*static_func_ptr)() = sym; \16__asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \17*(fp) = static_func_ptr; } while(0)18#endif1920hidden void _dlstart_c(size_t *sp, size_t *dynv)21{22size_t i, aux[AUX_CNT], dyn[DYN_CNT];23size_t *rel, rel_size, base;2425int argc = *sp;26char **argv = (void *)(sp+1);2728for (i=argc+1; argv[i]; i++);29size_t *auxv = (void *)(argv+i+1);3031for (i=0; i<AUX_CNT; i++) aux[i] = 0;32for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)33aux[auxv[i]] = auxv[i+1];3435#if DL_FDPIC36struct fdpic_loadseg *segs, fakeseg;37size_t j;38if (dynv) {39/* crt_arch.h entry point asm is responsible for reserving40* space and moving the extra fdpic arguments to the stack41* vector where they are easily accessible from C. */42segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;43} else {44/* If dynv is null, the entry point was started from loader45* that is not fdpic-aware. We can assume normal fixed-46* displacement ELF loading was performed, but when ldso was47* run as a command, finding the Ehdr is a heursitic: we48* have to assume Phdrs start in the first 4k of the file. */49base = aux[AT_BASE];50if (!base) base = aux[AT_PHDR] & -4096;51segs = &fakeseg;52segs[0].addr = base;53segs[0].p_vaddr = 0;54segs[0].p_memsz = -1;55Ehdr *eh = (void *)base;56Phdr *ph = (void *)(base + eh->e_phoff);57size_t phnum = eh->e_phnum;58size_t phent = eh->e_phentsize;59while (phnum-- && ph->p_type != PT_DYNAMIC)60ph = (void *)((size_t)ph + phent);61dynv = (void *)(base + ph->p_vaddr);62}63#endif6465for (i=0; i<DYN_CNT; i++) dyn[i] = 0;66for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)67dyn[dynv[i]] = dynv[i+1];6869#if DL_FDPIC70for (i=0; i<DYN_CNT; i++) {71if (i==DT_RELASZ || i==DT_RELSZ) continue;72if (!dyn[i]) continue;73for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);74dyn[i] += segs[j].addr - segs[j].p_vaddr;75}76base = 0;7778const Sym *syms = (void *)dyn[DT_SYMTAB];7980rel = (void *)dyn[DT_RELA];81rel_size = dyn[DT_RELASZ];82for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {83if (!IS_RELATIVE(rel[1], syms)) continue;84for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);85size_t *rel_addr = (void *)86(rel[0] + segs[j].addr - segs[j].p_vaddr);87if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {88*rel_addr += segs[rel_addr[1]].addr89- segs[rel_addr[1]].p_vaddr90+ syms[R_SYM(rel[1])].st_value;91rel_addr[1] = dyn[DT_PLTGOT];92} else {93size_t val = syms[R_SYM(rel[1])].st_value;94for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);95*rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;96}97}98#else99/* If the dynamic linker is invoked as a command, its load100* address is not available in the aux vector. Instead, compute101* the load address as the difference between &_DYNAMIC and the102* virtual address in the PT_DYNAMIC program header. */103base = aux[AT_BASE];104if (!base) {105size_t phnum = aux[AT_PHNUM];106size_t phentsize = aux[AT_PHENT];107Phdr *ph = (void *)aux[AT_PHDR];108for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {109if (ph->p_type == PT_DYNAMIC) {110base = (size_t)dynv - ph->p_vaddr;111break;112}113}114}115116/* MIPS uses an ugly packed form for GOT relocations. Since we117* can't make function calls yet and the code is tiny anyway,118* it's simply inlined here. */119if (NEED_MIPS_GOT_RELOCS) {120size_t local_cnt = 0;121size_t *got = (void *)(base + dyn[DT_PLTGOT]);122for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)123local_cnt = dynv[i+1];124for (i=0; i<local_cnt; i++) got[i] += base;125}126127rel = (void *)(base+dyn[DT_REL]);128rel_size = dyn[DT_RELSZ];129for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {130if (!IS_RELATIVE(rel[1], 0)) continue;131size_t *rel_addr = (void *)(base + rel[0]);132*rel_addr += base;133}134135rel = (void *)(base+dyn[DT_RELA]);136rel_size = dyn[DT_RELASZ];137for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {138if (!IS_RELATIVE(rel[1], 0)) continue;139size_t *rel_addr = (void *)(base + rel[0]);140*rel_addr = base + rel[2];141}142143rel = (void *)(base+dyn[DT_RELR]);144rel_size = dyn[DT_RELRSZ];145size_t *relr_addr = 0;146for (; rel_size; rel++, rel_size-=sizeof(size_t)) {147if ((rel[0]&1) == 0) {148relr_addr = (void *)(base + rel[0]);149*relr_addr++ += base;150} else {151for (size_t i=0, bitmap=rel[0]; bitmap>>=1; i++)152if (bitmap&1)153relr_addr[i] += base;154relr_addr += 8*sizeof(size_t)-1;155}156}157#endif158159stage2_func dls2;160GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);161dls2((void *)base, sp);162}163164165