Blob Blame History Raw
/*******************************************************************/
/*  slibtool: a skinny libtool implementation, written in C        */
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/

#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
#include "slibtool_mkdir_impl.h"
#include "slibtool_linkcmd_impl.h"
#include "slibtool_errinfo_impl.h"
#include "slibtool_ar_impl.h"

#define SLBT_ECTX_LIB_EXTRAS	24
#define SLBT_ECTX_SPARE_PTRS	16

static int slbt_ectx_free_exec_ctx_impl(
	struct slbt_exec_ctx_impl *	ictx,
	int				status);

static size_t slbt_parse_comma_separated_flags(
	const char *	str,
	int *		argc)
{
	const char * ch;

	for (ch=str; *ch; ch++)
		if (*ch == ',')
			(*argc)++;

	return ch - str;
}


static char * slbt_source_file(char ** argv)
{
	char **	parg;
	char *	ch;

	for (parg=argv; *parg; parg++)
		if ((ch = strrchr(*parg,'.')))
			if ((!(strcmp(++ch,"s")))
					|| (!(strcmp(ch,"S")))
					|| (!(strcmp(ch,"asm")))
					|| (!(strcmp(ch,"c")))
					|| (!(strcmp(ch,"cc")))
					|| (!(strcmp(ch,"cpp")))
					|| (!(strcmp(ch,"cxx"))))
				return *parg;
	return 0;
}


static int slbt_exec_ctx_tool_argc(char ** argv)
{
	char ** parg;

	if (!(parg = argv))
		return 0;

	for (; *parg; )
		parg++;

	return parg - argv + 1;
}


static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc(
	const struct slbt_driver_ctx *	dctx)
{
	struct slbt_driver_ctx_impl *   ctx;
	struct slbt_exec_ctx_impl *	ictx;
	size_t				size;
	size_t                          slen;
	int				argc;
	char *				args;
	char *				shadow;
	char *				csrc;
	char **				parg;
	struct slbt_archive_ctx **      dlactxv;
	size_t                          ndlopen;

	/* internal driver context for host-specific tool arguments */
	ctx = slbt_get_driver_ictx(dctx);

	/* initial buffer size (cargv, -Wc) */
	argc = 0;
	csrc = 0;
	size = 0;

	for (parg=dctx->cctx->cargv; *parg; parg++, argc++) {
		if (!(strncmp("-Wc,",*parg,4))) {
			size += slbt_parse_comma_separated_flags(
				&(*parg)[4],&argc) + 1;
		} else {
			size += strlen(*parg) + 1;
		}
	}

	/* argument transformation: additive, worst case scenario */
	size += argc * (strlen(".lo") + 1);
	size += argc * (strlen(".libs/") + 1);
	size += argc * (strlen(".0000.0000.0000") + 1);

	/* buffer size (csrc, ldirname, lbasename, lobjname, aobjname, etc.) */
	if (dctx->cctx->libname) {
		slen  = strlen(dctx->cctx->libname);
		size += (strlen(".slibtool.expsyms.extension") + slen + 1) * SLBT_ECTX_LIB_EXTRAS;

	} else if (dctx->cctx->output) {
		slen  = strlen(dctx->cctx->output);
		size += (strlen(".slibtool.expsyms.extension") + slen + 1) * SLBT_ECTX_LIB_EXTRAS;

	} else if ((csrc = slbt_source_file(dctx->cctx->cargv))) {
		slen  = strlen(csrc);
		size += (strlen(".slibtool.expsyms.extension") + slen + 1) * SLBT_ECTX_LIB_EXTRAS;
	}

	/* string buffers: args, shadow */
	if (!(args = malloc(size)))
		return 0;

	if (!(shadow = malloc(size))) {
		free(args);
		return 0;
	}

	/* tool-specific argv: to simplify matters, be additive */
	argc += slbt_exec_ctx_tool_argc(ctx->host.ar_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.as_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.nm_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.ranlib_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.windres_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.dlltool_argv);
	argc += slbt_exec_ctx_tool_argc(ctx->host.mdso_argv);

	/* argv transformation: .libs/libfoo.so --> -L.libs -lfoo */
	argc *= 2;

	/* argv ad-hoc extensions */
	argc += SLBT_ECTX_SPARE_PTRS;

	/* ctx alloc and vector alloc: argv, xargv, and altv, where we  */
	/* assume -Wl,--whole-archive arg -Wl,--no-whole-archive;      */
	/* and also dlargv for compiling dlunit.dlopen.c              */
	if (!(ictx = calloc(1,sizeof(*ictx)))) {
		free(args);
		free(shadow);
		return 0;
	}

	if (!(ictx->vbuffer = calloc(6*(argc+1),sizeof(char *)))) {
		free(args);
		free(shadow);
		free(ictx);
	}

	if ((ndlopen = (slbt_get_driver_ictx(dctx))->ndlopen)) {
		if (!(dlactxv = calloc(ndlopen+1,sizeof(*dlactxv)))) {
			free(ictx->vbuffer);
			free(ictx);
			free(args);
			free(shadow);
		}

		ictx->dlactxv = dlactxv;
	}

	/* all ready */
	ictx->dctx = dctx;
	ictx->args = args;
	ictx->argc = argc;

	ictx->size   = size;
	ictx->shadow = shadow;

	ictx->ctx.csrc  = csrc;
	ictx->fdwrapper = (-1);

	ictx->ctx.envp  = slbt_driver_envp(dctx);

	return ictx;
}


int  slbt_ectx_get_exec_ctx(
	const struct slbt_driver_ctx *	dctx,
	struct slbt_exec_ctx **		ectx)
{
	struct slbt_exec_ctx_impl *	ictx;
	struct slbt_driver_ctx_impl *   idctx;
	uint64_t                        fmask;
	char **				parg;
	char **				src;
	char **				dst;
	char *				ch;
	char *				mark;
	const char *			dmark;
	char *				slash;
	char *                          arname;
	struct slbt_archive_ctx **      dlactxv;
	const char **                   dlopenv;
	const char *			arprefix;
	const char *			dsoprefix;
	const char *			impprefix;
	const char *			ref;
	int				i;

	/* internal driver context */
	idctx = slbt_get_driver_ictx(dctx);

	/* alloc */
	if (!(ictx = slbt_exec_ctx_alloc(dctx)))
		return SLBT_NESTED_ERROR(dctx);

	/* init with guard for later .lo check */
	ch                = ictx->args + strlen(".lo");
	ictx->ctx.argv    = ictx->vbuffer;
	ictx->ctx.xargv   = &ictx->ctx.argv [ictx->argc + 1];
	ictx->ctx.altv    = &ictx->ctx.xargv[ictx->argc + 1];
	ictx->dlargv      = &ictx->ctx.altv [ictx->argc + 1];

	/* <compiler> */
	ictx->ctx.compiler = dctx->cctx->cargv[0];
	ictx->ctx.cargv    = ictx->ctx.argv;

	/* ldirname, lbasename */
	ref = (dctx->cctx->output)
		? dctx->cctx->output
		: ictx->ctx.csrc;

	if (ref && !ictx->ctx.csrc && (mark = strrchr(ref,'/'))) {
		if (!(strncmp(ref,"../",3)))
			dmark = 0;
		else if (!(strncmp(ref,"./",2)))
			dmark = &ref[1];
		else
			dmark = strchr(ref,'/');

		for (; dmark; ) {
			if (!(strncmp(dmark,"/./",3))) {
				dmark = strchr(&dmark[2],'/');
			} else if (!(strncmp(dmark,"/../",4))) {
				ictx->ctx.ldirdepth = -1;
				dmark = 0;
			} else {
				for (; *dmark=='/'; )
					dmark++;

				ictx->ctx.ldirdepth++;
				dmark = strchr(dmark,'/');
			}
		}

		ictx->ctx.ldirname = ch;
		strcpy(ch,ref);
		ch += mark - ref;
		ch += sprintf(ch,"%s","/.libs/");
		ch++;

		ictx->ctx.lbasename = ch;
		ch += sprintf(ch,"%s",++mark);
		ch++;
	} else if (ref) {
		ictx->ctx.ldirname = ch;
		ch += sprintf(ch,"%s",".libs/");
		ch++;

		ictx->ctx.lbasename = ch;
		mark = strrchr(ref,'/');
		ch += sprintf(ch,"%s",mark ? ++mark : ref);
		ch++;
	}

	/* lbasename suffix */
	if (ref && (dctx->cctx->mode == SLBT_MODE_COMPILE)) {
		if ((ch[-4] == '.') && (ch[-3] == 'l') && (ch[-2] == 'o')) {
			ch[-3] = 'o';
			ch[-2] = 0;
			ch--;
		} else if (ictx->ctx.csrc) {
			if ((mark = strrchr(ictx->ctx.lbasename,'.'))) {
				ch    = mark;
				*++ch = 'o';
				*++ch = 0;
				ch++;
			}
		}
	}

	/* cargv, -Wc */
	for (i=0, parg=dctx->cctx->cargv; *parg; parg++, ch++) {
		if (!(strncmp("-Wc,",*parg,4))) {
			strcpy(ch,&(*parg)[4]);
			ictx->ctx.argv[i++] = ch;

			for (; *ch; ch++)
				if (*ch == ',') {
					*ch++ = 0;
					ictx->ctx.argv[i++] = ch;
				}
		} else {
			ictx->ctx.argv[i++] = ch;
			ch += sprintf(ch,"%s",*parg);
			ch += strlen(".libs/-L-l");
		}
	}

	/* placeholders for -DPIC, -fPIC, -c, -o, <output> */
	ictx->ctx.dpic = &ictx->ctx.argv[i++];
	ictx->ctx.fpic = &ictx->ctx.argv[i++];
	ictx->ctx.cass = &ictx->ctx.argv[i++];

	ictx->ctx.noundef = &ictx->ctx.argv[i++];
	ictx->ctx.soname  = &ictx->ctx.argv[i++];
	ictx->ctx.lsoname = &ictx->ctx.argv[i++];
	ictx->ctx.symdefs = &ictx->ctx.argv[i++];
	ictx->ctx.symfile = &ictx->ctx.argv[i++];
	ictx->ctx.explarg = &ictx->ctx.argv[i++];
	ictx->ctx.expsyms = &ictx->ctx.argv[i++];

	ictx->ctx.lout[0] = &ictx->ctx.argv[i++];
	ictx->ctx.lout[1] = &ictx->ctx.argv[i++];

	ictx->ctx.rpath[0] = &ictx->ctx.argv[i++];
	ictx->ctx.rpath[1] = &ictx->ctx.argv[i++];

	ictx->ctx.sentinel= &ictx->ctx.argv[i++];

	slbt_reset_placeholders(&ictx->ctx);

	/* dsoprefix */
	if (dctx->cctx->settings.dsoprefix) {
		ictx->dsoprefix = ch;
		strcpy(ch,dctx->cctx->settings.dsoprefix);
		ch += strlen(ch) + 1;
	}

	/* output file name */
	if (ref && ((dctx->cctx->mode == SLBT_MODE_COMPILE))) {
		*ictx->ctx.lout[0] = "-o";
		*ictx->ctx.lout[1] = ch;
		ictx->ctx.lobjname = ch;

		ch += sprintf(ch,"%s%s",
			ictx->ctx.ldirname,
			ictx->ctx.lbasename)
			+ 1;

		ictx->ctx.aobjname = ch;

		ch += sprintf(ch,"%s",ictx->ctx.ldirname);
		ch -= strlen(".libs/");
		ch += sprintf(ch,"%s",
			ictx->ctx.lbasename)
			+ 1;

		ictx->ctx.ltobjname = ch;
		strcpy(ch,ictx->ctx.aobjname);

		if ((mark = strrchr(ch,'.')))
			ch = mark + sprintf(mark,"%s",".lo")
				+ 1;
	}

	/* linking: arfilename, lafilename, laifilename, dsobasename, dsofilename, mapfilename */
	if (dctx->cctx->mode == SLBT_MODE_LINK && dctx->cctx->libname) {
		/* arprefix, dsoprefix */
		if (dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
			ictx->ctx.sonameprefix = "";
			arprefix  = "";
			dsoprefix = "";
			impprefix = "";
		} else {
			ictx->ctx.sonameprefix = ictx->dsoprefix;
			arprefix  = dctx->cctx->settings.arprefix;
			dsoprefix = dctx->cctx->settings.dsoprefix;
			impprefix = dctx->cctx->settings.impprefix;
		}

		/* arfilename */
		ictx->ctx.arfilename = ch;
		ch += sprintf(ch,"%s%s%s%s",
				ictx->ctx.ldirname,
				arprefix,
				dctx->cctx->libname,
				dctx->cctx->settings.arsuffix);
		ch++;



		/* lafilename */
		ictx->ctx.lafilename = ch;
		ch += sprintf(ch,"%s%s%s.la",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname);
		ch++;


		/* laifilename */
		ictx->ctx.laifilename = ch;
		ch += sprintf(ch,"%s%s%s.lai",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname);
		ch++;


		/* dsobasename */
		ictx->ctx.dsobasename = ch;
		ch += sprintf(ch,"%s%s%s",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname);
		ch++;

		/* dsofilename */
		ictx->ctx.dsofilename = ch;
		ch += sprintf(ch,"%s%s%s%s",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname,
				dctx->cctx->settings.dsosuffix);
		ch++;

		/* mapfilename */
		ictx->ctx.mapfilename = ch;
		ch += sprintf(ch,"%s%s%s%s%s%s",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname,
				dctx->cctx->release ? "-" : "",
				dctx->cctx->release ? dctx->cctx->release : "",
				dctx->cctx->settings.mapsuffix);
		ch++;

		/* deffilename */
		ictx->ctx.deffilename = ch;
		ch += sprintf(ch,"%s%s%s%s%s%s.def",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname,
				dctx->cctx->release ? "-" : "",
				dctx->cctx->release ? dctx->cctx->release : "",
				dctx->cctx->settings.dsosuffix);
		ch++;

		/* rpathfilename */
		ictx->ctx.rpathfilename = ch;
		ch += sprintf(ch,"%s%s%s%s.slibtool.rpath",
				ictx->ctx.ldirname,
				dsoprefix,
				dctx->cctx->libname,
				dctx->cctx->settings.dsosuffix);
		ch++;

		/* default implib file name */
		ictx->ctx.dimpfilename = ch;
		ch += sprintf(ch,"%s%s%s%s",
				ictx->ctx.ldirname,
				impprefix,
				dctx->cctx->libname,
				dctx->cctx->settings.impsuffix);
		ch++;


		/* primary implib file name */
		ictx->ctx.pimpfilename = ch;
		ch += sprintf(ch,"%s%s%s%s%s.%d%s",
				ictx->ctx.ldirname,
				impprefix,
				dctx->cctx->libname,
				dctx->cctx->release ? "-" : "",
				dctx->cctx->release ? dctx->cctx->release : "",
				dctx->cctx->verinfo.major,
				dctx->cctx->settings.impsuffix);
		ch++;

		/* versioned implib file name */
		ictx->ctx.vimpfilename = ch;
		ch += sprintf(ch,"%s%s%s%s%s.%d.%d.%d%s",
				ictx->ctx.ldirname,
				impprefix,
				dctx->cctx->libname,
				dctx->cctx->release ? "-" : "",
				dctx->cctx->release ? dctx->cctx->release : "",
				dctx->cctx->verinfo.major,
				dctx->cctx->verinfo.minor,
				dctx->cctx->verinfo.revision,
				dctx->cctx->settings.impsuffix);
		ch++;

		/* relfilename */
		if (dctx->cctx->release) {
			ictx->ctx.relfilename = ch;
			ch += dctx->cctx->verinfo.verinfo
				? sprintf(ch,"%s%s%s-%s%s.%d.%d.%d%s",
					ictx->ctx.ldirname,
					dsoprefix,
					dctx->cctx->libname,
					dctx->cctx->release,
					dctx->cctx->settings.osdsuffix,
					dctx->cctx->verinfo.major,
					dctx->cctx->verinfo.minor,
					dctx->cctx->verinfo.revision,
					dctx->cctx->settings.osdfussix)
				: sprintf(ch,"%s%s%s-%s%s",
					ictx->ctx.ldirname,
					dsoprefix,
					dctx->cctx->libname,
					dctx->cctx->release,
					dctx->cctx->settings.dsosuffix);
			ch++;
		}

		/* dsorellnkname */
		if (dctx->cctx->release) {
			ictx->ctx.dsorellnkname = ch;
			ch += sprintf(ch,"%s%s%s-%s%s",
					ictx->ctx.ldirname,
					dsoprefix,
					dctx->cctx->libname,
					dctx->cctx->release,
					dctx->cctx->settings.dsosuffix);
			ch++;
		}

		/* dlopensrc, dlopenobj */
		if (idctx->ndlopen) {
			ictx->ctx.dlopensrc = ch;
			ch += sprintf(ch,"%s%s%s.dlopen.c",
					ictx->ctx.ldirname,
					dsoprefix,
					dctx->cctx->libname);

			ch++;

			ictx->ctx.dlopenobj = ch;
			ch += sprintf(ch,"%s%s%s.dlopen.o",
					ictx->ctx.ldirname,
					dsoprefix,
					dctx->cctx->libname);

			ch++;

			ictx->ctx.dlunit = ch;
			ch += sprintf(ch,"%s%s",
					dsoprefix,
					dctx->cctx->libname);

			ch++;
		}

	/* linking: exefilename */
	} else if (dctx->cctx->mode == SLBT_MODE_LINK) {
		ictx->ctx.exefilename = ch;

		if ((slash = strrchr(dctx->cctx->output,'/'))) {
			strcpy(ch,dctx->cctx->output);
			mark = ch + (slash - dctx->cctx->output);
			sprintf(++mark,".libs/%s",++slash);
			ch += strlen(ch) + 1;
		} else
			ch += sprintf(ch,".libs/%s",dctx->cctx->output) + 1;
	}

	/* dlopensrc, dlopenobj: executable program */
	if (idctx->dlopenv && !dctx->cctx->libname) {
		ictx->ctx.dlopensrc = ch;
		ch += sprintf(ch,"%s.dlopen.c",
				ictx->ctx.exefilename);

		ch++;

		ictx->ctx.dlopenobj = ch;
		ch += sprintf(ch,"%s.dlopen.o",
				ictx->ctx.exefilename);

		ch++;

		ictx->ctx.dlunit = ch;
		ch += sprintf(ch,"%s",
				"@PROGRAM@");

		ch++;

		ictx->ctx.mapfilename = ch;
		ch += sprintf(ch,"%s%s",
				ictx->ctx.exefilename,
				dctx->cctx->settings.mapsuffix);
		ch++;

	}

	/* dlopen, dlpreopen */
	if ((dlopenv = idctx->dlopenv), (dlactxv = ictx->dlactxv)) {
		fmask  = SLBT_DRIVER_DLPREOPEN_FORCE;
		fmask |= SLBT_DRIVER_DLOPEN_FORCE;

		if (dctx->cctx->drvflags & fmask) {
			if (slbt_ar_get_varchive_ctx(dctx,dlactxv) < 0)
				return slbt_ectx_free_exec_ctx_impl(
					ictx,
					SLBT_NESTED_ERROR(dctx));

			if (slbt_ar_update_syminfo(*dlactxv,&ictx->ctx) < 0)
				return slbt_ectx_free_exec_ctx_impl(
					ictx,
					SLBT_NESTED_ERROR(dctx));

			dlactxv++;
		}

		for (; *dlopenv; ) {
			arname = ictx->sbuf;
			strcpy(arname,*dlopenv);
			slbt_adjust_wrapper_argument(arname,true);

			if (slbt_ar_get_archive_ctx(dctx,arname,dlactxv) < 0)
				return slbt_ectx_free_exec_ctx_impl(
					ictx,
					SLBT_NESTED_ERROR(dctx));

			if (slbt_ar_update_syminfo(*dlactxv,&ictx->ctx) < 0)
				return slbt_ectx_free_exec_ctx_impl(
					ictx,
					SLBT_NESTED_ERROR(dctx));

			dlopenv++;
			dlactxv++;
		}

		if (slbt_mkdir(dctx,ictx->ctx.ldirname) < 0)
			return slbt_ectx_free_exec_ctx_impl(
				ictx,
				SLBT_SYSTEM_ERROR(
					dctx,
					ictx->ctx.ldirname));

		if (slbt_ar_create_dlsyms(
					ictx->dlactxv,
					ictx->ctx.dlunit,
					ictx->ctx.dlopensrc,
					0644) < 0)
				return slbt_ectx_free_exec_ctx_impl(
					ictx,
					SLBT_NESTED_ERROR(dctx));
	}

	/* vector of exported symbols (raw input via -export-symbols) */
	if (dctx->cctx->expsyms)
		if (slbt_lib_get_symlist_ctx(
				dctx,dctx->cctx->expsyms,
				&ictx->sctx) < 0)
			return SLBT_NESTED_ERROR(dctx);

	/* argument strings shadow copy */
	memcpy(ictx->shadow,ictx->args,ictx->size);

	/* compile mode: argument vector shadow copy */
	if (dctx->cctx->mode == SLBT_MODE_COMPILE)
		for (src=ictx->ctx.argv, dst=ictx->ctx.xargv; *src; src++, dst++)
			*dst = *src;

	/* save the full vector's lout, mout */
	ictx->lout[0] = ictx->ctx.lout[0];
	ictx->lout[1] = ictx->ctx.lout[1];

	ictx->mout[0] = ictx->ctx.mout[0];
	ictx->mout[1] = ictx->ctx.mout[1];

	/* all done */
	*ectx = &ictx->ctx;
	return 0;
}


static int slbt_ectx_free_exec_ctx_impl(
	struct slbt_exec_ctx_impl *	ictx,
	int				status)
{
	struct slbt_archive_ctx ** dlactxv;

	if (ictx->sctx)
		slbt_lib_free_symlist_ctx(ictx->sctx);

	if (ictx->fdwrapper >= 0)
		close(ictx->fdwrapper);

	if (ictx->dlactxv) {
		for (dlactxv=ictx->dlactxv; *dlactxv; dlactxv++)
			slbt_ar_free_archive_ctx(*dlactxv);

		free(ictx->dlactxv);
	}

	free(ictx->args);
	free(ictx->shadow);
	free(ictx->vbuffer);
	free (ictx);

	return status;
}


void slbt_ectx_free_exec_ctx(struct slbt_exec_ctx * ctx)
{
	struct slbt_exec_ctx_impl *	ictx;
	uintptr_t			addr;

	if (ctx) {
		addr = (uintptr_t)ctx - offsetof(struct slbt_exec_ctx_impl,ctx);
		ictx = (struct slbt_exec_ctx_impl *)addr;
		slbt_ectx_free_exec_ctx_impl(ictx,0);
	}
}


void slbt_ectx_reset_arguments(struct slbt_exec_ctx * ectx)
{
	struct slbt_exec_ctx_impl *	ictx;
	uintptr_t			addr;

	addr = (uintptr_t)ectx - offsetof(struct slbt_exec_ctx_impl,ctx);
	ictx = (struct slbt_exec_ctx_impl *)addr;
	memcpy(ictx->args,ictx->shadow,ictx->size);
}


void slbt_ectx_reset_argvector(struct slbt_exec_ctx * ectx)
{
	struct slbt_exec_ctx_impl *	ictx;
	uintptr_t			addr;
	char ** 			src;
	char ** 			dst;

	addr = (uintptr_t)ectx - offsetof(struct slbt_exec_ctx_impl,ctx);
	ictx = (struct slbt_exec_ctx_impl *)addr;

	for (src=ectx->xargv, dst=ectx->argv; *src; src++, dst++)
		*dst = *src;

	*dst = 0;

	ectx->lout[0] = ictx->lout[0];
	ectx->lout[1] = ictx->lout[1];

	ectx->mout[0] = ictx->mout[0];
	ectx->mout[1] = ictx->mout[1];
}


slbt_hidden void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
{
	struct slbt_exec_ctx_impl * ictx;

	ictx = slbt_get_exec_ictx(ectx);

	if (ictx->lout[0]) {
		ectx->lout[0] = ictx->lout[0];
		ectx->lout[1] = ictx->lout[1];
	}

	*ectx->dpic = "-USLIBTOOL_PLACEHOLDER_DPIC";
	*ectx->fpic = "-USLIBTOOL_PLACEHOLDER_FPIC";
	*ectx->cass = "-USLIBTOOL_PLACEHOLDER_COMPILE_ASSEMBLE";

	*ectx->noundef = "-USLIBTOOL_PLACEHOLDER_NO_UNDEFINED";
	*ectx->soname  = "-USLIBTOOL_PLACEHOLDER_SONAME";
	*ectx->lsoname = "-USLIBTOOL_PLACEHOLDER_LSONAME";
	*ectx->symdefs = "-USLIBTOOL_PLACEHOLDER_SYMDEF_SWITCH";
	*ectx->symfile = "-USLIBTOOL_PLACEHOLDER_SYMDEF_FILE";
	*ectx->explarg = "-USLIBTOOL_PLACEHOLDER_EXPSYMS_SWITCH";
	*ectx->expsyms = "-USLIBTOOL_PLACEHOLDER_EXPSYMS_FILE";

	*ectx->lout[0] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_SWITCH";
	*ectx->lout[1] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_FILE";

	*ectx->rpath[0] = "-USLIBTOOL_PLACEHOLDER_RPATH_SWITCH";
	*ectx->rpath[1] = "-USLIBTOOL_PLACEHOLDER_RPATH_DIR";

	ectx->mout[0]  = 0;
	ectx->mout[1]  = 0;

	*ectx->sentinel= 0;
}

slbt_hidden void slbt_disable_placeholders(struct slbt_exec_ctx * ectx)
{
	*ectx->dpic = 0;
	*ectx->fpic = 0;
	*ectx->cass = 0;

	*ectx->noundef = 0;
	*ectx->soname  = 0;
	*ectx->lsoname = 0;
	*ectx->symdefs = 0;
	*ectx->symfile = 0;
	*ectx->explarg = 0;
	*ectx->expsyms = 0;

	*ectx->lout[0] = 0;
	*ectx->lout[1] = 0;

	*ectx->rpath[0] = 0;
	*ectx->rpath[1] = 0;

	*ectx->sentinel= 0;
}