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>
528799
528799
#define SLBT_ARGV_SPARE_PTRS	16
528799
528799
struct slbt_exec_ctx_impl {
528799
	int			argc;
528799
	char *			args;
e7ddb2
	char *			shadow;
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")))
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) */
ef1e6e
	size  = strlen(".lo") + sizeof('\0');
f0c096
	size +=  8 * (strlen(".libs/") + sizeof('\0'));
ef1e6e
	size += 36 * (strlen(".0000") + sizeof('\0'));
528799
528799
	/* buffer size (cargv, -Wc) */
528799
	for (parg=dctx->cctx->cargv; *parg; parg++, argc++)
528799
		if (!(strncmp("-Wc,",*parg,4)))
528799
			size += sizeof('\0') + slbt_parse_comma_separated_flags(
4c2181
					&(*parg)[4],&argc);
528799
		else
528799
			size += sizeof('\0') + strlen(*parg);
528799
e88a39
	/* buffer size (ldirname, lbasename, lobjname, aobjname, ltobjname) */
df088e
	if (dctx->cctx->output)
e02305
		size += 4*strlen(dctx->cctx->output);
df088e
	else if ((csrc = slbt_source_file(dctx->cctx->cargv)))
e02305
		size += 4*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)
f0c096
		size += strlen(dctx->cctx->settings.arprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.arsuffix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.dsoprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.dsoprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.exeprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.exeprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.impprefix) + sizeof('\0')
f0c096
			+ strlen(dctx->cctx->settings.impprefix) + sizeof('\0');
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;
f47761
	char *				slash;
df088e
	const char *			ref;
528799
	int				i;
528799
528799
	/* alloc */
528799
	if (!(ictx = slbt_exec_ctx_alloc(dctx)))
528799
		return -1;
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,'/'))) {
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';
df088e
			ch[-2] = '\0';
df088e
			ch--;
df088e
		} else if (ictx->ctx.csrc) {
cae4bb
			if ((mark = strrchr(ictx->ctx.lbasename,'.'))) {
cae4bb
				ch    = mark;
df088e
				*++ch = 'o';
df088e
				*++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 == ',') {
869626
					*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++];
0f8591
5aae4b
	ictx->ctx.lout[0] = &ictx->ctx.argv[i++];
5aae4b
	ictx->ctx.lout[1] = &ictx->ctx.argv[i++];
b1f977
	ictx->ctx.sentinel= &ictx->ctx.argv[i++];
df088e
62a7c9
	slbt_reset_placeholders(&ictx->ctx);
62a7c9
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)
e02305
			+ sizeof('\0');
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)
e88a39
			+ sizeof('\0');
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")
e88a39
				+ sizeof('\0');
528799
	}
528799
731e44
	/* linking: arfilename, lafilename, dsofilename */
731e44
	if (dctx->cctx->mode == SLBT_MODE_LINK && dctx->cctx->libname) {
731e44
		/* arfilename */
731e44
		ictx->ctx.arfilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s%s",
731e44
				ictx->ctx.ldirname,
731e44
				dctx->cctx->settings.arprefix,
731e44
				dctx->cctx->libname,
731e44
				dctx->cctx->settings.arsuffix)
731e44
			+ sizeof('\0');
731e44
731e44
731e44
731e44
		/* lafilename */
731e44
		ictx->ctx.lafilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s.la",
731e44
				ictx->ctx.ldirname,
731e44
				dctx->cctx->settings.dsoprefix,
731e44
				dctx->cctx->libname)
731e44
			+ sizeof('\0');
731e44
731e44
731e44
		/* dsofilename */
731e44
		ictx->ctx.dsofilename = ch;
731e44
		ch += sprintf(ch,"%s%s%s%s",
731e44
				ictx->ctx.ldirname,
731e44
				dctx->cctx->settings.dsoprefix,
731e44
				dctx->cctx->libname,
731e44
				dctx->cctx->settings.dsosuffix)
731e44
			+ sizeof('\0');
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);
f47761
			ch += strlen(ch) + sizeof('\0');
f47761
		} else
f47761
			ch += sprintf(ch,".libs/%s",dctx->cctx->output)
f47761
				+ sizeof('\0');
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
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";
0f8591
a40c9a
	*ectx->lout[0] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_SWITCH";
a40c9a
	*ectx->lout[1] = "-USLIBTOOL_PLACEHOLDER_OUTPUT_FILE";
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;
2a7f1c
2a7f1c
	*ectx->lout[0] = 0;
2a7f1c
	*ectx->lout[1] = 0;
2a7f1c
	*ectx->sentinel= 0;
2a7f1c
}