Blame src/logic/slbt_exec_ctx.c

528799
/*******************************************************************/
528799
/*  slibtool: a skinny libtool implementation, written in C        */
528799
/*  Copyright (C) 2016  Z. Gilboa                                  */
528799
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
528799
/*******************************************************************/
528799
528799
#include <stdint.h>
528799
#include <unistd.h>
528799
#include <stdlib.h>
528799
#include <string.h>
528799
528799
#include <slibtool/slibtool.h>
2a6c45
#include "slibtool_errinfo_impl.h"
528799
528799
#define SLBT_ARGV_SPARE_PTRS	16
528799
528799
struct slbt_exec_ctx_impl {
528799
	int			argc;
528799
	char *			args;
e7ddb2
	char *			shadow;
2f9f52
	char *			dsoprefix;
e7ddb2
	size_t			size;
528799
	struct slbt_exec_ctx	ctx;
54d0a5
	char *			vbuffer[];
528799
};
528799
528799
528799
static size_t slbt_parse_comma_separated_flags(
528799
	const char *	str,
528799
	int *		argc)
528799
{
528799
	const char * ch;
528799
528799
	for (ch=str; *ch; ch++)
528799
		if (*ch == ',')
528799
			(*argc)++;
528799
528799
	return ch - str;
528799
}
528799
528799
df088e
static char * slbt_source_file(char ** argv)
df088e
{
df088e
	char **	parg;
df088e
	char *	ch;
df088e
df088e
	for (parg=argv; *parg; parg++)
df088e
		if ((ch = strrchr(*parg,'.')))
df088e
			if ((!(strcmp(++ch,"s")))
df088e
					|| (!(strcmp(ch,"S")))
533d94
					|| (!(strcmp(ch,"asm")))
df088e
					|| (!(strcmp(ch,"c")))
df088e
					|| (!(strcmp(ch,"cc")))
855e36
					|| (!(strcmp(ch,"cpp")))
df088e
					|| (!(strcmp(ch,"cxx"))))
df088e
				return *parg;
df088e
	return 0;
df088e
}
df088e
df088e
528799
static struct slbt_exec_ctx_impl * slbt_exec_ctx_alloc(
528799
	const struct slbt_driver_ctx *	dctx)
528799
{
528799
	struct slbt_exec_ctx_impl *	ictx;
528799
	size_t				size;
e7ddb2
	size_t				vsize;
528799
	int				argc;
528799
	char *				args;
e7ddb2
	char *				shadow;
df088e
	char *				csrc;
528799
	char **				parg;
528799
df088e
	argc = 0;
df088e
	csrc = 0;
df088e
ef1e6e
	/* clerical [worst-case] buffer size (guard, .libs, version) */
c59280
	size  = strlen(".lo") + 1;
2330a5
	size += 12 * (strlen(".libs/") + 1);
c59280
	size += 36 * (strlen(".0000") + 1);
528799
528799
	/* buffer size (cargv, -Wc) */
528799
	for (parg=dctx->cctx->cargv; *parg; parg++, argc++)
528799
		if (!(strncmp("-Wc,",*parg,4)))
c59280
			size += slbt_parse_comma_separated_flags(
c59280
				&(*parg)[4],&argc) + 1;
528799
		else
c59280
			size += strlen(*parg) + 1;
528799
b4491f
	/* buffer size (ldirname, lbasename, lobjname, aobjname, etc.) */
df088e
	if (dctx->cctx->output)
b4491f
		size += 8*strlen(dctx->cctx->output);
df088e
	else if ((csrc = slbt_source_file(dctx->cctx->cargv)))
b4491f
		size += 8*strlen(csrc);
df088e
b6184d
	/* pessimistic argc: .libs/libfoo.so --> -L.libs -lfoo */
b6184d
	argc *= 2;
b6184d
	argc += SLBT_ARGV_SPARE_PTRS;
b6184d
0919b0
	/* buffer size (.libs/%.o, pessimistic) */
b6184d
	size += argc * strlen(".libs/-L-l");
0919b0
f0c096
	/* buffer size (linking) */
f0c096
	if (dctx->cctx->mode == SLBT_MODE_LINK)
c59280
		size += strlen(dctx->cctx->settings.arprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.arsuffix) + 1
c59280
			+ strlen(dctx->cctx->settings.dsoprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.dsoprefix) + 1
2f9f52
			+ strlen(dctx->cctx->settings.dsoprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.exeprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.exeprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.impprefix) + 1
c59280
			+ strlen(dctx->cctx->settings.impprefix) + 1;
f0c096
528799
	/* alloc */
df088e
	if (!(args = malloc(size)))
528799
		return 0;
528799
e7ddb2
	if (!(shadow = malloc(size))) {
e7ddb2
		free(args);
e7ddb2
		return 0;
e7ddb2
	}
e7ddb2
b6184d
	/* altv: duplicate set, -Wl,--whole-archive, -Wl,--no-whole-archive */
b6184d
	vsize = sizeof(*ictx) + 4*(argc+1)*sizeof(char *);
528799
e7ddb2
	if (!(ictx = calloc(1,vsize))) {
528799
		free(args);
e7ddb2
		free(shadow);
528799
		return 0;
528799
	}
528799
528799
	ictx->args = args;
528799
	ictx->argc = argc;
528799
e7ddb2
	ictx->size   = size;
e7ddb2
	ictx->shadow = shadow;
e7ddb2
df088e
	ictx->ctx.csrc = csrc;
df088e
528799
	return ictx;
528799
}
528799
528799
528799
int  slbt_get_exec_ctx(
528799
	const struct slbt_driver_ctx *	dctx,
528799
	struct slbt_exec_ctx **		ectx)
528799
{
528799
	struct slbt_exec_ctx_impl *	ictx;
528799
	char **				parg;
528799
	char *				ch;
014f4c
	char *				mark;
7f35de
	const char *			dmark;
f47761
	char *				slash;
f63307
	const char *			arprefix;
f63307
	const char *			dsoprefix;
2f9f52
	const char *			impprefix;
df088e
	const char *			ref;
528799
	int				i;
528799
528799
	/* alloc */
528799
	if (!(ictx = slbt_exec_ctx_alloc(dctx)))
2a6c45
		return SLBT_NESTED_ERROR(dctx);
528799
528799
	/* init with guard for later .lo check */
528799
	ch                = ictx->args + strlen(".lo");
54d0a5
	ictx->ctx.argv    = ictx->vbuffer;
54d0a5
	ictx->ctx.altv    = &ictx->vbuffer[ictx->argc + 1];
528799
528799
	/* <compiler> */
27a8e1
	ictx->ctx.compiler = dctx->cctx->cargv[0];
27a8e1
	ictx->ctx.cargv    = ictx->ctx.argv;
528799
df088e
	/* ldirname, lbasename */
df088e
	ref = (dctx->cctx->output)
df088e
		? dctx->cctx->output
df088e
		: ictx->ctx.csrc;
df088e
014f4c
	if (ref && !ictx->ctx.csrc && (mark = strrchr(ref,'/'))) {
7f35de
		if (!(strncmp(ref,"../",3)))
7f35de
			dmark = 0;
7f35de
		else if (!(strncmp(ref,"./",2)))
7f35de
			dmark = &ref[1];
7f35de
		else
7f35de
			dmark = strchr(ref,'/');
7f35de
7f35de
		for (; dmark; ) {
7f35de
			if (!(strncmp(dmark,"/./",3))) {
7f35de
				dmark = strchr(&dmark[2],'/');
7f35de
			} else if (!(strncmp(dmark,"/../",4))) {
7f35de
				ictx->ctx.ldirdepth = -1;
7f35de
				dmark = 0;
7f35de
			} else {
7f35de
				for (; *dmark=='/'; )
7f35de
					dmark++;
7f35de
7f35de
				ictx->ctx.ldirdepth++;
7f35de
				dmark = strchr(dmark,'/');
7f35de
			}
7f35de
		}
7f35de
df088e
		ictx->ctx.ldirname = ch;
df088e
		strcpy(ch,ref);
014f4c
		ch += mark - ref;
df088e
		ch += sprintf(ch,"%s","/.libs/");
df088e
		ch++;
df088e
df088e
		ictx->ctx.lbasename = ch;
014f4c
		ch += sprintf(ch,"%s",++mark);
df088e
		ch++;
df088e
	} else if (ref) {
df088e
		ictx->ctx.ldirname = ch;
df088e
		ch += sprintf(ch,"%s",".libs/");
df088e
		ch++;
df088e
df088e
		ictx->ctx.lbasename = ch;
014f4c
		mark = strrchr(ref,'/');
014f4c
		ch += sprintf(ch,"%s",mark ? ++mark : ref);
df088e
		ch++;
df088e
	}
df088e
df088e
	/* lbasename suffix */
df088e
	if (ref && (dctx->cctx->mode == SLBT_MODE_COMPILE)) {
df088e
		if ((ch[-4] == '.') && (ch[-3] == 'l') && (ch[-2] == 'o')) {
df088e
			ch[-3] = 'o';
f7d687
			ch[-2] = 0;
df088e
			ch--;
df088e
		} else if (ictx->ctx.csrc) {
cae4bb
			if ((mark = strrchr(ictx->ctx.lbasename,'.'))) {
cae4bb
				ch    = mark;
df088e
				*++ch = 'o';
f7d687
				*++ch = 0;
df088e
				ch++;
df088e
			}
df088e
		}
df088e
	}
df088e
528799
	/* cargv, -Wc */
528799
	for (i=0, parg=dctx->cctx->cargv; *parg; parg++, ch++) {
528799
		if (!(strncmp("-Wc,",*parg,4))) {
4c2181
			strcpy(ch,&(*parg)[4]);
528799
			ictx->ctx.argv[i++] = ch;
528799
528799
			for (; *ch; ch++)
528799
				if (*ch == ',') {
f7d687
					*ch++ = 0;
869626
					ictx->ctx.argv[i++] = ch;
528799
				}
528799
		} else {
528799
			ictx->ctx.argv[i++] = ch;
528799
			ch += sprintf(ch,"%s",*parg);
b6184d
			ch += strlen(".libs/-L-l");
528799
		}
528799
	}
528799
5aae4b
	/* placeholders for -DPIC, -fPIC, -c, -o, <output> */
5aae4b
	ictx->ctx.dpic = &ictx->ctx.argv[i++];
5aae4b
	ictx->ctx.fpic = &ictx->ctx.argv[i++];
5aae4b
	ictx->ctx.cass = &ictx->ctx.argv[i++];
528799
93b62c
	ictx->ctx.noundef = &ictx->ctx.argv[i++];
0f8591
	ictx->ctx.soname  = &ictx->ctx.argv[i++];
0f8591
	ictx->ctx.lsoname = &ictx->ctx.argv[i++];
e15ee1
	ictx->ctx.symdefs = &ictx->ctx.argv[i++];
e15ee1
	ictx->ctx.symfile = &ictx->ctx.argv[i++];
0f8591
5aae4b
	ictx->ctx.lout[0] = &ictx->ctx.argv[i++];
5aae4b
	ictx->ctx.lout[1] = &ictx->ctx.argv[i++];
2330a5
2330a5
	ictx->ctx.rpath[0] = &ictx->ctx.argv[i++];
2330a5
	ictx->ctx.rpath[1] = &ictx->ctx.argv[i++];
2330a5
b1f977
	ictx->ctx.sentinel= &ictx->ctx.argv[i++];
df088e
62a7c9
	slbt_reset_placeholders(&ictx->ctx);
62a7c9
2f9f52
	/* dsoprefix */
2f9f52
	if (dctx->cctx->settings.dsoprefix) {
2f9f52
		ictx->dsoprefix = ch;
2f9f52
		strcpy(ch,dctx->cctx->settings.dsoprefix);
2f9f52
		ch += strlen(ch) + 1;
2f9f52
	}
2f9f52
df088e
	/* output file name */
2691fe
	if (ref && ((dctx->cctx->mode == SLBT_MODE_COMPILE))) {
5aae4b
		*ictx->ctx.lout[0] = "-o";
5aae4b
		*ictx->ctx.lout[1] = ch;
5aae4b
		ictx->ctx.lobjname = ch;
528799
e02305
		ch += sprintf(ch,"%s%s",
df088e
			ictx->ctx.ldirname,
e02305
			ictx->ctx.lbasename)
c59280
			+ 1;
e02305
e02305
		ictx->ctx.aobjname = ch;
e02305
e02305
		ch += sprintf(ch,"%s",ictx->ctx.ldirname);
e02305
		ch -= strlen(".libs/");
e88a39
		ch += sprintf(ch,"%s",
e88a39
			ictx->ctx.lbasename)
c59280
			+ 1;
e88a39
e88a39
		ictx->ctx.ltobjname = ch;
e88a39
		strcpy(ch,ictx->ctx.aobjname);
e88a39
cae4bb
		if ((mark = strrchr(ch,'.')))
cae4bb
			ch = mark + sprintf(mark,"%s",".lo")
c59280
				+ 1;
528799
	}
528799
26ea30
	/* linking: arfilename, lafilename, laifilename, dsofilename */
731e44
	if (dctx->cctx->mode == SLBT_MODE_LINK && dctx->cctx->libname) {
f63307
		/* arprefix, dsoprefix */
f63307
		if (dctx->cctx->drvflags & SLBT_DRIVER_MODULE) {
2f9f52
			ictx->ctx.sonameprefix = "";
f63307
			arprefix  = "";
f63307
			dsoprefix = "";
2f9f52
			impprefix = "";
f63307
		} else {
2f9f52
			ictx->ctx.sonameprefix = ictx->dsoprefix;
f63307
			arprefix  = dctx->cctx->settings.arprefix;
f63307
			dsoprefix = dctx->cctx->settings.dsoprefix;
2f9f52
			impprefix = dctx->cctx->settings.impprefix;
f63307
		}
f63307
731e44
		/* arfilename */
731e44
		ictx->ctx.arfilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s%s",
731e44
				ictx->ctx.ldirname,
f63307
				arprefix,
731e44
				dctx->cctx->libname,
c59280
				dctx->cctx->settings.arsuffix);
c59280
		ch++;
731e44
731e44
731e44
731e44
		/* lafilename */
731e44
		ictx->ctx.lafilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s.la",
731e44
				ictx->ctx.ldirname,
f63307
				dsoprefix,
c59280
				dctx->cctx->libname);
c59280
		ch++;
731e44
731e44
26ea30
		/* laifilename */
26ea30
		ictx->ctx.laifilename = ch;
26ea30
		ch += sprintf(ch,"%s%s%s.lai",
26ea30
				ictx->ctx.ldirname,
26ea30
				dsoprefix,
26ea30
				dctx->cctx->libname);
26ea30
		ch++;
26ea30
26ea30
731e44
		/* dsofilename */
731e44
		ictx->ctx.dsofilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s%s",
731e44
				ictx->ctx.ldirname,
f63307
				dsoprefix,
731e44
				dctx->cctx->libname,
c59280
				dctx->cctx->settings.dsosuffix);
c59280
		ch++;
b4491f
b4491f
		/* deffilename */
b4491f
		ictx->ctx.deffilename = ch;
b4491f
		ch += sprintf(ch,"%s%s%s%s.def",
b4491f
				ictx->ctx.ldirname,
f63307
				dsoprefix,
b4491f
				dctx->cctx->libname,
c59280
				dctx->cctx->settings.dsosuffix);
c59280
		ch++;
1677f4
2330a5
		/* rpathfilename */
2330a5
		ictx->ctx.rpathfilename = ch;
2330a5
		ch += sprintf(ch,"%s%s%s%s.slibtool.rpath",
2330a5
				ictx->ctx.ldirname,
2330a5
				dsoprefix,
2330a5
				dctx->cctx->libname,
2330a5
				dctx->cctx->settings.dsosuffix);
2330a5
		ch++;
2330a5
1677f4
		/* default implib file name */
1677f4
		ictx->ctx.dimpfilename = ch;
1677f4
		ch += sprintf(ch,"%s%s%s%s",
1677f4
				ictx->ctx.ldirname,
2f9f52
				impprefix,
1677f4
				dctx->cctx->libname,
c59280
				dctx->cctx->settings.impsuffix);
c59280
		ch++;
1677f4
1677f4
1677f4
		/* primary implib file name */
1677f4
		ictx->ctx.pimpfilename = ch;
1677f4
		ch += sprintf(ch,"%s%s%s.%d%s",
1677f4
				ictx->ctx.ldirname,
2f9f52
				impprefix,
1677f4
				dctx->cctx->libname,
1677f4
				dctx->cctx->verinfo.major,
c59280
				dctx->cctx->settings.impsuffix);
c59280
		ch++;
1677f4
1677f4
		/* versioned implib file name */
1677f4
		ictx->ctx.vimpfilename = ch;
1677f4
		ch += sprintf(ch,"%s%s%s.%d.%d.%d%s",
1677f4
				ictx->ctx.ldirname,
2f9f52
				impprefix,
1677f4
				dctx->cctx->libname,
1677f4
				dctx->cctx->verinfo.major,
1677f4
				dctx->cctx->verinfo.minor,
1677f4
				dctx->cctx->verinfo.revision,
c59280
				dctx->cctx->settings.impsuffix);
c59280
		ch++;
112a2b
112a2b
		/* relfilename */
112a2b
		if (dctx->cctx->release) {
112a2b
			ictx->ctx.relfilename = ch;
112a2b
			ch += sprintf(ch,"%s%s%s-%s%s",
112a2b
					ictx->ctx.ldirname,
112a2b
					dsoprefix,
112a2b
					dctx->cctx->libname,
112a2b
					dctx->cctx->release,
112a2b
					dctx->cctx->settings.dsosuffix);
112a2b
			ch++;
112a2b
		}
731e44
	}
731e44
f47761
	/* linking: exefilename */
f47761
	if (dctx->cctx->mode == SLBT_MODE_LINK && !dctx->cctx->libname) {
f47761
		ictx->ctx.exefilename = ch;
f47761
f47761
		if ((slash = strrchr(dctx->cctx->output,'/'))) {
f47761
			strcpy(ch,dctx->cctx->output);
f47761
			mark = ch + (slash - dctx->cctx->output);
f47761
			sprintf(++mark,".libs/%s",++slash);
c59280
			ch += strlen(ch) + 1;
f47761
		} else
c59280
			ch += sprintf(ch,".libs/%s",dctx->cctx->output) + 1;
f47761
	}
f47761
e7ddb2
	/* argument strings shadow copy */
e7ddb2
	memcpy(ictx->shadow,ictx->args,ictx->size);
e7ddb2
528799
	*ectx = &ictx->ctx;
528799
	return 0;
528799
}
528799
528799
528799
static int slbt_free_exec_ctx_impl(
528799
	struct slbt_exec_ctx_impl *	ictx,
528799
	int				status)
528799
{
5ee0d1
	if (ictx->ctx.fwrapper)
5ee0d1
		fclose(ictx->ctx.fwrapper);
5ee0d1
0913c3
	if (ictx->ctx.fdeps)
0913c3
		fclose(ictx->ctx.fdeps);
0913c3
528799
	free(ictx->args);
e7ddb2
	free(ictx->shadow);
528799
	free (ictx);
528799
	return status;
528799
}
528799
528799
528799
void slbt_free_exec_ctx(struct slbt_exec_ctx * ctx)
528799
{
528799
	struct slbt_exec_ctx_impl *	ictx;
528799
	uintptr_t			addr;
528799
528799
	if (ctx) {
528799
		addr = (uintptr_t)ctx - offsetof(struct slbt_exec_ctx_impl,ctx);
528799
		ictx = (struct slbt_exec_ctx_impl *)addr;
528799
		slbt_free_exec_ctx_impl(ictx,0);
528799
	}
528799
}
5aae4b
5aae4b
e7ddb2
void slbt_reset_arguments(struct slbt_exec_ctx * ectx)
e7ddb2
{
e7ddb2
	struct slbt_exec_ctx_impl *	ictx;
e7ddb2
	uintptr_t			addr;
e7ddb2
e7ddb2
	addr = (uintptr_t)ectx - offsetof(struct slbt_exec_ctx_impl,ctx);
e7ddb2
	ictx = (struct slbt_exec_ctx_impl *)addr;
e7ddb2
	memcpy(ictx->args,ictx->shadow,ictx->size);
e7ddb2
}
e7ddb2
e7ddb2
5aae4b
void slbt_reset_placeholders(struct slbt_exec_ctx * ectx)
5aae4b
{
a40c9a
	*ectx->dpic = "-USLIBTOOL_PLACEHOLDER_DPIC";
a40c9a
	*ectx->fpic = "-USLIBTOOL_PLACEHOLDER_FPIC";
a40c9a
	*ectx->cass = "-USLIBTOOL_PLACEHOLDER_COMPILE_ASSEMBLE";
5aae4b
93b62c
	*ectx->noundef = "-USLIBTOOL_PLACEHOLDER_NO_UNDEFINED";
0f8591
	*ectx->soname  = "-USLIBTOOL_PLACEHOLDER_SONAME";
0f8591
	*ectx->lsoname = "-USLIBTOOL_PLACEHOLDER_LSONAME";
e15ee1
	*ectx->symdefs = "-USLIBTOOL_PLACEHOLDER_SYMDEF_SWITCH";
e15ee1
	*ectx->symfile = "-USLIBTOOL_PLACEHOLDER_SYMDEF_FILE";
0f8591
a40c9a
	*ectx->lout[0] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_SWITCH";
a40c9a
	*ectx->lout[1] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_FILE";
3e7d5b
3e7d5b
	*ectx->rpath[0] = "-USLIBTOOL_PLACEHOLDER_RPATH_SWITCH";
3e7d5b
	*ectx->rpath[1] = "-USLIBTOOL_PLACEHOLDER_RPATH_DIR";
3e7d5b
df07fb
	ectx->mout[0]  = 0;
df07fb
	ectx->mout[1]  = 0;
df07fb
b1f977
	*ectx->sentinel= 0;
5aae4b
}
2a7f1c
2a7f1c
void slbt_disable_placeholders(struct slbt_exec_ctx * ectx)
2a7f1c
{
2a7f1c
	*ectx->dpic = 0;
2a7f1c
	*ectx->fpic = 0;
2a7f1c
	*ectx->cass = 0;
2a7f1c
2a7f1c
	*ectx->noundef = 0;
2a7f1c
	*ectx->soname  = 0;
2a7f1c
	*ectx->lsoname = 0;
e15ee1
	*ectx->symdefs = 0;
e15ee1
	*ectx->symfile = 0;
2a7f1c
2a7f1c
	*ectx->lout[0] = 0;
2a7f1c
	*ectx->lout[1] = 0;
3e7d5b
3e7d5b
	*ectx->rpath[0] = 0;
3e7d5b
	*ectx->rpath[1] = 0;
3e7d5b
2a7f1c
	*ectx->sentinel= 0;
2a7f1c
}