FreeBSD/libexec/rtld-elf/rtld.c
/*
 * Process a shared object's program header.  This is used only for the
 * main program, when the kernel has already loaded the main program
 * into memory before calling the dynamic linker.  It creates and
 * returns an Obj_Entry structure.
 */
Process a shared object's program header.  This is used only for the
main program, when the kernel has already loaded the main program
into memory before calling the dynamic linker.  It creates and
returns an Obj_Entry structure.
Process a shared object ' s program header . This is used only for the main program when the kernel has already loaded the main program into memory before calling the dynamic linker . It creates and returns an Obj_Entry structure .
static Obj_Entry *
digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
{
    Obj_Entry *obj;
    const Elf_Phdr *phlimit = phdr + phnum;
    const Elf_Phdr *ph;
    Elf_Addr note_start, note_end;
    int nsegs = 0;
    obj = obj_new();
    for (ph = phdr;  ph < phlimit;  ph++) {
	if (ph->p_type != PT_PHDR)
	    continue;
	obj->phdr = phdr;
	obj->phsize = ph->p_memsz;
	obj->relocbase = (caddr_t)phdr - ph->p_vaddr;
	break;
    }
    obj->stack_flags = PF_X | PF_R | PF_W;
    for (ph = phdr;  ph < phlimit;  ph++) {
	switch (ph->p_type) {
	case PT_INTERP:
	    obj->interp = (const char *)(ph->p_vaddr + obj->relocbase);
	    break;
	case PT_LOAD:
	    if (nsegs == 0) {	
		obj->vaddrbase = trunc_page(ph->p_vaddr);
		obj->mapbase = obj->vaddrbase + obj->relocbase;
		obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) -
		  obj->vaddrbase;
	    } else {		
		obj->mapsize = round_page(ph->p_vaddr + ph->p_memsz) -
		  obj->vaddrbase;
	    }
	    nsegs++;
	    break;
	case PT_DYNAMIC:
	    obj->dynamic = (const Elf_Dyn *)(ph->p_vaddr + obj->relocbase);
	    break;
	case PT_TLS:
	    obj->tlsindex = 1;
	    obj->tlssize = ph->p_memsz;
	    obj->tlsalign = ph->p_align;
	    obj->tlsinitsize = ph->p_filesz;
	    obj->tlsinit = (void*)(ph->p_vaddr + obj->relocbase);
	    break;
	case PT_GNU_STACK:
	    obj->stack_flags = ph->p_flags;
	    break;
	case PT_GNU_RELRO:
	    obj->relro_page = obj->relocbase + trunc_page(ph->p_vaddr);
	    obj->relro_size = round_page(ph->p_memsz);
	    break;
	case PT_NOTE:
	    note_start = (Elf_Addr)obj->relocbase + ph->p_vaddr;
	    note_end = note_start + ph->p_filesz;
	    digest_notes(obj, note_start, note_end);
	    break;
	}
    }
    if (nsegs < 1) {
	_rtld_error("%s: too few PT_LOAD segments", path);
	return NULL;
    }
    obj->entry = entry;
    return obj;
}
static Obj_Entry * digest_phdr ( const Elf_Phdr * phdr , int phnum , caddr_t entry , const char * path ) { Obj_Entry * obj ; const Elf_Phdr * phlimit = phdr + phnum ; const Elf_Phdr * ph ; Elf_Addr note_start , note_end ; int nsegs = 0 ; obj = obj_new ( ) ; for ( ph = phdr ; ph < phlimit ; ph ++ ) { if ( ph -> p_type != PT_PHDR ) continue ; obj -> phdr = phdr ; obj -> phsize = ph -> p_memsz ; obj -> relocbase = ( caddr_t ) phdr - ph -> p_vaddr ; break ; } obj -> stack_flags = PF_X | PF_R | PF_W ; for ( ph = phdr ; ph < phlimit ; ph ++ ) { switch ( ph -> p_type ) { case PT_INTERP : obj -> interp = ( const char * ) ( ph -> p_vaddr + obj -> relocbase ) ; break ; case PT_LOAD : if ( nsegs == 0 ) { obj -> vaddrbase = trunc_page ( ph -> p_vaddr ) ; obj -> mapbase = obj -> vaddrbase + obj -> relocbase ; obj -> textsize = round_page ( ph -> p_vaddr + ph -> p_memsz ) - obj -> vaddrbase ; } else { obj -> mapsize = round_page ( ph -> p_vaddr + ph -> p_memsz ) - obj -> vaddrbase ; } nsegs ++ ; break ; case PT_DYNAMIC : obj -> dynamic = ( const Elf_Dyn * ) ( ph -> p_vaddr + obj -> relocbase ) ; break ; case PT_TLS : obj -> tlsindex = 1 ; obj -> tlssize = ph -> p_memsz ; obj -> tlsalign = ph -> p_align ; obj -> tlsinitsize = ph -> p_filesz ; obj -> tlsinit = ( void * ) ( ph -> p_vaddr + obj -> relocbase ) ; break ; case PT_GNU_STACK : obj -> stack_flags = ph -> p_flags ; break ; case PT_GNU_RELRO : obj -> relro_page = obj -> relocbase + trunc_page ( ph -> p_vaddr ) ; obj -> relro_size = round_page ( ph -> p_memsz ) ; break ; case PT_NOTE : note_start = ( Elf_Addr ) obj -> relocbase + ph -> p_vaddr ; note_end = note_start + ph -> p_filesz ; digest_notes ( obj , note_start , note_end ) ; break ; } } if ( nsegs < 1 ) { _rtld_error ( " " , path ) ; return NULL ; } obj -> entry = entry ; return obj ; }
Process a shared object's program header.
Process a shared object ' s program header .
/* First load segment */ /* Last load segment */