const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],		     int lazy, int consider_profiling){  if (l->l_relocated)    return;  /* If DT_BIND_NOW is set relocate all references in this object.  We     do not do this if we are profiling, of course.  */  if (!consider_profiling && l->l_info[DT_BIND_NOW])    lazy = 0;  if (_dl_debug_reloc)    _dl_debug_message (1, "\nrelocation processing: ",		       l->l_name[0] ? l->l_name : _dl_argv[0],		       lazy ? " (lazy)\n" : "\n", NULL);  if (l->l_info[DT_TEXTREL])    {      /* Bletch.  We must make read-only segments writable	 long enough to relocate them.  */      const ElfW(Phdr) *ph;      for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)	if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)	  {	    caddr_t mapstart = ((caddr_t) l->l_addr +				(ph->p_vaddr & ~(_dl_pagesize - 1)));	    caddr_t mapend = ((caddr_t) l->l_addr +			      ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)			       & ~(_dl_pagesize - 1)));	    if (__mprotect (mapstart, mapend - mapstart,			    PROT_READ|PROT_WRITE) < 0)	      _dl_signal_error (errno, l->l_name,				"cannot make segment writable for relocation");	  }    }  {    /* Do the actual relocation of the object's GOT and other data.  */    /* String table object symbols.  */    const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;    /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */#define RESOLVE(ref, version, flags) \    (ELFW(ST_VISIBILITY) ((*ref)->st_other) != STV_PROTECTED		      \     ? ((version) != NULL && (version)->hash != 0			      \	? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, l, (ref),    \				       scope, (version), (flags))	      \	: _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), scope,	      \			     (flags)))					      \     : l->l_addr)#include "dynamic-link.h"    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);    if (_dl_profile != NULL)      {	/* Allocate the array which will contain the already found	   relocations.  */	l->l_reloc_result =	  (ElfW(Addr) *) calloc (sizeof (ElfW(Addr)),				 l->l_info[DT_PLTRELSZ]->d_un.d_val);	if (l->l_reloc_result == NULL)	  _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>",			    "cannot allocate memory for profiling", NULL);      }  }  /* Mark the object so we know this work has been done.  */  l->l_relocated = 1;  /* DT_TEXTREL is now in level 2 and might phase out at some time.     But we rewrite the DT_FLAGS entry to make testing easier and     therefore it will be available at all time.  */  if (l->l_info[DT_TEXTREL])    {      /* Undo the protection change we made before relocating.  */      const ElfW(Phdr) *ph;      for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)	if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)	  {	    caddr_t mapstart = ((caddr_t) l->l_addr +				(ph->p_vaddr & ~(_dl_pagesize - 1)));	    caddr_t mapend = ((caddr_t) l->l_addr +			      ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)			       & ~(_dl_pagesize - 1)));	    extern unsigned char _dl_pf_to_prot[8];	    int prot;	    if ((PF_R | PF_W | PF_X) == 7		&& (PROT_READ | PROT_WRITE | PROT_EXEC) == 7)	      prot = _dl_pf_to_prot[ph->p_flags & (PF_R | PF_X)];	    else	      {		prot = 0;		if (ph->p_flags & PF_R)		  prot |= PROT_READ;		if (ph->p_flags & PF_X)		  prot |= PROT_EXEC;	      }	    if (__mprotect (mapstart, mapend - mapstart, prot) < 0)	      _dl_signal_error (errno, l->l_name,				"can't restore segment prot after reloc");#ifdef CLEAR_CACHE	    CLEAR_CACHE (mapstart, mapend);#endif 	  }    }}