Blame src/logic/linkcmd/slbt_linkcmd_argv.c

3d5567
/*******************************************************************/
eac61a
/*  slibtool: a strong libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
3d5567
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
3d5567
/*******************************************************************/
3d5567
3d5567
#include <stdarg.h>
3d5567
#include <stdlib.h>
3d5567
#include <stdio.h>
3d5567
#include <string.h>
3d5567
#include <fcntl.h>
3d5567
#include <errno.h>
3d5567
#include <sys/stat.h>
3d5567
3d5567
#include <slibtool/slibtool.h>
3d5567
#include "slibtool_driver_impl.h"
3d5567
#include "slibtool_errinfo_impl.h"
752c02
#include "slibtool_spawn_impl.h"
3d5567
#include "slibtool_linkcmd_impl.h"
3d5567
#include "slibtool_mapfile_impl.h"
3d5567
#include "slibtool_metafile_impl.h"
3d5567
#include "slibtool_snprintf_impl.h"
3d5567
#include "slibtool_symlink_impl.h"
3d5567
#include "slibtool_readlink_impl.h"
4b56de
#include "slibtool_visibility_impl.h"
a07095
#include "slibtool_ar_impl.h"
3d5567
3d5567
ec3617
static const char * slbt_ar_self_dlunit = "@PROGRAM@";
ec3617
3d5567
static int slbt_linkcmd_exit(
3d5567
	struct slbt_deps_meta *	depsmeta,
3d5567
	int			ret)
3d5567
{
3d5567
	if (depsmeta->altv)
3d5567
		free(depsmeta->altv);
3d5567
3d5567
	if (depsmeta->args)
3d5567
		free(depsmeta->args);
3d5567
3d5567
	return ret;
3d5567
}
3d5567
3d5567
3d5567
static int slbt_emit_fdwrap_amend_dl_path(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx,
3d5567
	struct slbt_deps_meta * 	depsmeta,
3d5567
	const char *			fmt,
3d5567
					...)
3d5567
{
3d5567
	va_list		ap;
3d5567
	char *		buf;
3d5567
	int		cnt;
3d5567
	char		dlpathbuf[2048];
3d5567
	int		fdwrap;
3d5567
	const char *	fdwrap_fmt;
3d5567
	int		size;
3d5567
3d5567
	va_start(ap,fmt);
3d5567
3d5567
	size = sizeof(dlpathbuf);
3d5567
3d5567
	buf  = ((cnt = vsnprintf(dlpathbuf,size,fmt,ap)) < size)
3d5567
		? dlpathbuf : malloc((size = cnt + 1));
3d5567
3d5567
	va_end(ap);
3d5567
3d5567
	if (buf == dlpathbuf) {
3d5567
		(void)0;
3d5567
3d5567
	} else if (buf) {
3d5567
		va_start(ap,fmt);
3d5567
		vsprintf(buf,fmt,ap);
3d5567
		va_end(ap);
3d5567
3d5567
	} else {
3d5567
		return slbt_linkcmd_exit(
3d5567
			depsmeta,
3d5567
			SLBT_SYSTEM_ERROR(dctx,0));
3d5567
	}
3d5567
3d5567
	if ((fdwrap = slbt_exec_get_fdwrapper(ectx)) >= 0) {
3d5567
		if (buf[0] == '/') {
3d5567
			fdwrap_fmt =
3d5567
				"DL_PATH=\"${DL_PATH}${COLON}%s\"\n"
3d5567
				"COLON=':'\n\n";
3d5567
		} else {
3d5567
			fdwrap_fmt =
3d5567
				"DL_PATH=\"${DL_PATH}${COLON}${DL_PATH_FIXUP}%s\"\n"
3d5567
				"COLON=':'\n\n";
3d5567
		}
3d5567
3d5567
		if (slbt_dprintf(fdwrap,fdwrap_fmt,buf) < 0) {
3d5567
			return slbt_linkcmd_exit(
3d5567
				depsmeta,
3d5567
				SLBT_SYSTEM_ERROR(dctx,0));
3d5567
		}
3d5567
	}
3d5567
3d5567
	return 0;
3d5567
}
3d5567
3d5567
4b56de
slbt_hidden bool slbt_adjust_object_argument(
3d5567
	char *		arg,
3d5567
	bool		fpic,
3d5567
	bool		fany,
3d5567
	int		fdcwd)
3d5567
{
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
3d5567
	if (*arg == '-')
3d5567
		return false;
3d5567
3d5567
	/* object argument: foo.lo or foo.o */
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return false;
3d5567
3d5567
	if ((dot[1]=='l') && (dot[2]=='o') && !dot[3]) {
3d5567
		dot[1] = 'o';
3d5567
		dot[2] = 0;
3d5567
3d5567
	} else if ((dot[1]=='o') && !dot[2]) {
3d5567
		(void)0;
3d5567
3d5567
	} else {
3d5567
		return false;
3d5567
	}
3d5567
3d5567
	/* foo.o requested and is present? */
3d5567
	if (!fpic && !faccessat(fdcwd,arg,0,0))
3d5567
		return true;
3d5567
3d5567
	/* .libs/foo.o */
3d5567
	if ((slash = strrchr(arg,'/')))
3d5567
		slash++;
3d5567
	else
3d5567
		slash = arg;
3d5567
3d5567
	if (slbt_snprintf(base,sizeof(base),
3d5567
			"%s",slash) < 0)
3d5567
		return false;
3d5567
3d5567
	sprintf(slash,".libs/%s",base);
3d5567
3d5567
	if (!faccessat(fdcwd,arg,0,0))
3d5567
		return true;
3d5567
3d5567
	/* foo.o requested and neither is present? */
3d5567
	if (!fpic) {
3d5567
		strcpy(slash,base);
3d5567
		return true;
3d5567
	}
3d5567
3d5567
	/* .libs/foo.o explicitly requested and is not present? */
3d5567
	if (!fany)
3d5567
		return true;
3d5567
3d5567
	/* use foo.o in place of .libs/foo.o */
3d5567
	strcpy(slash,base);
3d5567
3d5567
	if (faccessat(fdcwd,arg,0,0))
3d5567
		sprintf(slash,".libs/%s",base);
3d5567
3d5567
	return true;
3d5567
}
3d5567
3d5567
4b56de
slbt_hidden bool slbt_adjust_wrapper_argument(
3d5567
	char *		arg,
d054ee
	bool		fpic,
d054ee
	const char *    suffix)
3d5567
{
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
3d5567
	if (*arg == '-')
3d5567
		return false;
3d5567
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return false;
3d5567
3d5567
	if (strcmp(dot,".la"))
3d5567
		return false;
3d5567
3d5567
	if (fpic) {
3d5567
		if ((slash = strrchr(arg,'/')))
3d5567
			slash++;
3d5567
		else
3d5567
			slash = arg;
3d5567
3d5567
		if (slbt_snprintf(base,sizeof(base),
3d5567
				"%s",slash) < 0)
3d5567
			return false;
3d5567
3d5567
		sprintf(slash,".libs/%s",base);
3d5567
		dot = strrchr(arg,'.');
3d5567
	}
3d5567
d054ee
	strcpy(dot,suffix);
3d5567
	return true;
3d5567
}
3d5567
3d5567
4b56de
slbt_hidden int slbt_adjust_linker_argument(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	char *				arg,
3d5567
	char **				xarg,
3d5567
	bool				fpic,
3d5567
	const char *			dsosuffix,
3d5567
	const char *			arsuffix,
3d5567
	struct slbt_deps_meta * 	depsmeta)
3d5567
{
3d5567
	int	fdcwd;
3d5567
	int	fdlib;
3d5567
	char *	slash;
3d5567
	char *	dot;
3d5567
	char	base[PATH_MAX];
3d5567
4ffae7
	/* argv switch or non-library input argument? */
3d5567
	if (*arg == '-')
3d5567
		return 0;
3d5567
3d5567
	if (!(dot = strrchr(arg,'.')))
3d5567
		return 0;
3d5567
4ffae7
	/* explicit .a input argument? */
3d5567
	if (!(strcmp(dot,arsuffix))) {
3d5567
		*xarg = arg;
3d5567
		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
3d5567
	}
3d5567
4ffae7
	/* explicit .so input argument? */
3d5567
	if (!(strcmp(dot,dsosuffix)))
3d5567
		return slbt_get_deps_meta(dctx,arg,1,depsmeta);
3d5567
4ffae7
	/* not an .la library? */
3d5567
	if (strcmp(dot,".la"))
3d5567
		return 0;
3d5567
4ffae7
	/* .la file, associated .deps located under .libs */
4ffae7
	if ((slash = strrchr(arg,'/'))) {
4ffae7
		slash++;
4ffae7
	} else {
4ffae7
		slash = arg;
4ffae7
	}
3d5567
4ffae7
	if (slbt_snprintf(base,sizeof(base),
4ffae7
			"%s",slash) < 0)
4ffae7
		return 0;
3d5567
4ffae7
	sprintf(slash,".libs/%s",base);
4ffae7
	dot = strrchr(arg,'.');
3d5567
3d5567
	/* fdcwd */
3d5567
	fdcwd = slbt_driver_fdcwd(dctx);
3d5567
5cfb11
	/* .a preferred but a.disabled present? */
5cfb11
	sprintf(dot,"%s",arsuffix);
5cfb11
5cfb11
	if (slbt_symlink_is_a_placeholder(fdcwd,arg))
5cfb11
		fpic = true;
5cfb11
3d5567
	/* shared library dependency? */
3d5567
	if (fpic) {
3d5567
		sprintf(dot,"%s",dsosuffix);
3d5567
4ffae7
		if (slbt_symlink_is_a_placeholder(fdcwd,arg)) {
3d5567
			sprintf(dot,"%s",arsuffix);
4ffae7
4ffae7
		} else if ((fdlib = openat(fdcwd,arg,O_RDONLY)) >= 0) {
3d5567
			close(fdlib);
4ffae7
4ffae7
		} else {
3d5567
			sprintf(dot,"%s",arsuffix);
4ffae7
		}
3d5567
3d5567
		return slbt_get_deps_meta(dctx,arg,0,depsmeta);
3d5567
	}
3d5567
3d5567
	/* input archive */
3d5567
	sprintf(dot,"%s",arsuffix);
3d5567
	return slbt_get_deps_meta(dctx,arg,0,depsmeta);
3d5567
}
3d5567
3d5567
4b56de
slbt_hidden int slbt_exec_link_adjust_argument_vector(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx,
3d5567
	struct slbt_deps_meta *		depsmeta,
3d5567
	const char *			cwd,
3d5567
	bool				flibrary)
3d5567
{
3d5567
	int			fd;
3d5567
	int			fdcwd;
3d5567
	char ** 		carg;
3d5567
	char ** 		aarg;
3d5567
	char *			slash;
3d5567
	char *			mark;
3d5567
	char *			darg;
3d5567
	char *			dot;
3d5567
	char *			base;
3d5567
	char *			dpath;
3d5567
	int			argc;
3d5567
	char			arg[PATH_MAX];
3d5567
	char			lib[PATH_MAX];
3d5567
	char			depdir  [PATH_MAX];
3d5567
	char			rpathdir[PATH_MAX];
3d5567
	char			rpathlnk[PATH_MAX];
3d5567
	struct stat		st;
3d5567
	size_t			size;
3d5567
	size_t			dlen;
9c528f
	struct slbt_map_info *	mapinfo = 0;
3d5567
	bool			fwholearchive = false;
3d5567
	int			ret;
3d5567
3d5567
	for (argc=0,carg=ectx->cargv; *carg; carg++)
3d5567
		argc++;
3d5567
3d5567
	if (!(depsmeta->args = calloc(1,depsmeta->infolen)))
3d5567
		return SLBT_SYSTEM_ERROR(dctx,0);
3d5567
3d5567
	argc *= 3;
3d5567
	argc += depsmeta->depscnt;
3d5567
3d5567
	if (!(depsmeta->altv = calloc(argc,sizeof(char *))))
3d5567
		return slbt_linkcmd_exit(
3d5567
			depsmeta,
3d5567
			SLBT_SYSTEM_ERROR(dctx,0));
3d5567
3d5567
	fdcwd = slbt_driver_fdcwd(dctx);
3d5567
3d5567
	carg = ectx->cargv;
3d5567
	aarg = depsmeta->altv;
3d5567
	darg = depsmeta->args;
3d5567
	size = depsmeta->infolen;
3d5567
3d5567
	for (; *carg; ) {
3d5567
		dpath = 0;
3d5567
3d5567
		if (!strcmp(*carg,"-Wl,--whole-archive"))
3d5567
			fwholearchive = true;
3d5567
		else if (!strcmp(*carg,"-Wl,--no-whole-archive"))
3d5567
			fwholearchive = false;
3d5567
3d5567
3d5567
3d5567
		/* output annotation */
3d5567
		if (carg == ectx->lout[0]) {
3d5567
			ectx->mout[0] = &aarg[0];
3d5567
			ectx->mout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		/* argument translation */
3d5567
		mark = *carg;
3d5567
3d5567
		if ((mark[0] == '-') && (mark[1] == 'L')) {
b5f778
			if ((ret = slbt_emit_fdwrap_amend_dl_path(
b5f778
					dctx,ectx,depsmeta,
b5f778
					"%s",&mark[2])) < 0)
b5f778
				return ret;
3d5567
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (**carg == '-') {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (!(dot = strrchr(*carg,'.'))) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (ectx->xargv[carg - ectx->cargv]) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (!(strcmp(dot,".a"))) {
270b46
			if (flibrary && !fwholearchive) {
270b46
				strcpy(lib,*carg);
270b46
				dot = strrchr(lib,'.');
270b46
				strcpy(dot,".lai");
270b46
270b46
				if ((fd = openat(fdcwd,lib,O_RDONLY,0)) < 0)
270b46
					*aarg++ = "-Wl,--whole-archive";
270b46
			}
3d5567
3d5567
			dpath = lib;
3d5567
			sprintf(lib,"%s.slibtool.deps",*carg);
3d5567
			*aarg++ = *carg++;
3d5567
270b46
			if (flibrary && !fwholearchive) {
270b46
				if (fd < 0) {
270b46
					*aarg++ = "-Wl,--no-whole-archive";
270b46
				} else {
270b46
					close(fd);
270b46
				}
270b46
			}
3d5567
3d5567
		} else if (strcmp(dot,dctx->cctx->settings.dsosuffix)) {
3d5567
			*aarg++ = *carg++;
3d5567
3d5567
		} else if (carg == ectx->lout[1]) {
3d5567
			/* ^^^hoppla^^^ */
3d5567
			*aarg++ = *carg++;
3d5567
		} else {
3d5567
			/* -rpath */
3d5567
			sprintf(rpathlnk,"%s.slibtool.rpath",*carg);
3d5567
3d5567
			if (!fstatat(fdcwd,rpathlnk,&st,AT_SYMLINK_NOFOLLOW)) {
3d5567
				if (slbt_readlinkat(
3d5567
						fdcwd,
3d5567
						rpathlnk,
3d5567
						rpathdir,
3d5567
						sizeof(rpathdir)))
3d5567
					return slbt_linkcmd_exit(
3d5567
						depsmeta,
3d5567
						SLBT_SYSTEM_ERROR(dctx,rpathlnk));
3d5567
3d5567
				sprintf(darg,"-Wl,%s",rpathdir);
3d5567
				*aarg++ = "-Wl,-rpath";
3d5567
				*aarg++ = darg;
3d5567
				darg   += strlen(darg);
3d5567
				darg++;
3d5567
			}
3d5567
3d5567
			dpath = lib;
3d5567
			sprintf(lib,"%s.slibtool.deps",*carg);
3d5567
3d5567
			/* account for {'-','L','-','l'} */
3d5567
			if (slbt_snprintf(arg,
3d5567
					sizeof(arg) - 4,
3d5567
					"%s",*carg) < 0)
3d5567
				return slbt_linkcmd_exit(
3d5567
					depsmeta,
3d5567
					SLBT_BUFFER_ERROR(dctx));
3d5567
3d5567
			if ((slash = strrchr(arg,'/'))) {
3d5567
				sprintf(*carg,"-L%s",arg);
3d5567
3d5567
				mark   = strrchr(*carg,'/');
3d5567
				*mark  = 0;
3d5567
				*slash = 0;
3d5567
3d5567
				if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
						dctx,ectx,depsmeta,
3d5567
						"%s%s%s",
3d5567
						((arg[0] == '/') ? "" : cwd),
3d5567
						((arg[0] == '/') ? "" : "/"),
3d5567
						arg)) < 0) {
3d5567
					return ret;
3d5567
				}
3d5567
3d5567
				dlen = strlen(dctx->cctx->settings.dsoprefix);
3d5567
3d5567
				/* -module? (todo: non-portable usage, display warning) */
3d5567
				if (strncmp(++slash,dctx->cctx->settings.dsoprefix,dlen)) {
3d5567
					*--slash = '/';
3d5567
					strcpy(*carg,arg);
3d5567
					*aarg++ = *carg++;
3d5567
				} else {
3d5567
					*aarg++ = *carg++;
3d5567
					*aarg++ = ++mark;
3d5567
3d5567
					slash += dlen;
3d5567
3d5567
					sprintf(mark,"-l%s",slash);
3d5567
					dot  = strrchr(mark,'.');
3d5567
					*dot = 0;
3d5567
				}
3d5567
			} else {
3d5567
				*aarg++ = *carg++;
3d5567
			}
3d5567
		}
3d5567
3d5567
		if (dpath && !fstatat(fdcwd,dpath,&st,0)) {
3d5567
			if (!(mapinfo = slbt_map_file(
3d5567
					fdcwd,dpath,
3d5567
					SLBT_MAP_INPUT)))
3d5567
				return slbt_linkcmd_exit(
3d5567
					depsmeta,
3d5567
					SLBT_SYSTEM_ERROR(dctx,dpath));
3d5567
3d5567
			if (!(strncmp(lib,".libs/",6))) {
3d5567
				*aarg++ = "-L.libs";
3d5567
				lib[1] = 0;
3d5567
			} else if ((base = strrchr(lib,'/'))) {
3d5567
				if (base - lib == 5) {
3d5567
					if (!(strncmp(&base[-5],".libs/",6)))
3d5567
						base -= 4;
3d5567
3d5567
				} else if (base - lib >= 6) {
3d5567
					if (!(strncmp(&base[-6],"/.libs/",7)))
3d5567
						base -= 6;
3d5567
				}
3d5567
3d5567
				*base = 0;
3d5567
			} else {
3d5567
				lib[0] = '.';
3d5567
				lib[1] = 0;
3d5567
			}
3d5567
3d5567
			while (mapinfo->mark < mapinfo->cap) {
3d5567
				if (slbt_mapped_readline(dctx,mapinfo,darg,size))
3d5567
					return slbt_linkcmd_exit(
3d5567
						depsmeta,
3d5567
						SLBT_NESTED_ERROR(dctx));
3d5567
7a6d89
				if (darg[0] != '#') {
7a6d89
					*aarg++ = darg;
7a6d89
				}
3d5567
7a6d89
				mark      = darg;
3d5567
				dlen      = strlen(darg);
3d5567
				size     -= dlen;
3d5567
				darg     += dlen;
3d5567
				darg[-1]  = 0;
3d5567
198205
				/* handle -L... and ::... as needed */
3d5567
				if ((mark[0] == '-')
3d5567
						&& (mark[1] == 'L')
3d5567
						&& (mark[2] != '/')) {
3d5567
					if (strlen(mark) >= sizeof(depdir) - 1)
3d5567
						return slbt_linkcmd_exit(
3d5567
							depsmeta,
3d5567
							SLBT_BUFFER_ERROR(dctx));
3d5567
3d5567
					darg = mark;
3d5567
					strcpy(depdir,&mark[2]);
3d5567
					sprintf(darg,"-L%s/%s",lib,depdir);
3d5567
3d5567
					darg += strlen(darg);
3d5567
					darg++;
3d5567
3d5567
					if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
							dctx,ectx,depsmeta,
3d5567
							"%s/%s",lib,depdir)) < 0)
3d5567
						return ret;
3d5567
198205
				} else if ((mark[0] == ':') && (mark[1] == ':')) {
198205
					if (strlen(mark) >= sizeof(depdir) - 1)
198205
						return slbt_linkcmd_exit(
198205
							depsmeta,
198205
							SLBT_BUFFER_ERROR(dctx));
198205
198205
					darg = mark;
198205
					strcpy(depdir,&mark[2]);
198205
198205
					sprintf(darg,"%s/%s",
198205
						mark[2] == '/' ? "" : lib,
198205
						depdir);
198205
198205
					darg += strlen(darg);
198205
					darg++;
198205
3d5567
				} else if ((mark[0] == '-') && (mark[1] == 'L')) {
3d5567
					if ((ret = slbt_emit_fdwrap_amend_dl_path(
3d5567
							dctx,ectx,depsmeta,
3d5567
							"%s",&mark[2])) < 0)
3d5567
						return ret;
3d5567
				}
3d5567
			}
3d5567
		}
9c528f
9c528f
		if (mapinfo) {
9c528f
			slbt_unmap_file(mapinfo);
9c528f
			mapinfo = 0;
9c528f
		}
3d5567
	}
3d5567
3d5567
	if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC)
3d5567
		*aarg++ = "-Wl,--export-dynamic";
3d5567
3d5567
	return 0;
3d5567
}
3d5567
3d5567
752c02
static int slbt_exec_link_remove_file(
752c02
	const struct slbt_driver_ctx *	dctx,
752c02
	struct slbt_exec_ctx *		ectx,
752c02
	const char *			target)
752c02
{
752c02
	int fdcwd;
752c02
752c02
	(void)ectx;
752c02
752c02
	/* fdcwd */
752c02
	fdcwd = slbt_driver_fdcwd(dctx);
752c02
752c02
	/* remove target (if any) */
752c02
	if (!unlinkat(fdcwd,target,0) || (errno == ENOENT))
752c02
		return 0;
752c02
752c02
	return SLBT_SYSTEM_ERROR(dctx,0);
752c02
}
752c02
752c02
752c02
static int slbt_exec_link_create_expsyms_archive(
752c02
	const struct slbt_driver_ctx *  dctx,
752c02
	struct slbt_exec_ctx *          ectx,
752c02
	char **                         lobjv,
ec3617
	char **                         cnvlv,
ec3617
	char                            (*arname)[PATH_MAX])
752c02
{
752c02
	int                             ret;
752c02
	char *                          dot;
752c02
	char **                         argv;
752c02
	char **                         aarg;
752c02
	char **                         parg;
752c02
	struct slbt_archive_ctx *       arctx;
752c02
	char **                         ectx_argv;
752c02
	char *                          ectx_program;
752c02
	char                            output [PATH_MAX];
ec3617
	char                            program[PATH_MAX];
752c02
752c02
	/* output */
752c02
	if (slbt_snprintf(output,sizeof(output),
752c02
			"%s",ectx->mapfilename) < 0)
752c02
		return SLBT_BUFFER_ERROR(dctx);
752c02
752c02
	if (!(dot = strrchr(output,'.')))
752c02
		return SLBT_CUSTOM_ERROR(
752c02
			dctx,
752c02
			SLBT_ERR_FLOW_ERROR);
752c02
5b42a8
	/* .expsyms.xxx --> .expsyms.a */
752c02
	dot[1] = 'a';
752c02
	dot[2] = '\0';
752c02
ec3617
	if (arname)
ec3617
		strcpy(*arname,output);
ec3617
752c02
	/* tool-specific argument vector */
752c02
	argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
752c02
752c02
	/* ar alternate argument vector */
752c02
	if (!argv)
752c02
		if (slbt_snprintf(program,sizeof(program),
752c02
				"%s",dctx->cctx->host.ar) < 0)
752c02
			return SLBT_BUFFER_ERROR(dctx);
752c02
752c02
	/* ar command argument vector */
752c02
	aarg = lobjv;
752c02
752c02
	if ((parg = argv)) {
752c02
		for (; *parg; )
752c02
			*aarg++ = *parg++;
752c02
	} else {
752c02
		*aarg++ = program;
752c02
	}
752c02
752c02
	*aarg++ = "-crs";
752c02
	*aarg++ = output;
752c02
752c02
	ectx_argv     = ectx->argv;
752c02
	ectx_program  = ectx->program;
752c02
752c02
	ectx->argv    = lobjv;
752c02
	ectx->program = ectx->argv[0];
752c02
752c02
	/* step output */
752c02
	if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
752c02
		if (slbt_output_link(ectx))
752c02
			return SLBT_NESTED_ERROR(dctx);
752c02
752c02
	/* remove old archive as needed */
752c02
	if (slbt_exec_link_remove_file(dctx,ectx,output))
752c02
		return SLBT_NESTED_ERROR(dctx);
752c02
752c02
	/* ar spawn */
752c02
	if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
752c02
		return SLBT_SPAWN_ERROR(dctx);
752c02
752c02
	} else if (ectx->exitcode) {
752c02
		return SLBT_CUSTOM_ERROR(
752c02
			dctx,
752c02
			SLBT_ERR_AR_ERROR);
752c02
	}
752c02
752c02
	/* restore link command ectx */
752c02
	ectx->argv    = ectx_argv;
752c02
	ectx->program = ectx_program;
752c02
752c02
	/* input objects associated with .la archives */
752c02
	for (parg=cnvlv; *parg; parg++)
752c02
		if (slbt_util_import_archive(ectx,output,*parg))
752c02
			return SLBT_NESTED_ERROR(dctx);
752c02
752c02
	/* do the thing */
752c02
	if (slbt_ar_get_archive_ctx(dctx,output,&arctx) < 0)
752c02
		return SLBT_NESTED_ERROR(dctx);
752c02
5b42a8
	/* .expsyms.a --> .exp */
ac4a1b
	if ((*dot = '\0'), !(dot = strrchr(output,'.'))) {
ac4a1b
		slbt_ar_free_archive_ctx(arctx);
ac4a1b
		return SLBT_CUSTOM_ERROR(
ac4a1b
			dctx,
ac4a1b
			SLBT_ERR_FLOW_ERROR);
ac4a1b
	}
ac4a1b
ac4a1b
	dot[1] = 'e';
ac4a1b
	dot[2] = 'x';
ac4a1b
	dot[3] = 'p';
ac4a1b
	dot[4] = '\0';
ac4a1b
ac4a1b
	/* symfile */
ac4a1b
	if (dctx->cctx->expsyms) {
ac4a1b
		struct slbt_symlist_ctx * sctx;
ac4a1b
		sctx = (slbt_get_exec_ictx(ectx))->sctx;
ac4a1b
ac4a1b
		ret = slbt_util_create_symfile(
ac4a1b
			sctx,output,0644);
ac4a1b
	} else {
ac4a1b
		ret = slbt_ar_create_symfile(
ac4a1b
			arctx->meta,
ac4a1b
			output,
ac4a1b
			0644);
ac4a1b
	}
ac4a1b
ac4a1b
	/* mapfile */
ac4a1b
	if ((ret == 0) && (dctx->cctx->regex)) {
ac4a1b
		ret = slbt_ar_create_mapfile(
ac4a1b
			arctx->meta,
ac4a1b
			ectx->mapfilename,
ac4a1b
			0644);
5b42a8
	}
5b42a8
752c02
	slbt_ar_free_archive_ctx(arctx);
752c02
ac4a1b
	return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0;
752c02
}
752c02
752c02
4b56de
slbt_hidden int slbt_exec_link_finalize_argument_vector(
3d5567
	const struct slbt_driver_ctx *	dctx,
3d5567
	struct slbt_exec_ctx *		ectx)
3d5567
{
30e15b
	size_t          nargs;
3d5567
	char *		sargv[1024];
3d5567
	char **		sargvbuf;
3d5567
	char **		base;
3d5567
	char **		parg;
752c02
	char **		pcap;
752c02
	char **         argv;
752c02
	char **         mark;
3d5567
	char **		aarg;
3d5567
	char **		oarg;
752c02
	char **		lobj;
752c02
	char **		cnvl;
3d5567
	char **		larg;
3d5567
	char **		darg;
3d5567
	char **		earg;
3d5567
	char **		rarg;
3d5567
	char **		aargv;
3d5567
	char **		oargv;
752c02
	char **		lobjv;
752c02
	char **		cnvlv;
42187c
	char **		dlargv;
3d5567
	char **		cap;
3d5567
	char **		src;
3d5567
	char **		dst;
3d5567
	char *		arg;
3d5567
	char *		dot;
3d5567
	char *		ccwrap;
abb1bf
	char *          program;
3d5567
	const char *	arsuffix;
3d5567
3d5567
	/* vector size */
3d5567
	base     = ectx->argv;
3d5567
	arsuffix = dctx->cctx->settings.arsuffix;
3d5567
3d5567
	for (parg=base; *parg; parg++)
3d5567
		(void)0;
3d5567
752c02
	if (dctx->cctx->regex) {
752c02
		argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
752c02
752c02
		for (mark=argv; mark && *mark; mark++)
752c02
			(void)0;
752c02
	} else {
752c02
		argv = 0;
752c02
		mark  = 0;
752c02
	}
752c02
3d5567
	/* buffer */
30e15b
	if ((nargs = ((parg - base) + (mark - argv))) < 256) {
3d5567
		aargv    = &sargv[0];
752c02
		oargv    = &sargv[1*256];
752c02
		lobjv    = &sargv[2*256];
752c02
		cnvlv    = &sargv[3*256];
3d5567
		sargvbuf = 0;
3d5567
752c02
		parg = &sargv[0];
752c02
		pcap = &sargv[1024];
752c02
752c02
		for (; parg
752c02
			*parg++ = 0;
752c02
30e15b
	} else if (!(sargvbuf = calloc(4*(nargs+1),sizeof(char *)))) {
3d5567
		return SLBT_SYSTEM_ERROR(dctx,0);
3d5567
3d5567
	} else {
3d5567
		aargv = &sargvbuf[0];
30e15b
		oargv = &sargvbuf[1*(nargs+1)];
30e15b
		lobjv = &sargvbuf[2*(nargs+1)];
30e15b
		cnvlv = &sargvbuf[3*(nargs+1)];
3d5567
	}
3d5567
752c02
	aarg = aargv;
752c02
	oarg = oargv;
752c02
	cnvl = cnvlv;
752c02
	lobj = lobjv;
752c02
752c02
	/* -export-symbols-regex: lobjv in place: ar [arg] [arg] -crs <output> */
752c02
	if (dctx->cctx->regex && argv)
752c02
		lobj += mark - argv + 2;
752c02
	else
752c02
		lobj += 3;
752c02
3d5567
	/* (program name) */
3d5567
	parg = &base[1];
3d5567
3d5567
	/* split object args from all other args, record output */
752c02
	/* annotation, and remove redundant -l arguments; and   */
752c02
	/* create additional vectors of all input objects as    */
752c02
	/* convenience libraries for -export-symbols-regex.     */
3d5567
	for (; *parg; ) {
3d5567
		if (ectx->lout[0] == parg) {
3d5567
			ectx->lout[0] = &aarg[0];
3d5567
			ectx->lout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		if (ectx->mout[0] == parg) {
3d5567
			ectx->mout[0] = &aarg[0];
3d5567
			ectx->mout[1] = &aarg[1];
3d5567
		}
3d5567
3d5567
		arg = *parg;
3d5567
		dot = strrchr(arg,'.');
3d5567
3d5567
		/* object input argument? */
3d5567
		if (dot && (!strcmp(dot,".o") || !strcmp(dot,".lo"))) {
752c02
			*lobj++ = *parg;
3d5567
			*oarg++ = *parg++;
3d5567
3d5567
		/* --whole-archive input argument? */
3d5567
		} else if ((arg[0] == '-')
3d5567
				&& (arg[1] == 'W')
3d5567
				&& (arg[2] == 'l')
3d5567
				&& (arg[3] == ',')
3d5567
				&& !strcmp(&arg[4],"--whole-archive")
3d5567
				&& parg[1] && parg[2]
3d5567
				&& !strcmp(parg[2],"-Wl,--no-whole-archive")
3d5567
				&& (dot = strrchr(parg[1],'.'))
3d5567
				&& !strcmp(dot,arsuffix)) {
752c02
			*cnvl++ = parg[1];
3d5567
			*oarg++ = *parg++;
3d5567
			*oarg++ = *parg++;
3d5567
			*oarg++ = *parg++;
3d5567
3d5567
		/* local archive input argument? */
3d5567
		} else if (dot && !strcmp(dot,arsuffix)) {
35000f
			*aarg++ = *parg++;
3d5567
3d5567
		/* -l argument? */
3d5567
		} else if ((parg[0][0] == '-') && (parg[0][1] == 'l')) {
3d5567
			/* find the previous occurence of this -l argument */
3d5567
			for (rarg=0, larg=&aarg[-1]; !rarg && (larg>=aargv); larg--)
3d5567
				if (!strcmp(*larg,*parg))
3d5567
					rarg = larg;
3d5567
3d5567
			/* first occurence of this specific -l argument? */
3d5567
			if (!rarg) {
3d5567
				*aarg++ = *parg++;
3d5567
3d5567
			} else {
3d5567
				larg = rarg;
3d5567
3d5567
				/* if all -l arguments following the previous */
3d5567
				/* occurence had already appeared before the */
3d5567
				/* previous argument, then the current      */
3d4e32
				/* occurence is (possibly) redundant.      */
3d5567
3d5567
				for (darg=&larg[1]; rarg && darg
3d5567
					/* only test -l arguments */
3d5567
					if ((darg[0][0] == '-') && (darg[0][1] == 'l')) {
3d5567
						for (rarg=0, earg=aargv; !rarg && earg
3d5567
							if (!strcmp(*earg,*darg))
3d5567
								rarg = darg;
3d5567
					}
3d5567
				}
3d5567
3d4e32
				/* any archive (.a) input arguments between the */
3d4e32
				/* current occurrence and the previous one?    */
3d4e32
				for (darg=&larg[1]; rarg && darg
3d4e32
					if ((dot = strrchr(*darg,'.')))
3d4e32
						if (!(strcmp(dot,arsuffix)))
3d4e32
							rarg = 0;
3d4e32
3d5567
				/* final verdict: repeated -l argument? */
3d5567
				if (rarg) {
3d5567
					parg++;
3d5567
3d5567
				} else {
3d5567
					*aarg++ = *parg++;
3d5567
				}
3d5567
			}
3d5567
3d5567
		/* -L argument? */
3d5567
		} else if ((parg[0][0] == '-') && (parg[0][1] == 'L')) {
3d5567
			/* find a previous occurence of this -L argument */
3d5567
			for (rarg=0, larg=aargv; !rarg && (larg
3d5567
				if (!strcmp(*larg,*parg))
3d5567
					rarg = larg;
3d5567
3d5567
			/* repeated -L argument? */
3d5567
			if (rarg) {
3d5567
				parg++;
3d5567
			} else {
3d5567
				*aarg++ = *parg++;
3d5567
			}
3d5567
42187c
		/* dlsyms vtable object must only be added once (see below) */
42187c
		} else if (!strcmp(*parg,"-dlpreopen")) {
42187c
			parg++;
42187c
3d5567
		/* placeholder argument? */
3d5567
		} else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) {
3d5567
			parg++;
3d5567
3d5567
		/* all other arguments */
3d5567
		} else {
3d5567
			*aarg++ = *parg++;
3d5567
		}
3d5567
	}
3d5567
42187c
	/* dlsyms vtable object inclusion */
42187c
	if (ectx->dlopenobj)
42187c
		*oarg++ = ectx->dlopenobj;
42187c
ac4a1b
	/* export-symbols-regex, proper dlpreopen support */
ac4a1b
	if (dctx->cctx->libname)
752c02
		if (slbt_exec_link_create_expsyms_archive(
ec3617
				dctx,ectx,lobjv,cnvlv,0) < 0)
ec3617
			return SLBT_NESTED_ERROR(dctx);
ec3617
ec3617
	/* -dlpreopen self */
ec3617
	if (dctx->cctx->drvflags & SLBT_DRIVER_DLPREOPEN_SELF) {
ec3617
		struct slbt_archive_ctx *   arctx;
ec3617
		struct slbt_archive_ctx **  arctxv;
ec3617
		struct slbt_exec_ctx_impl * ictx;
ec3617
		char                        arname[PATH_MAX];
ec3617
ec3617
		ictx   = slbt_get_exec_ictx(ectx);
ec3617
		arctxv = ictx->dlactxv;
ec3617
		arctx  = 0;
ec3617
ec3617
		/* add or repalce the archive context */
ec3617
		for (; !arctx && *arctxv; )
a07095
			if (!strcmp(*arctxv[0]->path,slbt_ar_self_dlunit))
ec3617
				arctx = *arctxv;
ec3617
			else
ec3617
				arctxv++;
ec3617
ec3617
		if (arctx)
ec3617
			slbt_ar_free_archive_ctx(arctx);
ec3617
ec3617
		if (slbt_exec_link_create_expsyms_archive(
ec3617
				dctx,ectx,lobjv,cnvlv,&arname) < 0)
ec3617
			return SLBT_NESTED_ERROR(dctx);
ec3617
ec3617
		if (slbt_ar_get_archive_ctx(dctx,arname,arctxv) < 0)
752c02
			return SLBT_NESTED_ERROR(dctx);
752c02
a07095
		arctx       = *arctxv;
a07095
		arctx->path = &slbt_ar_self_dlunit;
a07095
a07095
		if (slbt_ar_update_syminfo(arctx,ectx) < 0)
a07095
			return SLBT_NESTED_ERROR(dctx);
ec3617
ec3617
		/* regenerate the dlsyms vtable source */
ec3617
		if (slbt_ar_create_dlsyms(
ec3617
				ictx->dlactxv,
ec3617
				ectx->dlunit,
ec3617
				ectx->dlopensrc,
ec3617
				0644) < 0)
ec3617
			return SLBT_NESTED_ERROR(dctx);
ec3617
	}
ec3617
3d5567
	/* program name, ccwrap */
3d5567
	if ((ccwrap = (char *)dctx->cctx->ccwrap)) {
3d5567
		base[1] = base[0];
3d5567
		base[0] = ccwrap;
3d5567
		base++;
3d5567
	}
3d5567
3d5567
	/* join object args */
3d5567
	src = oargv;
3d5567
	cap = oarg;
3d5567
	dst = &base[1];
3d5567
3d5567
	for (; src
3d5567
		*dst++ = *src++;
3d5567
a07095
	/* dlpreopen */
a07095
	if (ectx->dlpreopen)
a07095
		*dst++ = ectx->dlpreopen;
a07095
c5c351
	/* join all other args, eliminate no-op linker path args */
3d5567
	src = aargv;
3d5567
	cap = aarg;
3d5567
c5c351
	for (; src
c5c351
		if ((src[0][0] == '-') && (src[0][1] == 'L')) {
c5c351
			for (larg=0,rarg=src; *rarg && !larg; rarg++)
c5c351
				if ((rarg[0][0] == '-') && (rarg[0][1] == 'l'))
c5c351
					larg = rarg;
c5c351
c5c351
			if (larg) {
c5c351
				*dst++ = *src++;
c5c351
			} else {
c5c351
				src++;
c5c351
			}
c5c351
		} else {
c5c351
			*dst++ = *src++;
c5c351
		}
c5c351
	}
3d5567
3d5567
	/* properly null-terminate argv, accounting for redundant -l arguments */
3d5567
	*dst = 0;
3d5567
3d5567
	/* output annotation */
3d5567
	if (ectx->lout[0]) {
3d5567
		ectx->lout[0] = &base[1] + (oarg - oargv) + (ectx->lout[0] - aargv);
3d5567
		ectx->lout[1] = ectx->lout[0] + 1;
3d5567
	}
3d5567
3d5567
	if (ectx->mout[0]) {
3d5567
		ectx->mout[0] = &base[1] + (oarg - oargv) + (ectx->mout[0] - aargv);
3d5567
		ectx->mout[1] = ectx->mout[0] + 1;
3d5567
	}
3d5567
42187c
	/* dlsyms vtable object compilation */
42187c
	if (ectx->dlopenobj) {
42187c
		dlargv  = (slbt_get_exec_ictx(ectx))->dlargv;
42187c
		*dlargv = base[0];
42187c
42187c
		src = aargv;
42187c
		cap = aarg;
42187c
		dst = &dlargv[1];
42187c
42187c
		/* compile argv, based on the linkcmd argv */
42187c
		for (; src
42187c
			if ((src[0][0] == '-') && (src[0][1] == '-')) {
42187c
				*dst++ = *src;
42187c
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'L')) {
42187c
				(void)0;
42187c
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'l')) {
42187c
				(void)0;
42187c
99fb66
			} else if ((dot = strrchr(*src,'.')) && (dot[1] == 'a') && !dot[2]) {
99fb66
				(void)0;
99fb66
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'o')) {
42187c
				src++;
42187c
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'D')) {
42187c
				if (!src[0][2])
42187c
					src++;
42187c
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'U')) {
42187c
				if (!src[0][2])
42187c
					src++;
42187c
42187c
			} else if ((src[0][0] == '-') && (src[0][1] == 'W')) {
42187c
				if ((src[0][2] == 'a') && (src[0][3] == ','))
42187c
					*dst++ = *src;
99fb66
42187c
			} else {
42187c
				*dst++ = *src;
42187c
			}
42187c
42187c
			src++;
42187c
		}
42187c
42187c
		*dst++ = dctx->cctx->settings.picswitch
42187c
			? dctx->cctx->settings.picswitch
42187c
			: *ectx->fpic;
42187c
42187c
		*dst++ = "-c";
42187c
		*dst++ = ectx->dlopensrc;
42187c
42187c
		*dst++ = "-o";
42187c
		*dst++ = ectx->dlopenobj;
42187c
abb1bf
		*dst++ = 0;
abb1bf
42187c
		/* nested compile step */
abb1bf
		program       = ectx->program;
abb1bf
		ectx->argv    = dlargv;
abb1bf
		ectx->program = dlargv[0];
42187c
42187c
		if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
42187c
			if (slbt_output_compile(ectx))
42187c
				return SLBT_NESTED_ERROR(dctx);
42187c
42187c
		if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0))
42187c
			return SLBT_SYSTEM_ERROR(dctx,0);
42187c
42187c
		if (ectx->exitcode)
42187c
			return SLBT_CUSTOM_ERROR(
42187c
				dctx,
42187c
				SLBT_ERR_COMPILE_ERROR);
42187c
abb1bf
		ectx->argv    = base;
abb1bf
		ectx->program = program;
42187c
	}
42187c
3d5567
	/* all done */
3d5567
	if (sargvbuf)
3d5567
		free(sargvbuf);
3d5567
3d5567
	return 0;
3d5567
}