⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclloadaix.c

📁 linux系统下的音频通信
💻 C
字号:
/*  * tclLoadAix.c -- * *	This file implements the dlopen and dlsym APIs under the *	AIX operating system, to enable the Tcl "load" command to *	work.  This code was provided by Jens-Uwe Mager. * *	This file is subject to the following copyright notice, which is *	different from the notice used elsewhere in Tcl.  The file has *	been modified to incorporate the file dlfcn.h in-line. * *	Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH *	Not derived from licensed software. *	Permission is granted to freely use, copy, modify, and redistribute *	this software, provided that the author is not construed to be liable *	for any results of using the software, alterations are clearly marked *	as such, and this notice is not modified. * * SCCS: @(#) tclLoadAix.c 1.11 96/10/07 10:41:24 * * Note:  this file has been altered from the original in a few * ways in order to work properly with Tcl. *//* * @(#)dlfcn.c	1.7 revision of 95/08/14  19:08:38 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH * 30159 Hannover, Germany */#include <stdio.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ldr.h>#include <a.out.h>#include <ldfcn.h>#include "../compat/dlfcn.h"/* * We simulate dlopen() et al. through a call to load. Because AIX has * no call to find an exported symbol we read the loader section of the * loaded module and build a list of exported symbols and their virtual * address. */typedef struct {	char		*name;		/* the symbols's name */	void		*addr;		/* its relocated virtual address */} Export, *ExportPtr;/* * xlC uses the following structure to list its constructors and * destructors. This is gleaned from the output of munch. */typedef struct {	void (*init)(void);		/* call static constructors */	void (*term)(void);		/* call static destructors */} Cdtor, *CdtorPtr;/* * The void * handle returned from dlopen is actually a ModulePtr. */typedef struct Module {	struct Module	*next;	char		*name;		/* module name for refcounting */	int		refCnt;		/* the number of references */	void		*entry;		/* entry point from load */	struct dl_info	*info;		/* optional init/terminate functions */	CdtorPtr	cdtors;		/* optional C++ constructors */	int		nExports;	/* the number of exports found */	ExportPtr	exports;	/* the array of exports */} Module, *ModulePtr;/* * We keep a list of all loaded modules to be able to call the fini * handlers and destructors at atexit() time. */static ModulePtr modList;/* * The last error from one of the dl* routines is kept in static * variables here. Each error is returned only once to the caller. */static char errbuf[BUFSIZ];static int errvalid;static void caterr(char *);static int readExports(ModulePtr);static void terminate(void);static void *findMain(void);VOID *dlopen(const char *path, int mode){	register ModulePtr mp;	static void *mainModule;	/*	 * Upon the first call register a terminate handler that will	 * close all libraries. Also get a reference to the main module	 * for use with loadbind.	 */	if (!mainModule) {		if ((mainModule = findMain()) == NULL)			return NULL;		atexit(terminate);	}	/*	 * Scan the list of modules if we have the module already loaded.	 */	for (mp = modList; mp; mp = mp->next)		if (strcmp(mp->name, path) == 0) {			mp->refCnt++;			return (VOID *) mp;		}	if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {		errvalid++;		strcpy(errbuf, "calloc: ");		strcat(errbuf, strerror(errno));		return (VOID *) NULL;	}	mp->name = malloc((unsigned) (strlen(path) + 1));	strcpy(mp->name, path);	/*	 * load should be declared load(const char *...). Thus we	 * cast the path to a normal char *. Ugly.	 */	if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {		free(mp->name);		free(mp);		errvalid++;		strcpy(errbuf, "dlopen: ");		strcat(errbuf, path);		strcat(errbuf, ": ");		/*		 * If AIX says the file is not executable, the error		 * can be further described by querying the loader about		 * the last error.		 */		if (errno == ENOEXEC) {			char *tmp[BUFSIZ/sizeof(char *)];			if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)				strcpy(errbuf, strerror(errno));			else {				char **p;				for (p = tmp; *p; p++)					caterr(*p);			}		} else			strcat(errbuf, strerror(errno));		return (VOID *) NULL;	}	mp->refCnt = 1;	mp->next = modList;	modList = mp;	if (loadbind(0, mainModule, mp->entry) == -1) {		dlclose(mp);		errvalid++;		strcpy(errbuf, "loadbind: ");		strcat(errbuf, strerror(errno));		return (VOID *) NULL;	}	/*	 * If the user wants global binding, loadbind against all other	 * loaded modules.	 */	if (mode & RTLD_GLOBAL) {		register ModulePtr mp1;		for (mp1 = mp->next; mp1; mp1 = mp1->next)			if (loadbind(0, mp1->entry, mp->entry) == -1) {				dlclose(mp);				errvalid++;				strcpy(errbuf, "loadbind: ");				strcat(errbuf, strerror(errno));				return (VOID *) NULL;			}	}	if (readExports(mp) == -1) {		dlclose(mp);		return (VOID *) NULL;	}	/*	 * If there is a dl_info structure, call the init function.	 */	if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {		if (mp->info->init)			(*mp->info->init)();	} else		errvalid = 0;	/*	 * If the shared object was compiled using xlC we will need	 * to call static constructors (and later on dlclose destructors).	 */	if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {		while (mp->cdtors->init) {			(*mp->cdtors->init)();			mp->cdtors++;		}	} else		errvalid = 0;	return (VOID *) mp;}/* * Attempt to decipher an AIX loader error message and append it * to our static error message buffer. */static void caterr(char *s){	register char *p = s;	while (*p >= '0' && *p <= '9')		p++;	switch(atoi(s)) {	case L_ERROR_TOOMANY:		strcat(errbuf, "to many errors");		break;	case L_ERROR_NOLIB:		strcat(errbuf, "can't load library");		strcat(errbuf, p);		break;	case L_ERROR_UNDEF:		strcat(errbuf, "can't find symbol");		strcat(errbuf, p);		break;	case L_ERROR_RLDBAD:		strcat(errbuf, "bad RLD");		strcat(errbuf, p);		break;	case L_ERROR_FORMAT:		strcat(errbuf, "bad exec format in");		strcat(errbuf, p);		break;	case L_ERROR_ERRNO:		strcat(errbuf, strerror(atoi(++p)));		break;	default:		strcat(errbuf, s);		break;	}}VOID *dlsym(void *handle, const char *symbol){	register ModulePtr mp = (ModulePtr)handle;	register ExportPtr ep;	register int i;	/*	 * Could speed up the search, but I assume that one assigns	 * the result to function pointers anyways.	 */	for (ep = mp->exports, i = mp->nExports; i; i--, ep++)		if (strcmp(ep->name, symbol) == 0)			return ep->addr;	errvalid++;	strcpy(errbuf, "dlsym: undefined symbol ");	strcat(errbuf, symbol);	return NULL;}char *dlerror(void){	if (errvalid) {		errvalid = 0;		return errbuf;	}	return NULL;}int dlclose(void *handle){	register ModulePtr mp = (ModulePtr)handle;	int result;	register ModulePtr mp1;	if (--mp->refCnt > 0)		return 0;	if (mp->info && mp->info->fini)		(*mp->info->fini)();	if (mp->cdtors)		while (mp->cdtors->term) {			(*mp->cdtors->term)();			mp->cdtors++;		}	result = unload(mp->entry);	if (result == -1) {		errvalid++;		strcpy(errbuf, strerror(errno));	}	if (mp->exports) {		register ExportPtr ep;		register int i;		for (ep = mp->exports, i = mp->nExports; i; i--, ep++)			if (ep->name)				free(ep->name);		free(mp->exports);	}	if (mp == modList)		modList = mp->next;	else {		for (mp1 = modList; mp1; mp1 = mp1->next)			if (mp1->next == mp) {				mp1->next = mp->next;				break;			}	}	free(mp->name);	free(mp);	return result;}static void terminate(void){	while (modList)		dlclose(modList);}/* * Build the export table from the XCOFF .loader section. */static int readExports(ModulePtr mp){	LDFILE *ldp = NULL;	SCNHDR sh, shdata;	LDHDR *lhp;	char *ldbuf;	LDSYM *ls;	int i;	ExportPtr ep;	if ((ldp = ldopen(mp->name, ldp)) == NULL) {		struct ld_info *lp;		char *buf;		int size = 4*1024;		if (errno != ENOENT) {			errvalid++;			strcpy(errbuf, "readExports: ");			strcat(errbuf, strerror(errno));			return -1;		}		/*		 * The module might be loaded due to the LIBPATH		 * environment variable. Search for the loaded		 * module using L_GETINFO.		 */		if ((buf = malloc(size)) == NULL) {			errvalid++;			strcpy(errbuf, "readExports: ");			strcat(errbuf, strerror(errno));			return -1;		}		while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {			free(buf);			size += 4*1024;			if ((buf = malloc(size)) == NULL) {				errvalid++;				strcpy(errbuf, "readExports: ");				strcat(errbuf, strerror(errno));				return -1;			}		}		if (i == -1) {			errvalid++;			strcpy(errbuf, "readExports: ");			strcat(errbuf, strerror(errno));			free(buf);			return -1;		}		/*		 * Traverse the list of loaded modules. The entry point		 * returned by load() does actually point to the data		 * segment origin.		 */		lp = (struct ld_info *)buf;		while (lp) {			if (lp->ldinfo_dataorg == mp->entry) {				ldp = ldopen(lp->ldinfo_filename, ldp);				break;			}			if (lp->ldinfo_next == 0)				lp = NULL;			else				lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);		}		free(buf);		if (!ldp) {			errvalid++;			strcpy(errbuf, "readExports: ");			strcat(errbuf, strerror(errno));			return -1;		}	}	if (TYPE(ldp) != U802TOCMAGIC) {		errvalid++;		strcpy(errbuf, "readExports: bad magic");		while(ldclose(ldp) == FAILURE)			;		return -1;	}	/*	 * Get the padding for the data section. This is needed for	 * AIX 4.1 compilers. This is used when building the final	 * function pointer to the exported symbol.	 */	if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {		errvalid++;		strcpy(errbuf, "readExports: cannot read data section header");		while(ldclose(ldp) == FAILURE)			;		return -1;	}	if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {		errvalid++;		strcpy(errbuf, "readExports: cannot read loader section header");		while(ldclose(ldp) == FAILURE)			;		return -1;	}	/*	 * We read the complete loader section in one chunk, this makes	 * finding long symbol names residing in the string table easier.	 */	if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {		errvalid++;		strcpy(errbuf, "readExports: ");		strcat(errbuf, strerror(errno));		while(ldclose(ldp) == FAILURE)			;		return -1;	}	if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {		errvalid++;		strcpy(errbuf, "readExports: cannot seek to loader section");		free(ldbuf);		while(ldclose(ldp) == FAILURE)			;		return -1;	}	if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {		errvalid++;		strcpy(errbuf, "readExports: cannot read loader section");		free(ldbuf);		while(ldclose(ldp) == FAILURE)			;		return -1;	}	lhp = (LDHDR *)ldbuf;	ls = (LDSYM *)(ldbuf+LDHDRSZ);	/*	 * Count the number of exports to include in our export table.	 */	for (i = lhp->l_nsyms; i; i--, ls++) {		if (!LDR_EXPORT(*ls))			continue;		mp->nExports++;	}	if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {		errvalid++;		strcpy(errbuf, "readExports: ");		strcat(errbuf, strerror(errno));		free(ldbuf);		while(ldclose(ldp) == FAILURE)			;		return -1;	}	/*	 * Fill in the export table. All entries are relative to	 * the entry point we got from load.	 */	ep = mp->exports;	ls = (LDSYM *)(ldbuf+LDHDRSZ);	for (i = lhp->l_nsyms; i; i--, ls++) {		char *symname;		char tmpsym[SYMNMLEN+1];		if (!LDR_EXPORT(*ls))			continue;		if (ls->l_zeroes == 0)			symname = ls->l_offset+lhp->l_stoff+ldbuf;		else {			/*			 * The l_name member is not zero terminated, we			 * must copy the first SYMNMLEN chars and make			 * sure we have a zero byte at the end.			 */			strncpy(tmpsym, ls->l_name, SYMNMLEN);			tmpsym[SYMNMLEN] = '\0';			symname = tmpsym;		}		ep->name = malloc((unsigned) (strlen(symname) + 1));		strcpy(ep->name, symname);		ep->addr = (void *)((unsigned long)mp->entry +					ls->l_value - shdata.s_vaddr);		ep++;	}	free(ldbuf);	while(ldclose(ldp) == FAILURE)		;	return 0;}/* * Find the main modules entry point. This is used as export pointer * for loadbind() to be able to resolve references to the main part. */static void * findMain(void){	struct ld_info *lp;	char *buf;	int size = 4*1024;	int i;	void *ret;	if ((buf = malloc(size)) == NULL) {		errvalid++;		strcpy(errbuf, "findMain: ");		strcat(errbuf, strerror(errno));		return NULL;	}	while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {		free(buf);		size += 4*1024;		if ((buf = malloc(size)) == NULL) {			errvalid++;			strcpy(errbuf, "findMain: ");			strcat(errbuf, strerror(errno));			return NULL;		}	}	if (i == -1) {		errvalid++;		strcpy(errbuf, "findMain: ");		strcat(errbuf, strerror(errno));		free(buf);		return NULL;	}	/*	 * The first entry is the main module. The entry point	 * returned by load() does actually point to the data	 * segment origin.	 */	lp = (struct ld_info *)buf;	ret = lp->ldinfo_dataorg;	free(buf);	return ret;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -