diff --git a/include/mdso/mdso.h b/include/mdso/mdso.h
index 5822880..105a9c5 100644
--- a/include/mdso/mdso.h
+++ b/include/mdso/mdso.h
@@ -55,6 +55,7 @@ enum mdso_custom_error {
 	MDSO_ERR_INVALID_DSTDIR,
 	MDSO_ERR_INVALID_CONTEXT,
 	MDSO_ERR_INVALID_SOURCE,
+	MDSO_ERR_INVALID_VECTOR,
 	MDSO_ERR_SOURCE_SIZE_ZERO,
 	MDSO_ERR_CAP,
 };
@@ -74,7 +75,7 @@ struct mdso_input {
 struct mdso_object {
 	void *		addr;
 	size_t		size;
-	void *		mapstrs;
+	char *		mapstrs;
 	uint32_t	mapstrsnum;
 	uint32_t	mapstrslen;
 	uint32_t	arhdrpos;
@@ -155,6 +156,7 @@ mdso_api int      mdso_asmgen_symfn	(const struct mdso_driver_ctx *, const char 
 mdso_api int      mdso_objgen_dsometa	(const struct mdso_driver_ctx *, FILE * fout, struct mdso_object *);
 mdso_api int      mdso_objgen_symentry	(const struct mdso_driver_ctx *, const char * sym, FILE * fout, struct mdso_object *);
 mdso_api int      mdso_objgen_symfn	(const struct mdso_driver_ctx *, const char * sym, FILE * fout, struct mdso_object *);
+mdso_api int      mdso_argen_common	(const struct mdso_driver_ctx *, const char ** symv, FILE * fout, struct mdso_object *);
 
 #ifdef __cplusplus
 }
diff --git a/project/common.mk b/project/common.mk
index 8823bcc..5b1c676 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -1,4 +1,5 @@
 API_SRCS = \
+	src/archive/mdso_argen_common.c \
 	src/crc/mdso_crc64.c \
 	src/crc/mdso_crc32.c \
 	src/driver/mdso_amain.c \
diff --git a/project/tree.mk b/project/tree.mk
index ce61482..55b5f90 100644
--- a/project/tree.mk
+++ b/project/tree.mk
@@ -1,5 +1,6 @@
 tree.tag:
 		mkdir -p src
+		mkdir -p src/archive
 		mkdir -p src/crc
 		mkdir -p src/driver
 		mkdir -p src/helper
diff --git a/src/archive/mdso_argen_common.c b/src/archive/mdso_argen_common.c
new file mode 100644
index 0000000..95282e3
--- /dev/null
+++ b/src/archive/mdso_argen_common.c
@@ -0,0 +1,292 @@
+/****************************************************************/
+/*  mdso: midipix dso scavenger                                 */
+/*  Copyright (C) 2015--2017  Z. Gilboa                         */
+/*  Released under GPLv2 and GPLv3; see COPYING.MDSO.           */
+/****************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mdso/mdso.h>
+#include "mdso_errinfo_impl.h"
+#include "perk_structs.h"
+
+static void mdso_argen_common_hdr(
+	struct pe_raw_archive_common_hdr *	arhdr,
+	char *					file_id,
+	size_t					size)
+{
+	size_t	slen;
+	char	sbuf[10];
+
+	memset(arhdr,0x20,sizeof(*arhdr));
+
+	slen = strlen(file_id);
+	memcpy(arhdr->ar_file_id,file_id,slen);
+	arhdr->ar_file_id[slen] = '/';
+
+	arhdr->ar_uid[0] = '0';
+	arhdr->ar_gid[0] = '0';
+	arhdr->ar_file_mode[0] = '0';
+
+	slen = sprintf(sbuf,"%zu",size);
+	memcpy(arhdr->ar_file_size,sbuf,slen);
+
+	arhdr->ar_end_tag[0] = 0x60;
+	arhdr->ar_end_tag[1] = 0x0a;
+}
+
+static void mdso_write_big_endian_long(unsigned char * ch, uint32_t val)
+{
+	ch[3] = val;
+	ch[2] = val >> 8;
+	ch[1] = val >> 16;
+	ch[0] = val >> 24;
+}
+
+int  mdso_argen_common(
+	const struct mdso_driver_ctx *	dctx,
+	const char **			symv,
+	FILE *				fout,
+	struct mdso_object *		vobj)
+{
+	int					ret;
+	const char **				psym;
+	int					nsym;
+	int					nobj;
+	uint32_t				objlen;
+	uint32_t				hdrlen;
+	uint32_t				mapstrsnum;
+	uint32_t				mapstrslen;
+	uint32_t				symidx;
+	unsigned char *				ar;
+	unsigned char *				mark;
+	unsigned char *				idx;
+	char *					mapstrs;
+	struct pe_raw_archive_common_hdr *	arhdr;
+	struct mdso_object *			pobj;
+	struct mdso_object *			aobj;
+	struct mdso_object			sobj[256];
+	char					objname[16];
+
+	/* init */
+	memset (sobj,0,sizeof(sobj));
+
+	for (nsym=0,psym=symv; *psym; psym++)
+		nsym++;
+
+	if ((nobj = 2*nsym + 1) < 256)
+		aobj = sobj;
+
+	else if (nobj > 1024*1024)
+		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_VECTOR);
+
+	else if (!(aobj = calloc(1,nobj*sizeof(*aobj))))
+		return MDSO_SYSTEM_ERROR(dctx);
+
+	/* archive signature, archive header */
+	objlen  = 8;
+	objlen += sizeof(struct pe_raw_archive_common_hdr);
+
+	/* archive meta */
+	ret = mdso_objgen_dsometa(dctx,0,aobj);
+
+	aobj->size += 1;
+	aobj->size |= 1;
+	aobj->size ^= 1;
+
+	objlen += aobj->size;
+	objlen += aobj->mapstrslen;
+	objlen += sizeof(uint32_t) * aobj->mapstrsnum;
+	objlen += sizeof(struct pe_raw_archive_common_hdr);
+
+	mapstrslen = aobj->mapstrslen;
+	mapstrsnum = aobj->mapstrsnum;
+
+	for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) {
+		ret  = mdso_objgen_symfn(dctx,*psym,0,pobj);
+
+		pobj->size += 1;
+		pobj->size |= 1;
+		pobj->size ^= 1;
+
+		objlen += pobj->size;
+		objlen += pobj->mapstrslen;
+		objlen += sizeof(uint32_t) * pobj->mapstrsnum;
+		objlen += sizeof(struct pe_raw_archive_common_hdr);
+
+		mapstrslen += pobj->mapstrslen;
+		mapstrsnum += pobj->mapstrsnum;
+		pobj++;
+
+		ret |= mdso_objgen_symentry(dctx,*psym,0,pobj);
+
+		pobj->size += 1;
+		pobj->size |= 1;
+		pobj->size ^= 1;
+
+		objlen += pobj->size;
+		objlen += pobj->mapstrslen;
+		objlen += sizeof(uint32_t) * pobj->mapstrsnum;
+		objlen += sizeof(struct pe_raw_archive_common_hdr);
+
+		mapstrslen += pobj->mapstrslen;
+		mapstrsnum += pobj->mapstrsnum;
+		pobj++;
+	}
+
+	if (ret && (aobj != sobj))
+		free(aobj);
+
+	if (ret)
+		return ret;
+
+	/* archive alignment */
+	mapstrslen += 1;
+	mapstrslen |= 1;
+	mapstrslen ^= 1;
+
+	objlen += 15;
+	objlen |= 15;
+	objlen ^= 15;
+
+	if (vobj && vobj->addr && (vobj->size < objlen))
+		return MDSO_BUFFER_ERROR(dctx);
+
+	if (vobj && !vobj->addr) {
+		vobj->size = objlen;
+		vobj->mapstrslen = mapstrslen;
+		vobj->mapstrsnum = mapstrsnum;
+		return 0;
+	}
+
+	if (vobj)
+		ar = (unsigned char *)vobj->addr;
+
+	else if (!(ar = calloc(1,objlen))) {
+		if (aobj != sobj)
+			free(aobj);
+
+		return MDSO_SYSTEM_ERROR(dctx);
+	}
+
+	/* archive signature */
+	memcpy(ar,"!<arch>\n",8);
+	mark = &ar[8];
+
+	/* archive header */
+	arhdr  = (struct pe_raw_archive_common_hdr *)mark;
+	hdrlen = sizeof(uint32_t) * (1 + mapstrsnum) + mapstrslen;
+	mdso_argen_common_hdr(arhdr,"",hdrlen);
+	mark += sizeof(*arhdr);
+
+	/* archive index initialization */
+	mdso_write_big_endian_long(mark,mapstrsnum);
+	mark += sizeof(uint32_t);
+
+	idx   = mark;
+	mark += sizeof(uint32_t) * mapstrsnum;
+
+	mapstrs = (char *)mark;
+	mark   += mapstrslen;
+
+	/* .dsometa object */
+	aobj->mapstrs  = mapstrs;
+	aobj->arhdrpos = (uint32_t)(mark - ar);
+	aobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
+	aobj->addr     = &mark[aobj->arhdrlen];
+
+	for (symidx=0; symidx<aobj->mapstrsnum; symidx++) {
+		mdso_write_big_endian_long(idx,aobj->arhdrpos);
+		idx += sizeof(uint32_t);
+	}
+
+	ret = mdso_objgen_dsometa(dctx,0,aobj);
+
+	mdso_argen_common_hdr(
+		(struct pe_raw_archive_common_hdr *)mark,
+		".dsometa.o",aobj->size);
+
+	mark    += aobj->arhdrlen + aobj->size;
+	mapstrs += aobj->mapstrslen;
+
+	/* archive symfn and symentry objects */
+	for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) {
+		/* symfn object */
+		pobj->mapstrs  = mapstrs;
+		pobj->arhdrpos = (uint32_t)(mark - ar);
+		pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
+		pobj->addr     = &mark[pobj->arhdrlen];
+
+		for (symidx=0; symidx<pobj->mapstrsnum; symidx++) {
+			mdso_write_big_endian_long(idx,pobj->arhdrpos);
+			idx += sizeof(uint32_t);
+		}
+
+		ret = mdso_objgen_symfn(dctx,*psym,0,pobj);
+
+		sprintf(
+			objname,"f%06zu.o",
+			psym - symv);
+
+		mdso_argen_common_hdr(
+			(struct pe_raw_archive_common_hdr *)mark,
+			objname,pobj->size);
+
+		mark    += pobj->arhdrlen + pobj->size;
+		mapstrs += pobj->mapstrslen;
+		pobj++;
+
+
+		/* symentry object */
+		pobj->mapstrs  = mapstrs;
+		pobj->arhdrpos = (uint32_t)(mark - ar);
+		pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
+		pobj->addr     = &mark[pobj->arhdrlen];
+
+		for (symidx=0; symidx<pobj->mapstrsnum; symidx++) {
+			mdso_write_big_endian_long(idx,pobj->arhdrpos);
+			idx += sizeof(uint32_t);
+		}
+
+		sprintf(
+			objname,"s%06zu.o",
+			psym - symv);
+
+		ret = mdso_objgen_symentry(dctx,*psym,0,pobj);
+
+		mdso_argen_common_hdr(
+			(struct pe_raw_archive_common_hdr *)mark,
+			objname,pobj->size);
+
+		mark    += pobj->arhdrlen + pobj->size;
+		mapstrs += pobj->mapstrslen;
+		pobj++;
+	}
+
+	if (ret) {
+		if (aobj != sobj)
+			free(aobj);
+
+		if (!vobj)
+			free(ar);
+
+		return ret;
+	}
+
+	/* tada */
+	if (fout)
+		ret = fwrite(ar,objlen,1,fout);
+
+	if (aobj != sobj)
+		free(aobj);
+
+	if (!vobj)
+		free(ar);
+
+	return (ret == 0)
+		? MDSO_FILE_ERROR(dctx)
+		: 0;
+}
diff --git a/src/object/mdso_objgen_dsometa.c b/src/object/mdso_objgen_dsometa.c
index 61df843..dfe8a33 100644
--- a/src/object/mdso_objgen_dsometa.c
+++ b/src/object/mdso_objgen_dsometa.c
@@ -70,6 +70,8 @@ int mdso_objgen_dsometa(
 
 	if (vobj && !vobj->addr) {
 		vobj->size = objlen;
+		vobj->mapstrsnum = 1;
+		vobj->mapstrslen = 10 + liblen;
 		return 0;
 	}
 
@@ -217,6 +219,10 @@ int mdso_objgen_dsometa(
 	memcpy(&mark[0],".dsometa_",9);
 	memcpy(&mark[9],dctx->cctx->libname,liblen);
 
+	/* archive symbol map */
+	if (vobj && vobj->mapstrs)
+		memcpy(vobj->mapstrs,mark,9+liblen);
+
 	/* .libname */
 	mark = dsometa->hdr.cfh_machine;
 	memcpy(&mark[stroff],dctx->cctx->libname,liblen);
diff --git a/src/object/mdso_objgen_symentry.c b/src/object/mdso_objgen_symentry.c
index 3a3503f..47167c7 100644
--- a/src/object/mdso_objgen_symentry.c
+++ b/src/object/mdso_objgen_symentry.c
@@ -38,6 +38,7 @@ int mdso_objgen_symentry(
 	struct mdso_symentry_object *	syment;
 	struct pe_raw_coff_symbol *	symrec;
 	unsigned char *			mark;
+	unsigned char *			mapsym;
 	struct pe_raw_aux_rec_section *	aux;
 	size_t				buflen;
 	size_t				liblen;
@@ -57,6 +58,7 @@ int mdso_objgen_symentry(
 	uint32_t			cstoff;
 	uint32_t			datoff;
 	uint32_t			stroff;
+	uint32_t			uscore;
 
 	if ((buflen = strlen(sym)) > 1024*1024)
 		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA);
@@ -67,12 +69,15 @@ int mdso_objgen_symentry(
 	symlen = (uint32_t)buflen;
 	cstlen = (uint32_t)liblen + (3 * symlen) + 64;
 	objlen = sizeof(*syment) + cstlen;
+	uscore = !(dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR);
 
 	if (vobj && vobj->addr && (vobj->size < objlen))
 		return MDSO_BUFFER_ERROR(dctx);
 
 	if (vobj && !vobj->addr) {
 		vobj->size = objlen;
+		vobj->mapstrsnum = 1;
+		vobj->mapstrslen = 7 + uscore + symlen;
 		return 0;
 	}
 
@@ -210,6 +215,7 @@ int mdso_objgen_symentry(
 	symrec += 1;
 
 	/* coff symbol: __imp_sym */
+	mapsym = mark;
 	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
 	symrec[0].cs_num_of_aux_symbols[0] = 0;
 
@@ -231,6 +237,10 @@ int mdso_objgen_symentry(
 	mark   += 7 + symlen;
 	symrec += 1;
 
+	/* archive symbol map */
+	if (vobj && vobj->mapstrs)
+		memcpy(vobj->mapstrs,mapsym,mark-mapsym);
+
 	/* coff symbol: .dsometa_libname */
 	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
 	symrec[0].cs_num_of_aux_symbols[0] = 0;
diff --git a/src/object/mdso_objgen_symfn.c b/src/object/mdso_objgen_symfn.c
index 3bdd98f..47f9280 100644
--- a/src/object/mdso_objgen_symfn.c
+++ b/src/object/mdso_objgen_symfn.c
@@ -53,6 +53,7 @@ int mdso_objgen_symfn(
 	struct pe_raw_coff_symbol *	symrec;
 	const unsigned char *		code;
 	unsigned char *			mark;
+	unsigned char *			mapsym;
 	struct pe_raw_aux_rec_section *	aux;
 	size_t				buflen;
 	uint32_t			symlen;
@@ -69,6 +70,7 @@ int mdso_objgen_symfn(
 	uint32_t			cstoff;
 	uint32_t			codoff;
 	uint32_t			datoff;
+	uint32_t			uscore;
 
 	if ((buflen = strlen(sym)) > 1024*1024)
 		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA);
@@ -76,12 +78,15 @@ int mdso_objgen_symfn(
 	symlen = (uint32_t)buflen;
 	cstlen = (3 * symlen) + 32;
 	objlen = sizeof(*symfn) + cstlen;
+	uscore = !(dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR);
 
 	if (vobj && vobj->addr && (vobj->size < objlen))
 		return MDSO_BUFFER_ERROR(dctx);
 
 	if (vobj && !vobj->addr) {
 		vobj->size = objlen;
+		vobj->mapstrsnum = 1;
+		vobj->mapstrslen = 1 + uscore + symlen;
 		return 0;
 	}
 
@@ -179,6 +184,7 @@ int mdso_objgen_symfn(
 	symrec += 2;
 
 	/* coff symbol: sym */
+	mapsym = mark;
 	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
 	symrec[0].cs_num_of_aux_symbols[0] = 1;
 
@@ -199,6 +205,10 @@ int mdso_objgen_symfn(
 	mark   += 1 + symlen;
 	symrec += 2;
 
+	/* archive symbol map */
+	if (vobj && vobj->mapstrs)
+		memcpy(vobj->mapstrs,mapsym,mark-mapsym);
+
 	/* coff symbol: __imp_sym */
 	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
 	symrec[0].cs_num_of_aux_symbols[0] = 0;
diff --git a/src/output/mdso_output_error.c b/src/output/mdso_output_error.c
index 08d66dc..4793a35 100644
--- a/src/output/mdso_output_error.c
+++ b/src/output/mdso_output_error.c
@@ -27,6 +27,7 @@ static const char const * const mdso_error_strings[MDSO_ERR_CAP] = {
 	[MDSO_ERR_INVALID_DSTDIR]   = "invalid destination directory",
 	[MDSO_ERR_INVALID_CONTEXT]  = "invalid driver or unit context",
 	[MDSO_ERR_INVALID_SOURCE]   = "invalid symbol definition source file",
+	[MDSO_ERR_INVALID_VECTOR]   = "invalid symbol vector, or vector too long",
 	[MDSO_ERR_SOURCE_SIZE_ZERO] = "cannot map an empty symbol definition source file",
 };