MSIZE MBArrowLook::GetDefaultSize(MArrow* pThumb) { if(pThumb->m_nDirection==0){ if(m_pArrowBitmaps[4]==NULL) return MArrowLook::GetDefaultSize(pThumb); return MSIZE(m_pArrowBitmaps[4]->GetWidth(), m_pArrowBitmaps[4]->GetHeight()); } else{ if(m_pArrowBitmaps[0]==NULL) return MArrowLook::GetDefaultSize(pThumb); return MSIZE(m_pArrowBitmaps[0]->GetWidth(), m_pArrowBitmaps[0]->GetHeight()); } }
/* * doMemReallocUnsafe - reallocate a block, return NULL if it fails */ static void *doMemReAllocUnsafe( void *ptr, size_t size, WHO_PTR who ) { void *tmp; size_t orig_size; #ifdef __WATCOMC__ size_t tsize; #endif if( ptr != NULL ) { #ifdef __WATCOMC__ orig_size = MSIZE( ptr ); #else orig_size = 0xffffffff; #endif } else { orig_size = 0; } #ifdef TRMEM tmp = _trmem_realloc( ptr, size, who, trmemHandle ); #else who = who; tmp = realloc( ptr, size ); #endif #ifdef __WATCOMC__ if( tmp == NULL ) { tmp = doMemAllocUnsafe( size, who ); if( tmp == NULL ) { return( NULL ); } size = MSIZE( tmp ); if( orig_size != 0 ) { tsize = orig_size; if( tsize > size ) { tsize = size; } memcpy( tmp, ptr, tsize ); MemFree( ptr ); } } else #endif { #ifdef __WATCOMC__ size = MSIZE( tmp ); #endif if( size > orig_size ) { memset( &(((char *)tmp)[orig_size]), 0, size - orig_size ); } } return( tmp ); } /* doMemReAllocUnsafe */
/* * try_realloc_right - if heap is * |MALLOC|FREE and size is enough, then make as * |REALLOC |FRE and return same pointer. * */ void* try_realloc_right(MALLOC target,void* origin, FREE right, size_t realsize) { size_t rightnewF; if(MSIZE(target) + FSIZE(right) >= realsize) { rightnewF = realsize - MSIZE(target); divide_freeNode(right,rightnewF); delete_free(right); setAllocatedBlockSize(target,realsize); return M_TO_P(target); } return NULL; }
int socfpga_dwmmc_init(u32 regbase, int bus_width, int index) { struct dwmci_host *host; unsigned long clk = cm_get_mmc_controller_clk_hz(); if (clk == 0) { printf("%s: MMC clock is zero!", __func__); return -EINVAL; } /* calloc for zero init */ host = calloc(1, sizeof(struct dwmci_host)); if (!host) { printf("%s: calloc() failed!\n", __func__); return -ENOMEM; } host->name = "SOCFPGA DWMMC"; host->ioaddr = (void *)regbase; host->buswidth = bus_width; host->clksel = socfpga_dwmci_clksel; host->dev_index = index; /* fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) | TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2); return add_dwmci(host, host->bus_hz, 400000); }
static int dwmci_init(struct mmc *mmc) { struct dwmci_host *host = (struct dwmci_host *)mmc->priv; u32 fifo_size, fifoth_val; dwmci_writel(host, DWMCI_PWREN, 1); if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); return -1; } dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); dwmci_writel(host, DWMCI_INTMASK, 0); dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); fifo_size = dwmci_readl(host, DWMCI_FIFOTH); if (host->fifoth_val) fifoth_val = host->fifoth_val; else fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | TX_WMARK(fifo_size/2); dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); return 0; }
static int dw_mci_init(u32 regbase, int bus_width, int index, int max_clock) { struct dwmci_host *host = NULL; int fifo_size = 0x20; host = malloc(sizeof(struct dwmci_host)); if (!host) { printf("dwmci_host malloc fail!\n"); return 1; } dw_mci_set_clk(index, max_clock * 2); host->name = NXP_NAME; host->ioaddr = (void *)regbase; host->buswidth = bus_width; host->clksel = dw_mci_clksel; host->dev_index = index; host->get_mmc_clk = dw_mci_get_clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | TX_WMARK(fifo_size/2); add_dwmci(host, max_clock, 400000); return 0; }
/* * mm_free - Freeing a block inserts new free chunks to explicit list/tree * and tries merging free chunks. */ void mm_free(void *ptr) { MALLOC toFree = P_TO_M(ptr); insert_free(toFree,MSIZE(toFree)); merge_freeChunks(toFree); //mm_check(); return; }
/* * divide_malloc - * if size > newsize, make * |MALLOC(size)| -> |MALLOC(newsize)|FREE|. * * */ void divide_malloc(MALLOC target, size_t newsize) { size_t oldsize = MSIZE(target); if(newsize >= oldsize) return; void* newtarget = (char*)target + newsize; setAllocatedBlockSize(target,newsize); insert_free(newtarget, oldsize-newsize); return; }
ZBmNumLabel::ZBmNumLabel(const char* szName, MWidget* pParent, MListener* pListener) : MWidget(szName, pParent, pListener) { m_pLabelBitmap = NULL; m_AlignmentMode = MAM_RIGHT; m_nIndexOffset = 0; SetCharSize( MSIZE(32, 32)); }
static int rockchip_dwmmc_probe(struct udevice *dev) { struct rockchip_mmc_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; int ret; #if CONFIG_IS_ENABLED(OF_PLATDATA) struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat; host->name = dev->name; host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); host->buswidth = dtplat->bus_width; host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk; host->priv = dev; host->dev_index = 0; priv->fifo_depth = dtplat->fifo_depth; priv->fifo_mode = 0; priv->minmax[0] = 400000; /* 400 kHz */ priv->minmax[1] = dtplat->max_frequency; ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); if (ret < 0) return ret; #else ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; #endif host->fifoth_val = MSIZE(0x2) | RX_WMARK(priv->fifo_depth / 2 - 1) | TX_WMARK(priv->fifo_depth / 2); host->fifo_mode = priv->fifo_mode; #ifdef CONFIG_PWRSEQ /* Enable power if needed */ ret = uclass_get_device_by_phandle(UCLASS_PWRSEQ, dev, "mmc-pwrseq", &pwr_dev); if (!ret) { ret = pwrseq_set_power(pwr_dev, true); if (ret) return ret; } #endif dwmci_setup_cfg(&plat->cfg, host, priv->minmax[1], priv->minmax[0]); host->mmc = &plat->mmc; host->mmc->priv = &priv->host; host->mmc->dev = dev; upriv->mmc = host->mmc; return dwmci_probe(dev); }
BOOL AllocAndInitIpv6PktInfo(LPWSAMSG pWSAMsg) { PBYTE CtrlBuf = (PBYTE)MALLOC(WSA_CMSG_SPACE(sizeof IN6_PKTINFO)); //caller frees heap allocated CtrlBuf if(NULL == CtrlBuf) { ERR("HeapAlloc"); return FALSE; } pWSAMsg->Control.buf = (CHAR*)CtrlBuf; pWSAMsg->Control.len = (ULONG)MSIZE(CtrlBuf); return TRUE; }
static int rockchip_dwmmc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; u32 minmax[2]; int ret; int fifo_depth; ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; priv->periph = ret; if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock-freq-min-max", minmax, 2)) return -EINVAL; fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "fifo-depth", 0); if (fifo_depth < 0) return -EINVAL; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode")) host->fifo_mode = true; #ifdef CONFIG_PWRSEQ /* Enable power if needed */ ret = uclass_get_device_by_phandle(UCLASS_PWRSEQ, dev, "mmc-pwrseq", &pwr_dev); if (!ret) { ret = pwrseq_set_power(pwr_dev, true); if (ret) return ret; } #endif ret = add_dwmci(host, minmax[1], minmax[0]); if (ret) return ret; upriv->mmc = host->mmc; return 0; }
void MFrame::SetShade(bool bShade) { if (!m_bCanShade) return; if (m_bShade == bShade) return; if(m_bShade==false){ m_BeforeShade = MSIZE(m_Rect.w, m_Rect.h); SetSize(m_Rect.w, MTITLEBAR_HEIGHT); m_bShade = true; m_bResizable = false; } else{ SetSize(m_BeforeShade); m_bShade = false; m_bResizable = true; } }
static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) { /* FIXME: probe from DT eventually too/ */ const unsigned long clk = cm_get_mmc_controller_clk_hz(); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; int fifo_depth; if (clk == 0) { printf("DWMMC: MMC clock is zero!"); return -EINVAL; } fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "fifo-depth", 0); if (fifo_depth < 0) { printf("DWMMC: Can't get FIFO depth\n"); return -EINVAL; } host->name = dev->name; host->ioaddr = (void *)dev_get_addr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "bus-width", 4); host->clksel = socfpga_dwmci_clksel; /* * TODO([email protected]): Remove the need for this hack. * We only have one dwmmc block on gen5 SoCFPGA. */ host->dev_index = 0; /* Fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "drvsel", 3); priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "smplsel", 0); host->priv = priv; return 0; }
/* * getMem - get and clear memory */ static void *getMem( size_t size, WHO_PTR who ) { void *tmp; #ifdef TRMEM tmp = _trmem_alloc( size, who, trmemHandle ); #else who = who; tmp = malloc( size ); #endif if( tmp != NULL ) { #ifdef __WATCOMC__ size = MSIZE( tmp ); #endif memset( tmp, 0, size ); } return( tmp ); } /* getMem */
int socfpga_dwmmc_init(u32 regbase, int bus_width, int index) { struct dwmci_host *host = NULL; host = calloc(sizeof(struct dwmci_host), 1); if (!host) { printf("dwmci_host calloc fail!\n"); return -1; } host->name = SOCFPGA_NAME; host->ioaddr = (void *)regbase; host->buswidth = bus_width; host->clksel = socfpga_dwmci_clksel; host->dev_index = index; /* fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ; host->fifoth_val = MSIZE(0x2) | RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) | TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2); return add_dwmci(host, host->bus_hz, 400000); }
/* * mm_realloc - we check left chunk whether it is free chunk. * * 1. if it is free and its size is enough to cover reallocating size, * change malloc/free info and return same pointer. * * 2. if not, check this chunk is rightmost( or left of rightmost * free chunk) * * 2-1. if it is rightmost chunk (except free chunk), extend heap * and return same pointer (change malloc/free info) * * 2-2. if not, extend heap with new size and return that poitner. */ void *mm_realloc(void *ptr, size_t size) { MALLOC toRealloc = P_TO_M(ptr); void* retVal = NULL; size_t realSize = REQSIZE(size); size_t oldSize = MSIZE(toRealloc); if(realSize <= oldSize) { divide_malloc(toRealloc, realSize); return M_TO_P(toRealloc); } FREE right = (FREE)getRightBlock((void*)toRealloc); if(!right) { mem_sbrk(realSize - oldSize); setAllocatedBlockSize(toRealloc,realSize); return M_TO_P(toRealloc); } if(right&&(*((size_t*)right)&1)) retVal = try_realloc_right(toRealloc,ptr,right,realSize); if(retVal) { return retVal; } FREE left = (FREE)getLeftBlock((void*)toRealloc); if(left&&(*((size_t*)left)&1)) retVal = try_realloc_leftRight(toRealloc,ptr,left,right,realSize); if(retVal) { return retVal; } retVal = mm_malloc(size); memcpy(retVal,ptr,oldSize - MHEAD); mm_free(ptr); return retVal; }
/// Create and Initialize mail queue. /// \param[in] queue_def reference to the mail queue definition obtain with \ref osMailQ /// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL. /// \return mail queue ID for reference by other functions or NULL in case of error. /// \note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS. osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id) { mbq_id mbq; (void) thread_id; port_sys_lock(); unsigned size = MSIZE(queue_def->item_sz) + 1; mbq = core_sys_alloc(sizeof(mbq_t) + queue_def->queue_sz * size * sizeof(void*)); if (mbq) { mbq->mem.limit = queue_def->queue_sz; mbq->mem.size = size; mbq->mem.data = mbq + 1; mem_init(&mbq->mem); } port_sys_unlock(); return mbq; }
static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx) { /* FIXME: probe from DT eventually too/ */ const unsigned long clk = cm_get_mmc_controller_clk_hz(); struct dwmci_host *host; struct dwmci_socfpga_priv_data *priv; fdt_addr_t reg_base; int bus_width, fifo_depth; if (clk == 0) { printf("DWMMC%d: MMC clock is zero!", idx); return -EINVAL; } /* Get the register address from the device node */ reg_base = fdtdec_get_addr(blob, node, "reg"); if (!reg_base) { printf("DWMMC%d: Can't get base address\n", idx); return -EINVAL; } /* Get the bus width from the device node */ bus_width = fdtdec_get_int(blob, node, "bus-width", 0); if (bus_width <= 0) { printf("DWMMC%d: Can't get bus-width\n", idx); return -EINVAL; } fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); if (fifo_depth < 0) { printf("DWMMC%d: Can't get FIFO depth\n", idx); return -EINVAL; } /* Allocate the host */ host = calloc(1, sizeof(*host)); if (!host) return -ENOMEM; /* Allocate the priv */ priv = calloc(1, sizeof(*priv)); if (!priv) { free(host); return -ENOMEM; } host->name = "SOCFPGA DWMMC"; host->ioaddr = (void *)reg_base; host->buswidth = bus_width; host->clksel = socfpga_dwmci_clksel; host->dev_index = idx; /* Fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); priv->drvsel = fdtdec_get_uint(blob, node, "drvsel", 3); priv->smplsel = fdtdec_get_uint(blob, node, "smplsel", 0); host->priv = priv; return add_dwmci(host, host->bus_hz, 400000); }
int __cdecl main() { WSADATA wsd; INT i = 0, nErr = 0, nStartup = 0, rc = 0; SOCKET sock = INVALID_SOCKET; SOCKADDR_STORAGE addr = {0}, mcaddr = {0}, remoteaddr = {0}; WSAOVERLAPPED over = {0}; WSABUF wsabuf = {0}; DWORD dwBytes = 0, dwFlags = 0, dwRet = 0; IPV6_MREQ mreq = {0}; WSAMSG wsamsg = {0}; LPFN_WSARECVMSG WSARecvMsg = NULL; __try { //Initialize Winsock nErr = WSAStartup(WS_VER,&wsd); if (nErr) { WSASetLastError(nErr); ERR("WSAStartup"); __leave; } else nStartup++; // bind socket and register multicast mcaddr.ss_family = AF_INET6; InitMcastAddr((SOCKADDR*)&mcaddr,sizeof mcaddr); if (INVALID_SOCKET == (sock = socket(AF_INET6,SOCK_DGRAM,0))) { ERR("socket"); __leave; } if(!RouteLookup((SOCKADDR*)&mcaddr, sizeof mcaddr, (SOCKADDR*)&addr, sizeof addr )) { ERR("RouteLookup"); __leave; } SET_PORT((SOCKADDR*)&addr,DEFAULT_PORT); if (SOCKET_ERROR == bind(sock,(SOCKADDR*)&addr,sizeof addr)) { ERR("bind"); __leave; } mreq.ipv6mr_multiaddr = ((SOCKADDR_IN6*)&mcaddr)->sin6_addr; if (SOCKET_ERROR == setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&mreq, sizeof mreq )) { ERR("setsockopt IPV6_ADD_MEMBRESHIP"); __leave; } // PktInfo if (!SetIpv6PktInfoOption(sock)) { ERR("SetIpv6PktInfoOption"); __leave; } if(!AllocAndInitIpv6PktInfo(&wsamsg)) { ERR("AllocAndInitIpv6PktInfo"); __leave; } // data buffer wsabuf.buf = (CHAR*)MALLOC(100); if(NULL == wsabuf.buf) { ERR("HeapAlloc"); __leave; } wsabuf.len = (ULONG)MSIZE(wsabuf.buf); wsamsg.lpBuffers = &wsabuf; wsamsg.dwBufferCount = 1; // packet source address wsamsg.name = (SOCKADDR*)&remoteaddr; wsamsg.namelen = sizeof remoteaddr; //Post overlapped WSARecvMsg InitOverlap(&over); if (NULL == (WSARecvMsg = GetWSARecvMsgFunctionPointer())) { ERR("GetWSARecvMsgFunctionPointer"); __leave; } if (SOCKET_ERROR == WSARecvMsg(sock, &wsamsg, &dwBytes, &over, NULL )) { if (WSA_IO_PENDING != WSAGetLastError()) { ERR("WSARecvMsg"); __leave; } } //set send interface if (SOCKET_ERROR == SetSendInterface(sock,(SOCKADDR*)&addr)) { ERR("SetSendInterface"); __leave; } //send msg to multicast SET_PORT((SOCKADDR*)&mcaddr,DEFAULT_PORT); //send a few packets for (i=0; i<5; i++) { if (SOCKET_ERROR == (rc = sendto(sock, TST_MSG, lstrlenA(TST_MSG), 0, (SOCKADDR*)&mcaddr, sizeof (mcaddr) ))) { ERR("sendto"); __leave; } printf("Sent %d bytes\n",rc); } dwRet = WaitForSingleObject(over.hEvent,DEFAULT_WAIT); if (dwRet) { printf("%s\n",gai_strerror(dwRet)); __leave; } if (!WSAGetOverlappedResult(sock, &over, &dwBytes, TRUE, &dwFlags )) { ERR("WSAGetOverlappedResult"); __leave; } printf("WSARecvMsg completed with %d bytes\n",dwBytes); // if multicast packet do further processing if (MSG_MCAST & wsamsg.dwFlags) { if (ProcessIpv6Msg(&wsamsg)) { //do something more interesting here printf("Recvd multicast msg.\n"); } } } __finally { CLOSESOCK(sock); FREE(wsabuf.buf); FREE(wsamsg.Control.buf); CLOSESOCKEVENT(over.hEvent); if(nStartup) WSACleanup(); } return 0; }
Rt_map * setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, char *_rtldname, ulong_t ld_base, ulong_t interp_base, int fd, Phdr *phdr, char *execname, char **argv, uid_t uid, uid_t euid, gid_t gid, gid_t egid, void *aoutdyn, int auxflags, uint_t *hwcap) { Rt_map *rlmp, *mlmp, *clmp, **tobj = NULL; Ehdr *ehdr; rtld_stat_t status; int features = 0, ldsoexec = 0; size_t eaddr, esize; char *str, *argvname; Word lmflags; mmapobj_result_t *mpp; Fdesc fdr = { 0 }, fdm = { 0 }; Rej_desc rej = { 0 }; APlist *ealp = NULL; /* * Now that ld.so has relocated itself, initialize our own 'environ' so * as to establish an address suitable for any libc requirements. */ _environ = (char **)((ulong_t)auxv - sizeof (char *)); _init(); _environ = envp; /* * Establish a base time. Total time diagnostics start from entering * ld.so.1 here, however the base time is reset each time the ld.so.1 * is re-entered. Note also, there will be a large time associated * with the first diagnostic from ld.so.1, as bootstrapping ld.so.1 * and establishing the liblddbg infrastructure takes some time. */ (void) gettimeofday(&DBG_TOTALTIME, NULL); DBG_DELTATIME = DBG_TOTALTIME; /* * Determine how ld.so.1 has been executed. */ if ((fd == -1) && (phdr == NULL)) { /* * If we received neither the AT_EXECFD nor the AT_PHDR aux * vector, ld.so.1 must have been invoked directly from the * command line. */ ldsoexec = 1; /* * AT_SUN_EXECNAME provides the most precise name, if it is * available, otherwise fall back to argv[0]. At this time, * there is no process name. */ if (execname) rtldname = execname; else if (argv[0]) rtldname = argv[0]; else rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN); } else { /* * Otherwise, we have a standard process. AT_SUN_EXECNAME * provides the most precise name, if it is available, * otherwise fall back to argv[0]. Provided the application * is already mapped, the process is the application, so * simplify the application name for use in any diagnostics. */ if (execname) argvname = execname; else if (argv[0]) argvname = execname = argv[0]; else argvname = execname = (char *)MSG_INTL(MSG_STR_UNKNOWN); if (fd == -1) { if ((str = strrchr(argvname, '/')) != NULL) procname = ++str; else procname = argvname; } /* * At this point, we don't know the runtime linkers full path * name. The _rtldname passed to us is the SONAME of the * runtime linker, which is typically /lib/ld.so.1 no matter * what the full path is. Use this for now, we'll reset the * runtime linkers name once the application is analyzed. */ if (_rtldname) { if ((str = strrchr(_rtldname, '/')) != NULL) rtldname = ++str; else rtldname = _rtldname; } else rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN); /* exec() brought in two objects for us. Count the second one */ cnt_map++; } /* * Initialize any global variables. */ at_flags = _flags; if ((org_scapset->sc_plat = _platform) != NULL) org_scapset->sc_platsz = strlen(_platform); if (org_scapset->sc_plat == NULL) platform_name(org_scapset); if (org_scapset->sc_mach == NULL) machine_name(org_scapset); /* * If pagesize is unspecified find its value. */ if ((syspagsz = _syspagsz) == 0) syspagsz = _sysconfig(_CONFIG_PAGESIZE); /* * Add the unused portion of the last data page to the free space list. * The page size must be set before doing this. Here, _end refers to * the end of the runtime linkers bss. Note that we do not use the * unused data pages from any included .so's to supplement this free * space as badly behaved .os's may corrupt this data space, and in so * doing ruin our data. */ eaddr = S_DROUND((size_t)&_end); esize = eaddr % syspagsz; if (esize) { esize = syspagsz - esize; addfree((void *)eaddr, esize); } /* * Establish initial link-map list flags, and link-map list alists. */ if (alist_append(&lml_main.lm_lists, NULL, sizeof (Lm_cntl), AL_CNT_LMLISTS) == NULL) return (0); lml_main.lm_flags |= LML_FLG_BASELM; lml_main.lm_lmid = LM_ID_BASE; lml_main.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_BASE); if (alist_append(&lml_rtld.lm_lists, NULL, sizeof (Lm_cntl), AL_CNT_LMLISTS) == NULL) return (0); lml_rtld.lm_flags |= (LML_FLG_RTLDLM | LML_FLG_HOLDLOCK); lml_rtld.lm_tflags |= LML_TFLG_NOAUDIT; lml_rtld.lm_lmid = LM_ID_LDSO; lml_rtld.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_LDSO); /* * Determine whether we have a secure executable. */ security(uid, euid, gid, egid, auxflags); /* * Make an initial pass of environment variables to pick off those * related to locale processing. At the same time, collect and save * any LD_XXXX variables for later processing. Note that this later * processing will be skipped if ld.so.1 is invoked from the command * line with -e LD_NOENVIRON. */ if (envp && (readenv_user((const char **)envp, &ealp) == 1)) return (0); /* * If ld.so.1 has been invoked directly, process its arguments. */ if (ldsoexec) { /* * Process any arguments that are specific to ld.so.1, and * reorganize the process stack to effectively remove ld.so.1 * from the stack. Reinitialize the environment pointer, as * this pointer may have been shifted after skipping ld.so.1's * arguments. */ if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags), &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) { eprintf(&lml_main, ERR_NONE, MSG_INTL(MSG_USG_BADOPT)); return (0); } _environ = envp; /* * Open the object that ld.so.1 is to execute. */ argvname = execname = argv[0]; if ((fd = open(argvname, O_RDONLY)) == -1) { int err = errno; eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), argvname, strerror(err)); return (0); } } /* * Having processed any ld.so.1 command line options, return to process * any LD_XXXX environment variables. */ if (ealp) { if (((rtld_flags & RT_FL_NOENVIRON) == 0) && (procenv_user(ealp, &(lml_main.lm_flags), &(lml_main.lm_tflags), (aoutdyn != 0)) == 1)) return (0); free(ealp); } /* * Initialize a hardware capability descriptor for use in comparing * each loaded object. The aux vector must provide AF_SUN_HWCAPVERIFY, * as prior to this setting any hardware capabilities that were found * could not be relied upon. */ if (auxflags & AF_SUN_HWCAPVERIFY) { rtld_flags2 |= RT_FL2_HWCAP; org_scapset->sc_hw_1 = (Xword)hwcap[0]; org_scapset->sc_hw_2 = (Xword)hwcap[1]; } /* * Create a mapping descriptor for ld.so.1. We can determine our * two segments information from known symbols. */ if ((mpp = calloc(2, sizeof (mmapobj_result_t))) == NULL) return (0); mpp[0].mr_addr = (caddr_t)M_PTRUNC(ld_base); mpp[0].mr_msize = (caddr_t)&_etext - mpp[0].mr_addr; mpp[0].mr_fsize = mpp[0].mr_msize; mpp[0].mr_prot = (PROT_READ | PROT_EXEC); mpp[1].mr_addr = (caddr_t)M_PTRUNC((uintptr_t)&r_debug); mpp[1].mr_msize = (caddr_t)&_end - mpp[1].mr_addr; mpp[1].mr_fsize = (caddr_t)&_edata - mpp[1].mr_addr; mpp[1].mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC); if ((fdr.fd_nname = stravl_insert(_rtldname, 0, 0, 0)) == NULL) return (0); if ((rlmp = elf_new_lmp(&lml_rtld, ALIST_OFF_DATA, &fdr, (Addr)mpp->mr_addr, (size_t)((uintptr_t)eaddr - (uintptr_t)ld_base), NULL, NULL, NULL)) == NULL) return (0); MMAPS(rlmp) = mpp; MMAPCNT(rlmp) = 2; PADSTART(rlmp) = (ulong_t)mpp[0].mr_addr; PADIMLEN(rlmp) = (ulong_t)mpp[0].mr_addr + (ulong_t)mpp[1].mr_addr + (ulong_t)mpp[1].mr_msize; MODE(rlmp) |= (RTLD_LAZY | RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD); FLAGS(rlmp) |= (FLG_RT_ANALYZED | FLG_RT_RELOCED | FLG_RT_INITDONE | FLG_RT_INITCLCT | FLG_RT_FINICLCT | FLG_RT_MODESET); /* * Initialize the runtime linkers information. */ interp = &_interp; interp->i_name = (char *)rtldname; interp->i_faddr = (caddr_t)ADDR(rlmp); ldso_plt_init(rlmp); /* * Map in the file, if exec has not already done so, or if the file * was passed as an argument to an explicit execution of ld.so.1 from * the command line. */ if (fd != -1) { /* * Map the file. Once the object is mapped we no longer need * the file descriptor. */ (void) rtld_fstat(fd, &status); fdm.fd_oname = argvname; fdm.fd_ftp = map_obj(&lml_main, &fdm, status.st_size, argvname, fd, &rej); (void) close(fd); if (fdm.fd_ftp == NULL) { Conv_reject_desc_buf_t rej_buf; eprintf(&lml_main, ERR_FATAL, MSG_INTL(err_reject[rej.rej_type]), argvname, conv_reject_desc(&rej, &rej_buf, M_MACH)); return (0); } /* * Finish processing the loading of the file. */ if ((fdm.fd_nname = stravl_insert(argvname, 0, 0, 0)) == NULL) return (0); fdm.fd_dev = status.st_dev; fdm.fd_ino = status.st_ino; if ((mlmp = load_file(&lml_main, ALIST_OFF_DATA, NULL, &fdm, NULL)) == NULL) return (0); /* * We now have a process name for error diagnostics. */ if ((str = strrchr(argvname, '/')) != NULL) procname = ++str; else procname = argvname; if (ldsoexec) { mmapobj_result_t *mpp = MMAPS(mlmp); uint_t mnum, mapnum = MMAPCNT(mlmp); void *brkbase = NULL; /* * Since ld.so.1 was the primary executed object - the * brk() base has not yet been initialized, we need to * initialize it. For an executable, initialize it to * the end of the object. For a shared object (ET_DYN) * initialize it to the first page in memory. */ for (mnum = 0; mnum < mapnum; mnum++, mpp++) brkbase = mpp->mr_addr + mpp->mr_msize; if (brkbase == NULL) brkbase = (void *)syspagsz; if (_brk_unlocked(brkbase) == -1) { int err = errno; eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_BRK), argvname, strerror(err)); return (0); } } } else { /* * Set up function ptr and arguments according to the type * of file class the executable is. (Currently only supported * types are ELF and a.out format.) Then create a link map * for the executable. */ if (aoutdyn) { #ifdef A_OUT mmapobj_result_t *mpp; /* * Create a mapping structure sufficient to describe * a single two segments. The ADDR() of the a.out is * established as 0, which is required but the AOUT * relocation code. */ if ((mpp = calloc(sizeof (mmapobj_result_t), 2)) == NULL) return (0); if ((fdm.fd_nname = stravl_insert(execname, 0, 0, 0)) == NULL) return (0); if ((mlmp = aout_new_lmp(&lml_main, ALIST_OFF_DATA, &fdm, 0, 0, aoutdyn, NULL, NULL)) == NULL) return (0); /* * Establish the true mapping information for the a.out. */ if (aout_get_mmap(&lml_main, mpp)) { free(mpp); return (0); } MSIZE(mlmp) = (size_t)(mpp[1].mr_addr + mpp[1].mr_msize) - S_ALIGN((size_t)mpp[0].mr_addr, syspagsz); MMAPS(mlmp) = mpp; MMAPCNT(mlmp) = 2; PADSTART(mlmp) = (ulong_t)mpp->mr_addr; PADIMLEN(mlmp) = mpp->mr_msize; /* * Disable any object configuration cache (BCP apps * bring in sbcp which can benefit from any object * cache, but both the app and sbcp can't use the same * objects). */ rtld_flags |= RT_FL_NOOBJALT; /* * Make sure no-direct bindings are in effect. */ lml_main.lm_tflags |= LML_TFLG_NODIRECT; #else eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_ERR_REJ_UNKFILE), argvname); return (0); #endif } else if (phdr) { Phdr *pptr; Off i_offset = 0; Addr base = 0; ulong_t phsize; mmapobj_result_t *mpp, *fmpp, *hmpp = NULL; uint_t mapnum = 0; int i; size_t msize; /* * Using the executables phdr address determine the base * address of the input file. NOTE, this assumes the * program headers and elf header are part of the same * mapped segment. Although this has held for many * years now, it might be more flexible if the kernel * gave use the ELF headers start address, rather than * the Program headers. * * Determine from the ELF header if we're been called * from a shared object or dynamic executable. If the * latter, then any addresses within the object are used * as is. Addresses within shared objects must be added * to the process's base address. */ ehdr = (Ehdr *)((Addr)phdr - phdr->p_offset); phsize = ehdr->e_phentsize; if (ehdr->e_type == ET_DYN) base = (Addr)ehdr; /* * Allocate a mapping array to retain mapped segment * information. */ if ((fmpp = mpp = calloc(ehdr->e_phnum, sizeof (mmapobj_result_t))) == NULL) return (0); /* * Extract the needed information from the segment * headers. */ for (i = 0, pptr = phdr; i < ehdr->e_phnum; i++) { if (pptr->p_type == PT_INTERP) { i_offset = pptr->p_offset; interp->i_faddr = (caddr_t)interp_base; } if ((pptr->p_type == PT_LOAD) && (pptr->p_filesz || pptr->p_memsz)) { int perm = (PROT_READ | PROT_EXEC); size_t off; if (i_offset && pptr->p_filesz && (i_offset >= pptr->p_offset) && (i_offset <= (pptr->p_memsz + pptr->p_offset))) { interp->i_name = (char *) pptr->p_vaddr + i_offset - pptr->p_offset + base; i_offset = 0; } if (pptr->p_flags & PF_W) perm |= PROT_WRITE; /* * Retain segments mapping info. Round * each segment to a page boundary, as * this insures addresses are suitable * for mprotect() if required. */ off = pptr->p_vaddr + base; if (hmpp == NULL) { hmpp = mpp; mpp->mr_addr = (caddr_t)ehdr; } else mpp->mr_addr = (caddr_t)off; off -= (size_t)(uintptr_t)mpp->mr_addr; mpp->mr_msize = pptr->p_memsz + off; mpp->mr_fsize = pptr->p_filesz + off; mpp->mr_prot = perm; mpp++, mapnum++; } pptr = (Phdr *)((ulong_t)pptr + phsize); } mpp--; msize = (size_t)(mpp->mr_addr + mpp->mr_msize) - S_ALIGN((size_t)fmpp->mr_addr, syspagsz); if ((fdm.fd_nname = stravl_insert(execname, 0, 0, 0)) == NULL) return (0); if ((mlmp = elf_new_lmp(&lml_main, ALIST_OFF_DATA, &fdm, (Addr)hmpp->mr_addr, msize, NULL, NULL, NULL)) == NULL) return (0); MMAPS(mlmp) = fmpp; MMAPCNT(mlmp) = mapnum; PADSTART(mlmp) = (ulong_t)fmpp->mr_addr; PADIMLEN(mlmp) = (ulong_t)fmpp->mr_addr + (ulong_t)mpp->mr_addr + (ulong_t)mpp->mr_msize; } } /* * Establish the interpretors name as that defined within the initial * object (executable). This provides for ORIGIN processing of ld.so.1 * dependencies. Note, the NAME() of the object remains that which was * passed to us as the SONAME on execution. */ if (ldsoexec == 0) { size_t len = strlen(interp->i_name); if (expand(&interp->i_name, &len, 0, 0, (PD_TKN_ISALIST | PD_TKN_CAP), rlmp) & PD_TKN_RESOLVED) fdr.fd_flags |= FLG_FD_RESOLVED; } fdr.fd_pname = interp->i_name; (void) fullpath(rlmp, &fdr); /* * The runtime linker acts as a filtee for various dl*() functions that * are defined in libc (and libdl). Make sure this standard name for * the runtime linker is also registered in the FullPathNode AVL tree. */ (void) fpavl_insert(&lml_rtld, rlmp, _rtldname, 0); /* * Having established the true runtime linkers name, simplify the name * for error diagnostics. */ if ((str = strrchr(PATHNAME(rlmp), '/')) != NULL) rtldname = ++str; else rtldname = PATHNAME(rlmp); /* * Expand the fullpath name of the application. This typically occurs * as a part of loading an object, but as the kernel probably mapped * it in, complete this processing now. */ (void) fullpath(mlmp, 0); /* * Some troublesome programs will change the value of argv[0]. Dupping * the process string protects us, and insures the string is left in * any core files. */ if ((str = (char *)strdup(procname)) == NULL) return (0); procname = str; FLAGS(mlmp) |= (FLG_RT_ISMAIN | FLG_RT_MODESET); FLAGS1(mlmp) |= FL1_RT_USED; /* * It's the responsibility of MAIN(crt0) to call it's _init and _fini * section, therefore null out any INIT/FINI so that this object isn't * collected during tsort processing. And, if the application has no * initarray or finiarray we can economize on establishing bindings. */ INIT(mlmp) = FINI(mlmp) = NULL; if ((INITARRAY(mlmp) == NULL) && (FINIARRAY(mlmp) == NULL)) FLAGS1(mlmp) |= FL1_RT_NOINIFIN; /* * Identify lddstub if necessary. */ if (lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) FLAGS1(mlmp) |= FL1_RT_LDDSTUB; /* * Retain our argument information for use in dlinfo. */ argsinfo.dla_argv = argv--; argsinfo.dla_argc = (long)*argv; argsinfo.dla_envp = envp; argsinfo.dla_auxv = auxv; (void) enter(0); /* * Add our two main link-maps to the dynlm_list */ if (aplist_append(&dynlm_list, &lml_main, AL_CNT_DYNLIST) == NULL) return (0); if (aplist_append(&dynlm_list, &lml_rtld, AL_CNT_DYNLIST) == NULL) return (0); /* * Reset the link-map counts for both lists. The init count is used to * track how many objects have pending init sections, this gets incre- * mented each time an object is relocated. Since ld.so.1 relocates * itself, it's init count will remain zero. * The object count is used to track how many objects have pending fini * sections, as ld.so.1 handles its own fini we can zero its count. */ lml_main.lm_obj = 1; lml_rtld.lm_obj = 0; /* * Initialize debugger information structure. Some parts of this * structure were initialized statically. */ r_debug.rtd_rdebug.r_map = (Link_map *)lml_main.lm_head; r_debug.rtd_rdebug.r_ldsomap = (Link_map *)lml_rtld.lm_head; r_debug.rtd_rdebug.r_ldbase = r_debug.rtd_rdebug.r_ldsomap->l_addr; r_debug.rtd_dynlmlst = &dynlm_list; /* * Determine the dev/inode information for the executable to complete * load_so() checking for those who might dlopen(a.out). */ if (rtld_stat(PATHNAME(mlmp), &status) == 0) { STDEV(mlmp) = status.st_dev; STINO(mlmp) = status.st_ino; } /* * Initialize any configuration information. */ if (!(rtld_flags & RT_FL_NOCFG)) { if ((features = elf_config(mlmp, (aoutdyn != 0))) == -1) return (0); } #if defined(_ELF64) /* * If this is a 64-bit process, determine whether this process has * restricted the process address space to 32-bits. Any dependencies * that are restricted to a 32-bit address space can only be loaded if * the executable has established this requirement. */ if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32) rtld_flags2 |= RT_FL2_ADDR32; #endif /* * Establish any alternative capabilities, and validate this object * if it defines it's own capabilities information. */ if (cap_alternative() == 0) return (0); if (cap_check_lmp(mlmp, &rej) == 0) { if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) { /* LINTED */ (void) printf(MSG_INTL(ldd_warn[rej.rej_type]), NAME(mlmp), rej.rej_str); } else { /* LINTED */ eprintf(&lml_main, ERR_FATAL, MSG_INTL(err_reject[rej.rej_type]), NAME(mlmp), rej.rej_str); return (0); } } /* * Establish the modes of the initial object. These modes are * propagated to any preloaded objects and explicit shared library * dependencies. * * If we're generating a configuration file using crle(1), remove * any RTLD_NOW use, as we don't want to trigger any relocation proc- * essing during crle(1)'s first past (this would just be unnecessary * overhead). Any filters are explicitly loaded, and thus RTLD_NOW is * not required to trigger filter loading. * * Note, RTLD_NOW may have been established during analysis of the * application had the application been built -z now. */ MODE(mlmp) |= (RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD); if (rtld_flags & RT_FL_CONFGEN) { MODE(mlmp) |= RTLD_CONFGEN; MODE(mlmp) &= ~RTLD_NOW; rtld_flags2 &= ~RT_FL2_BINDNOW; } if ((MODE(mlmp) & RTLD_NOW) == 0) { if (rtld_flags2 & RT_FL2_BINDNOW) MODE(mlmp) |= RTLD_NOW; else MODE(mlmp) |= RTLD_LAZY; } /* * If debugging was requested initialize things now that any cache has * been established. A user can specify LD_DEBUG=help to discover the * list of debugging tokens available without running the application. * However, don't allow this setting from a configuration file. * * Note, to prevent recursion issues caused by loading and binding the * debugging libraries themselves, a local debugging descriptor is * initialized. Once the debugging setup has completed, this local * descriptor is copied to the global descriptor which effectively * enables diagnostic output. * * Ignore any debugging request if we're being monitored by a process * that expects the old getpid() initialization handshake. */ if ((rpl_debug || prm_debug) && ((rtld_flags & RT_FL_DEBUGGER) == 0)) { Dbg_desc _dbg_desc = {0}; struct timeval total = DBG_TOTALTIME; struct timeval delta = DBG_DELTATIME; if (rpl_debug) { if (dbg_setup(rpl_debug, &_dbg_desc) == 0) return (0); if (_dbg_desc.d_extra & DBG_E_HELP_EXIT) rtldexit(&lml_main, 0); } if (prm_debug) (void) dbg_setup(prm_debug, &_dbg_desc); *dbg_desc = _dbg_desc; DBG_TOTALTIME = total; DBG_DELTATIME = delta; } /* * Now that debugging is enabled generate any diagnostics from any * previous events. */ if (DBG_ENABLED) { DBG_CALL(Dbg_cap_val(&lml_main, org_scapset, alt_scapset, M_MACH)); DBG_CALL(Dbg_file_config_dis(&lml_main, config->c_name, features)); DBG_CALL(Dbg_file_ldso(rlmp, envp, auxv, LIST(rlmp)->lm_lmidstr, ALIST_OFF_DATA)); if (THIS_IS_ELF(mlmp)) { DBG_CALL(Dbg_file_elf(&lml_main, PATHNAME(mlmp), ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr, ALIST_OFF_DATA)); } else { DBG_CALL(Dbg_file_aout(&lml_main, PATHNAME(mlmp), ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr, ALIST_OFF_DATA)); } } /* * Enable auditing. */ if (rpl_audit || prm_audit || profile_lib) { int ndx; const char *aud[3]; aud[0] = rpl_audit; aud[1] = prm_audit; aud[2] = profile_lib; /* * Any global auditing (set using LD_AUDIT or LD_PROFILE) that * can't be established is non-fatal. */ if ((auditors = calloc(1, sizeof (Audit_desc))) == NULL) return (0); for (ndx = 0; ndx < 3; ndx++) { if (aud[ndx]) { if ((auditors->ad_name = strdup(aud[ndx])) == NULL) return (0); rtld_flags2 |= RT_FL2_FTL2WARN; (void) audit_setup(mlmp, auditors, PD_FLG_EXTLOAD, NULL); rtld_flags2 &= ~RT_FL2_FTL2WARN; } } lml_main.lm_tflags |= auditors->ad_flags; } if (AUDITORS(mlmp)) { /* * Any object required auditing (set with a DT_DEPAUDIT dynamic * entry) that can't be established is fatal. */ if (FLAGS1(mlmp) & FL1_RT_GLOBAUD) { /* * If this object requires global auditing, use the * local auditing information to set the global * auditing descriptor. The effect is that a * DT_DEPAUDIT act as an LD_AUDIT. */ if ((auditors == NULL) && ((auditors = calloc(1, sizeof (Audit_desc))) == NULL)) return (0); auditors->ad_name = AUDITORS(mlmp)->ad_name; if (audit_setup(mlmp, auditors, 0, NULL) == 0) return (0); lml_main.lm_tflags |= auditors->ad_flags; /* * Clear the local auditor information. */ free((void *) AUDITORS(mlmp)); AUDITORS(mlmp) = NULL; } else { /* * Establish any local auditing. */ if (audit_setup(mlmp, AUDITORS(mlmp), 0, NULL) == 0) return (0); AFLAGS(mlmp) |= AUDITORS(mlmp)->ad_flags; lml_main.lm_flags |= LML_FLG_LOCAUDIT; } } /* * Explicitly add the initial object and ld.so.1 to those objects being * audited. Note, although the ld.so.1 link-map isn't auditable, * establish a cookie for ld.so.1 as this may be bound to via the * dl*() family. */ if ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_MASK) { if (((audit_objopen(mlmp, mlmp) == 0) || (audit_objopen(mlmp, rlmp) == 0)) && (AFLAGS(mlmp) & LML_TFLG_AUD_MASK)) return (0); } /* * Map in any preloadable shared objects. Establish the caller as the * head of the main link-map list. In the case of being exercised from * lddstub, the caller gets reassigned to the first target shared object * so as to provide intuitive diagnostics from ldd(). * * Note, it is valid to preload a 4.x shared object with a 5.0 * executable (or visa-versa), as this functionality is required by * ldd(1). */ clmp = mlmp; if (rpl_preload && (preload(rpl_preload, mlmp, &clmp) == 0)) return (0); if (prm_preload && (preload(prm_preload, mlmp, &clmp) == 0)) return (0); /* * Load all dependent (needed) objects. */ if (analyze_lmc(&lml_main, ALIST_OFF_DATA, mlmp, mlmp, NULL) == NULL) return (0); /* * Relocate all the dependencies we've just added. * * If this process has been established via crle(1), the environment * variable LD_CONFGEN will have been set. crle(1) may create this * process twice. The first time crle only needs to gather dependency * information. The second time, is to dldump() the images. * * If we're only gathering dependencies, relocation is unnecessary. * As crle(1) may be building an arbitrary family of objects, they may * not fully relocate either. Hence the relocation phase is not carried * out now, but will be called by crle(1) once all objects have been * loaded. */ if ((rtld_flags & RT_FL_CONFGEN) == 0) { DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD)); if (relocate_lmc(&lml_main, ALIST_OFF_DATA, mlmp, mlmp, NULL) == 0) return (0); /* * Inform the debuggers that basic process initialization is * complete, and that the state of ld.so.1 (link-map lists, * etc.) is stable. This handshake enables the debugger to * initialize themselves, and consequently allows the user to * set break points in .init code. * * Most new debuggers use librtld_db to monitor activity events. * Older debuggers indicated their presence by setting the * DT_DEBUG entry in the dynamic executable (see elf_new_lm()). * In this case, getpid() is called so that the debugger can * catch the system call. This old mechanism has some * restrictions, as getpid() should not be called prior to * basic process initialization being completed. This * restriction has become increasingly difficult to maintain, * as the use of auditors, LD_DEBUG, and the initialization * handshake with libc can result in "premature" getpid() * calls. The use of this getpid() handshake is expected to * disappear at some point in the future, and there is intent * to work towards that goal. */ rd_event(&lml_main, RD_DLACTIVITY, RT_CONSISTENT); rd_event(&lml_rtld, RD_DLACTIVITY, RT_CONSISTENT); if (rtld_flags & RT_FL_DEBUGGER) { r_debug.rtd_rdebug.r_flags |= RD_FL_ODBG; (void) getpid(); } } /* * Indicate preinit activity, and call any auditing routines. These * routines are called before initializing any threads via libc, or * before collecting the complete set of .inits on the primary link-map. * Although most libc interfaces are encapsulated in local routines * within libc, they have been known to escape (ie. call a .plt). As * the appcert auditor uses preinit as a trigger to establish some * external interfaces to the main link-maps libc, we need to activate * this trigger before exercising any code within libc. Additionally, * I wouldn't put it past an auditor to add additional objects to the * primary link-map. Hence, we collect .inits after the audit call. */ rd_event(&lml_main, RD_PREINIT, 0); if (aud_activity || ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_ACTIVITY)) audit_activity(mlmp, LA_ACT_CONSISTENT); if (aud_preinit || ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_PREINIT)) audit_preinit(mlmp); /* * If we're creating initial configuration information, we're done * now that the auditing step has been called. */ if (rtld_flags & RT_FL_CONFGEN) { leave(LIST(mlmp), 0); return (mlmp); } /* * Sort the .init sections of all objects we've added. If we're * tracing we only need to execute this under ldd(1) with the -i or -u * options. */ lmflags = lml_main.lm_flags; if (((lmflags & LML_FLG_TRC_ENABLE) == 0) || (lmflags & (LML_FLG_TRC_INIT | LML_FLG_TRC_UNREF))) { if ((tobj = tsort(mlmp, LIST(mlmp)->lm_init, RT_SORT_REV)) == (Rt_map **)S_ERROR) return (0); } /* * If we are tracing we're done. This is the one legitimate use of a * direct call to rtldexit() rather than return, as we don't want to * return and jump to the application. */ if (lmflags & LML_FLG_TRC_ENABLE) { unused(&lml_main); rtldexit(&lml_main, 0); } /* * Check if this instance of the linker should have a primary link * map. This flag allows multiple copies of the -same- -version- * of the linker (and libc) to run in the same address space. * * Without this flag we only support one copy of the linker in a * process because by default the linker will always try to * initialize at one primary link map The copy of libc which is * initialized on a primary link map will initialize global TLS * data which can be shared with other copies of libc in the * process. The problem is that if there is more than one copy * of the linker, only one copy should link libc onto a primary * link map, otherwise libc will attempt to re-initialize global * TLS data. So when a copy of the linker is loaded with this * flag set, it will not initialize any primary link maps since * presumably another copy of the linker will do this. * * Note that this flag only allows multiple copies of the -same- * -version- of the linker (and libc) to coexist. This approach * will not work if we are trying to load different versions of * the linker and libc into the same process. The reason for * this is that the format of the global TLS data may not be * the same for different versions of libc. In this case each * different version of libc must have it's own primary link map * and be able to maintain it's own TLS data. The only way this * can be done is by carefully managing TLS pointers on transitions * between code associated with each of the different linkers. * Note that this is actually what is done for processes in lx * branded zones. Although in the lx branded zone case, the * other linker and libc are actually gld and glibc. But the * same general TLS management mechanism used by the lx brand * would apply to any attempts to run multiple versions of the * solaris linker and libc in a single process. */ if (auxflags & AF_SUN_NOPLM) rtld_flags2 |= RT_FL2_NOPLM; /* * Establish any static TLS for this primary link-map. Note, regardless * of whether TLS is available, an initial handshake occurs with libc to * indicate we're processing the primary link-map. Having identified * the primary link-map, initialize threads. */ if (rt_get_extern(&lml_main, mlmp) == 0) return (0); if ((rtld_flags2 & RT_FL2_NOPLM) == 0) { if (tls_statmod(&lml_main, mlmp) == 0) return (0); rt_thr_init(&lml_main); rtld_flags2 |= RT_FL2_PLMSETUP; } else { rt_thr_init(&lml_main); } /* * Fire all dependencies .init sections. Identify any unused * dependencies, and leave the runtime linker - effectively calling * the dynamic executables entry point. */ call_array(PREINITARRAY(mlmp), (uint_t)PREINITARRAYSZ(mlmp), mlmp, SHT_PREINIT_ARRAY); if (tobj) call_init(tobj, DBG_INIT_SORT); rd_event(&lml_main, RD_POSTINIT, 0); unused(&lml_main); DBG_CALL(Dbg_util_call_main(mlmp)); rtld_flags |= (RT_FL_OPERATION | RT_FL_APPLIC); leave(LIST(mlmp), 0); return (mlmp); }