Blame src/arbits/slbt_archive_merge.c

db49af
/*******************************************************************/
db49af
/*  slibtool: a skinny libtool implementation, written in C        */
db49af
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
db49af
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
db49af
/*******************************************************************/
db49af
db49af
#include <time.h>
db49af
#include <stdio.h>
db49af
#include <stdint.h>
db49af
#include <stddef.h>
db49af
#include <stdlib.h>
db49af
#include <string.h>
db49af
#include <inttypes.h>
db49af
#include <sys/mman.h>
db49af
#include <sys/types.h>
db49af
db49af
#include <slibtool/slibtool.h>
db49af
#include <slibtool/slibtool_arbits.h>
db49af
#include "slibtool_ar_impl.h"
db49af
#include "slibtool_driver_impl.h"
db49af
#include "slibtool_errinfo_impl.h"
db49af
db49af
/* anonymous fun */
db49af
#ifndef MAP_ANONYMOUS
db49af
#define MAP_ANONYMOUS MAP_ANON
db49af
#endif
db49af
db49af
/* time stamp format specifier */
db49af
#define PPRII64 "%"PRIi64
db49af
db49af
/* file size format specifier */
db49af
#define PPRIU64 "%"PRIu64
db49af
db49af
struct armap_buffer_32 {
db49af
	uint32_t        moffset;
db49af
	const char *    symname;
db49af
	uint32_t        baseidx;
db49af
};
db49af
db49af
struct armap_buffer_64 {
db49af
	uint64_t        moffset;
db49af
	const char *    symname;
db49af
	uint64_t        baseidx;
db49af
};
db49af
db49af
static const char ar_signature[] = AR_SIGNATURE;
db49af
db49af
static int slbt_create_anonymous_archive_ctx(
db49af
	const struct slbt_driver_ctx *	dctx,
db49af
	size_t                          size,
db49af
	struct slbt_archive_ctx **	pctx)
db49af
{
db49af
	struct slbt_archive_ctx_impl *	ctx;
db49af
db49af
	if (!(ctx = calloc(1,sizeof(*ctx))))
db49af
		return SLBT_BUFFER_ERROR(dctx);
db49af
db49af
	ctx->map.map_size = size;
db49af
	ctx->map.map_addr = mmap(
db49af
		0,size,
db49af
		PROT_READ|PROT_WRITE,
db49af
		MAP_PRIVATE|MAP_ANONYMOUS,
db49af
		-1,0);
db49af
db49af
	if (ctx->map.map_addr == MAP_FAILED) {
db49af
		free(ctx);
db49af
		return SLBT_SYSTEM_ERROR(dctx,0);
db49af
	}
db49af
db49af
	ctx->dctx       = dctx;
db49af
	ctx->actx.map	= &ctx->map;
db49af
db49af
	*pctx = &ctx->actx;
db49af
db49af
	return 0;
db49af
}
db49af
db49af
static off_t slbt_armap_write_be_32(unsigned char * mark, uint32_t val)
db49af
{
db49af
	mark[0] = val >> 24;
db49af
	mark[1] = val >> 16;
db49af
	mark[2] = val >> 8;
db49af
	mark[3] = val;
db49af
db49af
	return sizeof(uint32_t);
db49af
}
db49af
db49af
static off_t slbt_armap_write_le_32(unsigned char * mark, uint32_t val)
db49af
{
db49af
	mark[0] = val;
db49af
	mark[1] = val >> 8;
db49af
	mark[2] = val >> 16;
db49af
	mark[3] = val >> 24;
db49af
db49af
	return sizeof(uint32_t);
db49af
}
db49af
db49af
static off_t slbt_armap_write_be_64(unsigned char * mark, uint64_t val)
db49af
{
db49af
	slbt_armap_write_be_32(&mark[0],val >> 32);
db49af
	slbt_armap_write_be_32(&mark[4],val);
db49af
db49af
	return sizeof(uint64_t);
db49af
}
db49af
db49af
static off_t slbt_armap_write_le_64(unsigned char * mark, uint64_t val)
db49af
{
db49af
	slbt_armap_write_be_32(&mark[0],val);
db49af
	slbt_armap_write_be_32(&mark[4],val >> 32);
db49af
db49af
	return sizeof(uint64_t);
db49af
}
db49af
db49af
db49af
static int slbt_merge_archives_fail(
db49af
	struct slbt_archive_ctx *   arctx,
db49af
	struct armap_buffer_32 *    bsdmap32,
db49af
	struct armap_buffer_64 *    bsdmap64,
db49af
	int                         ret)
db49af
{
db49af
	if (bsdmap32)
db49af
		free(bsdmap32);
db49af
db49af
	if (bsdmap64)
db49af
		free(bsdmap64);
db49af
db49af
	if (arctx)
db49af
		slbt_free_archive_ctx(arctx);
db49af
db49af
	return ret;
db49af
}
db49af
db49af
db49af
int slbt_merge_archives(
db49af
	struct slbt_archive_ctx * const arctxv[],
db49af
	struct slbt_archive_ctx **      arctxm)
db49af
{
db49af
	struct slbt_archive_ctx * const *       arctxp;
db49af
	struct slbt_archive_ctx *               arctx;
db49af
db49af
	const struct slbt_driver_ctx *          dctx;
db49af
	const struct slbt_archive_meta *        meta;
db49af
db49af
	struct ar_raw_file_header *             arhdr;
db49af
	struct ar_meta_member_info **           memberp;
db49af
	struct ar_meta_member_info *            meminfo;
db49af
db49af
	struct ar_meta_member_info *            armap;
db49af
	struct ar_meta_member_info *            arnames;
db49af
db49af
	const struct ar_meta_armap_common_32 *  armap32;
db49af
	const struct ar_meta_armap_common_64 *  armap64;
db49af
	const struct ar_meta_armap_ref_32 *     symref32;
db49af
	const struct ar_meta_armap_ref_64 *     symref64;
db49af
db49af
	struct armap_buffer_32 *                bsdmap32;
db49af
	struct armap_buffer_64 *                bsdmap64;
db49af
	struct armap_buffer_32 *                bsdsort32;
db49af
	struct armap_buffer_64 *                bsdsort64;
db49af
db49af
	size_t                                  nbytes;
db49af
	ssize_t                                 nwritten;
db49af
db49af
	uint32_t                                mapattr;
db49af
	uint64_t                                nmembers;
db49af
	uint64_t                                nsymrefs;
db49af
db49af
	uint64_t                                sarmap;
db49af
	uint64_t                                sarname;
db49af
	uint64_t                                sarchive;
db49af
	uint64_t                                smembers;
db49af
	uint64_t                                ssymrefs;
db49af
	uint64_t                                ssymstrs;
db49af
	uint64_t                                snamestrs;
db49af
db49af
	int64_t                                 omembers;
db49af
	int64_t                                 osymrefs;
db49af
	int64_t                                 onamestrs;
db49af
	int64_t                                 omemfixup;
db49af
db49af
	char *                                  base;
db49af
	unsigned char *                         ubase;
db49af
db49af
	char *                                  ch;
db49af
	unsigned char *                         uch;
db49af
db49af
	char *                                  namebase;
db49af
	char *                                  namestr;
db49af
	char *                                  strtbl;
db49af
db49af
	uint64_t                                idx;
db49af
	uint64_t                                mapidx;
db49af
	uint64_t                                cmpidx;
db49af
db49af
	off_t (*armap_write_uint32)(
db49af
		unsigned char *,
db49af
		uint32_t);
db49af
db49af
	off_t (*armap_write_uint64)(
db49af
		unsigned char *,
db49af
		uint64_t);
db49af
db49af
	/* init */
db49af
	nmembers = nsymrefs = ssymstrs = mapattr   = 0;
db49af
	sarchive = smembers = ssymrefs = snamestrs = 0;
db49af
	omembers = osymrefs = onamestrs = 0;
db49af
db49af
	if (!arctxv || !arctxv[0])
db49af
		return -1;
db49af
db49af
	if (!(dctx = slbt_get_archive_ictx(arctxv[0])->dctx))
db49af
		return -1;
db49af
db49af
	/* determine armap type and size of archive elements */
db49af
	for (armap=0,arnames=0,arctxp=arctxv; *arctxp; arctxp++) {
db49af
		if (slbt_get_archive_ictx(*arctxp)->dctx != dctx)
db49af
			return SLBT_CUSTOM_ERROR(
db49af
				dctx,
db49af
				SLBT_ERR_AR_DRIVER_MISMATCH);
db49af
db49af
		meta    = (*arctxp)->meta;
db49af
		armap32 = meta->a_armap_primary.ar_armap_common_32;
db49af
		armap64 = meta->a_armap_primary.ar_armap_common_64;
db49af
db49af
		for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
db49af
			meminfo = *memberp;
db49af
db49af
			switch (meminfo->ar_member_attr) {
db49af
				case AR_MEMBER_ATTR_ARMAP:
db49af
					if (armap32) {
db49af
						if (mapattr == 0) {
db49af
							armap   = meminfo;
db49af
							mapattr = armap32->ar_armap_attr;
db49af
						} else if (mapattr != armap32->ar_armap_attr) {
db49af
							return SLBT_CUSTOM_ERROR(
db49af
								dctx,
db49af
								SLBT_ERR_AR_ARMAP_MISMATCH);
db49af
						}
db49af
db49af
						nsymrefs += armap32->ar_num_of_symbols;
db49af
						ssymstrs += armap32->ar_size_of_strs;
db49af
db49af
					} else if (armap64) {
db49af
						if (mapattr == 0) {
db49af
							armap   = meminfo;
db49af
							mapattr = armap64->ar_armap_attr;
db49af
						} else if (mapattr != armap64->ar_armap_attr) {
db49af
							return SLBT_CUSTOM_ERROR(
db49af
								dctx,
db49af
								SLBT_ERR_AR_ARMAP_MISMATCH);
db49af
						}
db49af
db49af
						nsymrefs += armap64->ar_num_of_symbols;
db49af
					}
db49af
db49af
					break;
db49af
db49af
				case AR_MEMBER_ATTR_LINKINFO:
db49af
					break;
db49af
db49af
				case AR_MEMBER_ATTR_NAMESTRS:
db49af
					snamestrs += meminfo->ar_object_size;
db49af
db49af
					if (!arnames)
db49af
						arnames = meminfo;
db49af
db49af
					break;
db49af
db49af
				default:
db49af
					smembers += sizeof(struct ar_raw_file_header);
db49af
					smembers += meminfo->ar_file_header.ar_file_size;
db49af
					smembers += 1;
db49af
					smembers |= 1;
db49af
					smembers ^= 1;
db49af
					nmembers++;
db49af
db49af
					break;
db49af
			}
db49af
		}
db49af
	}
db49af
db49af
	/* armap size */
db49af
	if (sarmap = 0, sarname = 0, (mapattr == 0)) {
db49af
		(void)0;
db49af
db49af
	} else if (mapattr & AR_ARMAP_ATTR_SYSV) {
db49af
		if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
db49af
			sarmap += sizeof(uint32_t);
db49af
			sarmap += sizeof(uint32_t) * nsymrefs;
db49af
		} else {
db49af
			sarmap += sizeof(uint64_t);
db49af
			sarmap += sizeof(uint64_t) * nsymrefs;
db49af
		}
db49af
db49af
	} else if (mapattr & AR_ARMAP_ATTR_BSD) {
db49af
		if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
db49af
			sarmap += 2 * sizeof(uint32_t);
db49af
			sarmap += 2 * sizeof(uint32_t) * nsymrefs;
db49af
		} else {
db49af
			sarmap += 2 * sizeof(uint64_t);
db49af
			sarmap += 2 * sizeof(uint64_t) * nsymrefs;
db49af
		}
db49af
db49af
		sarname += armap->ar_file_header.ar_file_size;
db49af
		sarname -= armap->ar_object_size;
db49af
	} else {
db49af
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);
db49af
	}
db49af
32c230
	ssymstrs += 1;
32c230
	ssymstrs |= 1;
32c230
	ssymstrs ^= 1;
32c230
6b3bd5
	/* (debugging) */
6b3bd5
	(void)nmembers;
6b3bd5
db49af
	/* long-names member alignment */
db49af
	snamestrs += 1;
db49af
	snamestrs |= 1;
db49af
	snamestrs ^= 1;
db49af
db49af
	/* archive size */
db49af
	sarchive  = sizeof(struct ar_raw_signature);
db49af
	sarchive += armap   ? sizeof(struct ar_raw_file_header) : 0;
db49af
	sarchive += arnames ? sizeof(struct ar_raw_file_header) : 0;
db49af
	sarchive += sarname;
db49af
	sarchive += sarmap;
db49af
	sarchive += ssymstrs;
db49af
	sarchive += snamestrs;
db49af
	sarchive += smembers;
db49af
db49af
	/* offset from archive base to first public member */
db49af
	omembers  = sarchive;
db49af
	omembers -= smembers;
db49af
db49af
db49af
	/* create in-memory archive */
db49af
	if (slbt_create_anonymous_archive_ctx(dctx,sarchive,&arctx) < 0)
db49af
		return SLBT_NESTED_ERROR(dctx);
db49af
db49af
db49af
	/* get ready for writing */
db49af
	base  = arctx->map->map_addr;
db49af
	ubase = arctx->map->map_addr;
db49af
db49af
db49af
	/* archive header */
db49af
	ch = base;
db49af
	memcpy(ch,ar_signature,sizeof(struct ar_raw_signature));
db49af
	ch += sizeof(struct ar_raw_signature);
db49af
db49af
db49af
	/* armap header */
db49af
	if (armap) {
db49af
		arhdr = (struct ar_raw_file_header *)ch;
db49af
		memcpy(arhdr,armap->ar_member_data,sizeof(*arhdr)+sarname);
db49af
db49af
		nwritten = armap->ar_file_header.ar_time_date_stamp
db49af
				? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
db49af
				: 0;
db49af
db49af
		if (nwritten < 0)
db49af
			return slbt_merge_archives_fail(
db49af
				arctx,0,0,
db49af
				SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
		for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
db49af
			arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
db49af
db49af
		nwritten = sprintf(
db49af
			arhdr->ar_file_size,PPRIU64,
db49af
			sarname + sarmap + ssymstrs);
db49af
db49af
		if (nwritten < 0)
db49af
			return slbt_merge_archives_fail(
db49af
				arctx,0,0,
db49af
				SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
		for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
db49af
			arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
db49af
	}
db49af
db49af
db49af
	/* arnames header (sysv only) */
db49af
	if (arnames) {
db49af
		ch  = base;
db49af
		ch += omembers;
db49af
		ch -= snamestrs;
db49af
		ch -= sizeof(struct ar_raw_file_header);
db49af
db49af
		namebase  = ch;
db49af
		namebase += sizeof(struct ar_raw_file_header);
db49af
db49af
		memset(namebase,0,snamestrs);
db49af
		namestr = namebase;
db49af
db49af
		arhdr = (struct ar_raw_file_header *)ch;
db49af
		memcpy(arhdr,arnames->ar_member_data,sizeof(*arhdr));
db49af
db49af
		nwritten = arnames->ar_file_header.ar_time_date_stamp
db49af
				? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
db49af
				: 0;
db49af
db49af
		if (nwritten < 0)
db49af
			return slbt_merge_archives_fail(
db49af
				arctx,0,0,
db49af
				SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
		for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
db49af
			arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
db49af
db49af
		nwritten = sprintf(
db49af
			arhdr->ar_file_size,PPRIU64,
db49af
			snamestrs);
db49af
db49af
		if (nwritten < 0)
db49af
			return slbt_merge_archives_fail(
db49af
				arctx,0,0,
db49af
				SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
		for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
db49af
			arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
db49af
	}
db49af
db49af
db49af
	/* armap data (preparation) */
db49af
	armap_write_uint32 = 0;
db49af
	armap_write_uint64 = 0;
db49af
db49af
	bsdmap32 = 0;
db49af
	bsdmap64 = 0;
db49af
db49af
	if (mapattr & AR_ARMAP_ATTR_BE_32)
db49af
		armap_write_uint32 = slbt_armap_write_be_32;
db49af
db49af
	else if (mapattr & AR_ARMAP_ATTR_LE_32)
db49af
		armap_write_uint32 = slbt_armap_write_le_32;
db49af
db49af
	else if (mapattr & AR_ARMAP_ATTR_BE_64)
db49af
		armap_write_uint64 = slbt_armap_write_be_64;
db49af
db49af
	else if (mapattr & AR_ARMAP_ATTR_LE_64)
db49af
		armap_write_uint64 = slbt_armap_write_le_64;
db49af
db49af
	uch  = ubase;
db49af
	uch += sizeof(struct ar_raw_signature);
db49af
	uch += sizeof(struct ar_raw_file_header);
db49af
	uch += sarname;
db49af
db49af
	if (mapattr & AR_ARMAP_ATTR_SYSV) {
db49af
		if (armap_write_uint32) {
db49af
			uch += armap_write_uint32(uch,nsymrefs);
db49af
db49af
			ch  = base;
db49af
			ch += uch - ubase;
db49af
			ch += sizeof(uint32_t) * nsymrefs;
db49af
		} else {
db49af
			uch += armap_write_uint64(uch,nsymrefs);
db49af
db49af
			ch  = base;
db49af
			ch += uch - ubase;
db49af
			ch += sizeof(uint64_t) * nsymrefs;
db49af
		}
db49af
db49af
	} else if (mapattr & AR_ARMAP_ATTR_BSD) {
db49af
		strtbl  = base;
db49af
		strtbl += omembers;
db49af
		strtbl -= ssymstrs;
db49af
db49af
		memset(strtbl,0,ssymstrs);
db49af
db49af
		if (armap_write_uint32) {
db49af
			if (!(bsdmap32 = calloc(2*nsymrefs,sizeof(struct armap_buffer_32))))
db49af
				return slbt_merge_archives_fail(
db49af
					arctx,0,0,
db49af
					SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
			bsdsort32 = &bsdmap32[nsymrefs];
db49af
db49af
		} else {
db49af
			if (!(bsdmap64 = calloc(2*nsymrefs,sizeof(struct armap_buffer_64))))
db49af
				return slbt_merge_archives_fail(
db49af
					arctx,0,0,
db49af
					SLBT_SYSTEM_ERROR(dctx,0));
db49af
db49af
			bsdsort64 = &bsdmap64[nsymrefs];
db49af
		}
db49af
	}
db49af
db49af
	/* main iteration (armap data, long-names, public members) */
db49af
	for (mapidx=0,arctxp=arctxv; *arctxp; arctxp++) {
db49af
		meta    = (*arctxp)->meta;
db49af
		armap32 = meta->a_armap_primary.ar_armap_common_32;
db49af
		armap64 = meta->a_armap_primary.ar_armap_common_64;
db49af
db49af
		if ((memberp = meta->a_memberv)) {
db49af
			for (omemfixup=0; *memberp && !omemfixup; memberp++) {
db49af
				meminfo = *memberp;
db49af
db49af
				switch (meminfo->ar_member_attr) {
db49af
					case AR_MEMBER_ATTR_ARMAP:
db49af
					case AR_MEMBER_ATTR_LINKINFO:
db49af
					case AR_MEMBER_ATTR_NAMESTRS:
db49af
						break;
db49af
db49af
					default:
db49af
						omemfixup  = (int64_t)meminfo->ar_member_data;
db49af
						omemfixup -= (int64_t)meta->r_archive.map_addr;
db49af
						break;
db49af
				}
db49af
			}
db49af
		}
db49af
db49af
		for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
db49af
			meminfo = *memberp;
db49af
db49af
			switch (meminfo->ar_member_attr) {
db49af
				case AR_MEMBER_ATTR_ARMAP:
db49af
					if (armap32 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
db49af
						symref32 = armap32->ar_symrefs;
db49af
db49af
						for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
db49af
							uch += armap_write_uint32(
db49af
								uch,
db49af
								symref32[idx].ar_member_offset + omembers - omemfixup);
db49af
db49af
							strcpy(ch,&armap32->ar_string_table[symref32[idx].ar_name_offset]);
db49af
							ch += strlen(ch);
db49af
							ch++;
db49af
						}
db49af
db49af
					} else if (armap64 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
db49af
						symref64 = armap64->ar_symrefs;
db49af
db49af
						for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
db49af
							uch += armap_write_uint64(
db49af
								uch,
db49af
								symref64[idx].ar_member_offset + omembers - omemfixup);
db49af
db49af
							strcpy(ch,&armap64->ar_string_table[symref64[idx].ar_name_offset]);
db49af
							ch += strlen(ch);
db49af
							ch++;
db49af
						}
db49af
db49af
					} else if (armap32 && (mapattr & AR_ARMAP_ATTR_BSD)) {
db49af
						symref32 = armap32->ar_symrefs;
db49af
db49af
						for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
db49af
							bsdmap32[mapidx].moffset  = symref32[idx].ar_member_offset;
db49af
							bsdmap32[mapidx].moffset += omembers - omemfixup;
db49af
db49af
							bsdmap32[mapidx].symname  = armap32->ar_string_table;
db49af
							bsdmap32[mapidx].symname += symref32[idx].ar_name_offset;
db49af
db49af
							mapidx++;
db49af
						}
db49af
db49af
					} else if (armap64 && (mapattr & AR_ARMAP_ATTR_BSD)) {
db49af
						symref64 = armap64->ar_symrefs;
db49af
db49af
						for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
db49af
							bsdmap64[mapidx].moffset  = symref64[idx].ar_member_offset;
db49af
							bsdmap64[mapidx].moffset += omembers - omemfixup;
db49af
db49af
							bsdmap64[mapidx].symname  = armap64->ar_string_table;
db49af
							bsdmap64[mapidx].symname += symref64[idx].ar_name_offset;
db49af
db49af
							mapidx++;
db49af
						}
db49af
					}
db49af
db49af
					break;
db49af
db49af
				case AR_MEMBER_ATTR_LINKINFO:
db49af
					break;
db49af
db49af
				case AR_MEMBER_ATTR_NAMESTRS:
db49af
					break;
db49af
db49af
				default:
db49af
					arhdr = meminfo->ar_member_data;
db49af
db49af
					memcpy(
db49af
						&base[omembers],arhdr,
db49af
						sizeof(*arhdr) + meminfo->ar_file_header.ar_file_size);
db49af
db49af
					if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_SYSV) {
db49af
						if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_NAME_REF) {
db49af
							nwritten = sprintf(
db49af
								&base[omembers],"/"PPRII64,
db49af
								namestr - namebase);
db49af
db49af
							if (nwritten < 0)
db49af
								SLBT_SYSTEM_ERROR(dctx,0);
db49af
db49af
							for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_id); nbytes++)
db49af
								base[omembers + nbytes] = AR_DEC_PADDING;
db49af
db49af
							strcpy(namestr,meminfo->ar_file_header.ar_member_name);
db49af
							namestr += strlen(namestr);
db49af
							*namestr++ = '/';
db49af
							*namestr++ = AR_OBJ_PADDING;
db49af
						}
db49af
					}
db49af
db49af
					omembers += sizeof(*arhdr);
db49af
					omembers += meminfo->ar_file_header.ar_file_size;
db49af
					omembers += 1;
db49af
					omembers |= 1;
db49af
					omembers ^= 1;
db49af
					break;
db49af
			}
db49af
		}
db49af
	}
db49af
db49af
	/* bsd variant: also sort the string table (because we can:=)) */
db49af
	if (bsdmap32) {
db49af
		for (mapidx=0; mapidx
db49af
			for (cmpidx=0; cmpidx
db49af
				if (strcmp(bsdmap32[cmpidx].symname,bsdmap32[mapidx].symname) < 0)
db49af
					bsdmap32[mapidx].baseidx++;
db49af
db49af
		/* a symbol might be present in more than one member; */
db49af
		/* see whether ar_member_offset has already been set) */
db49af
		for (mapidx=0,ch=strtbl; mapidx
db49af
			idx = bsdmap32[mapidx].baseidx;
db49af
db49af
			for (; bsdsort32[idx].moffset; )
db49af
				idx++;
db49af
db49af
			bsdsort32[idx].moffset = bsdmap32[mapidx].moffset;
db49af
			bsdsort32[idx].symname = bsdmap32[mapidx].symname;
db49af
		}
db49af
db49af
		uch += armap_write_uint32(uch,2*sizeof(uint32_t)*nsymrefs);
db49af
db49af
		for (mapidx=0,ch=strtbl; mapidx
db49af
			uch += armap_write_uint32(uch,ch-strtbl);
db49af
			uch += armap_write_uint32(uch,bsdsort32[mapidx].moffset);
db49af
db49af
			strcpy(ch,bsdsort32[mapidx].symname);
db49af
			ch += strlen(ch);
db49af
			ch++;
db49af
		}
db49af
e094ec
		uch += armap_write_uint32(uch,ssymstrs);
db49af
db49af
		free(bsdmap32);
db49af
db49af
	} else if (bsdmap64) {
db49af
		for (mapidx=0; mapidx
db49af
			for (cmpidx=0; cmpidx
db49af
				if (strcmp(bsdmap64[cmpidx].symname,bsdmap64[mapidx].symname) < 0)
db49af
					bsdmap64[mapidx].baseidx++;
db49af
db49af
		/* a symbol might be present in more than one member; */
db49af
		/* see whether ar_member_offset has already been set) */
db49af
		for (mapidx=0,ch=strtbl; mapidx
db49af
			idx = bsdmap64[mapidx].baseidx;
db49af
db49af
			for (; bsdsort64[idx].moffset; )
db49af
				idx++;
db49af
db49af
			bsdsort64[idx].moffset = bsdmap64[mapidx].moffset;
db49af
			bsdsort64[idx].symname = bsdmap64[mapidx].symname;
db49af
		}
db49af
db49af
		uch += armap_write_uint64(uch,2*sizeof(uint64_t)*nsymrefs);
db49af
db49af
		for (mapidx=0,ch=strtbl; mapidx
db49af
			uch += armap_write_uint64(uch,ch-strtbl);
db49af
			uch += armap_write_uint64(uch,bsdsort64[mapidx].moffset);
db49af
db49af
			strcpy(ch,bsdsort64[mapidx].symname);
db49af
			ch += strlen(ch);
db49af
			ch++;
db49af
		}
db49af
e094ec
		uch += armap_write_uint64(uch,ssymstrs);
db49af
db49af
		free(bsdmap64);
db49af
	}
db49af
db49af
	struct slbt_archive_ctx_impl * ictx;
db49af
	ictx = slbt_get_archive_ictx(arctx);
db49af
db49af
	if (slbt_get_archive_meta(dctx,arctx->map,&ictx->meta) < 0)
4bc345
		return slbt_merge_archives_fail(
db49af
			arctx,0,0,
db49af
			SLBT_NESTED_ERROR(dctx));
db49af
db49af
	ictx->actx.meta = ictx->meta;
db49af
db49af
	*arctxm = arctx;
db49af
db49af
	return 0;
db49af
}