summaryrefslogtreecommitdiff
path: root/src/arbits
diff options
context:
space:
mode:
Diffstat (limited to 'src/arbits')
-rw-r--r--src/arbits/output/slbt_au_output_arname.c86
-rw-r--r--src/arbits/output/slbt_au_output_dlsyms.c12
-rw-r--r--src/arbits/output/slbt_au_output_mapfile.c12
-rw-r--r--src/arbits/output/slbt_au_output_members.c278
-rw-r--r--src/arbits/output/slbt_au_output_symbols.c201
-rw-r--r--src/arbits/slbt_archive_ctx.c117
-rw-r--r--src/arbits/slbt_archive_dlsyms.c458
-rw-r--r--src/arbits/slbt_archive_mapfile.c162
-rw-r--r--src/arbits/slbt_archive_mapstrv.c47
-rw-r--r--src/arbits/slbt_archive_merge.c734
-rw-r--r--src/arbits/slbt_archive_meta.c888
-rw-r--r--src/arbits/slbt_archive_store.c145
-rw-r--r--src/arbits/slbt_archive_symfile.c138
-rw-r--r--src/arbits/slbt_archive_syminfo.c345
-rw-r--r--src/arbits/slbt_armap_bsd_32.c157
-rw-r--r--src/arbits/slbt_armap_bsd_64.c174
-rw-r--r--src/arbits/slbt_armap_sysv_32.c120
-rw-r--r--src/arbits/slbt_armap_sysv_64.c128
18 files changed, 4202 insertions, 0 deletions
diff --git a/src/arbits/output/slbt_au_output_arname.c b/src/arbits/output/slbt_au_output_arname.c
new file mode 100644
index 0000000..28e081d
--- /dev/null
+++ b/src/arbits/output/slbt_au_output_arname.c
@@ -0,0 +1,86 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_ar_impl.h"
+
+#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \
+ | SLBT_PRETTY_POSIX \
+ | SLBT_PRETTY_HEXDATA)
+
+static int slbt_au_output_arname_impl(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_archive_ctx * actx,
+ const struct slbt_fd_ctx * fdctx,
+ const char * fmt)
+{
+ const char * path;
+ const char mema[] = "<memory_object>";
+
+ path = actx->path && *actx->path ? *actx->path : mema;
+
+ if (slbt_dprintf(fdctx->fdout,fmt,path) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+static int slbt_au_output_arname_posix(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_archive_ctx * actx,
+ const struct slbt_fd_ctx * fdctx)
+{
+ if (slbt_au_output_arname_impl(
+ dctx,actx,fdctx,
+ "%s:\n") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
+static int slbt_au_output_arname_yaml(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_archive_ctx * actx,
+ const struct slbt_fd_ctx * fdctx)
+{
+ if (slbt_au_output_arname_impl(
+ dctx,actx,fdctx,
+ "Archive:\n"
+ " - Meta:\n"
+ " - [ name: %s ]\n\n") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
+int slbt_au_output_arname(const struct slbt_archive_ctx * actx)
+{
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_fd_ctx fdctx;
+
+ dctx = (slbt_get_archive_ictx(actx))->dctx;
+
+ if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) {
+ case SLBT_PRETTY_YAML:
+ return slbt_au_output_arname_yaml(
+ dctx,actx,&fdctx);
+
+ case SLBT_PRETTY_POSIX:
+ return slbt_au_output_arname_posix(
+ dctx,actx,&fdctx);
+
+ default:
+ return slbt_au_output_arname_yaml(
+ dctx,actx,&fdctx);
+ }
+}
diff --git a/src/arbits/output/slbt_au_output_dlsyms.c b/src/arbits/output/slbt_au_output_dlsyms.c
new file mode 100644
index 0000000..512f60f
--- /dev/null
+++ b/src/arbits/output/slbt_au_output_dlsyms.c
@@ -0,0 +1,12 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+
+int slbt_au_output_dlsyms(struct slbt_archive_ctx ** arctxv, const char * dlunit)
+{
+ return slbt_ar_create_dlsyms(arctxv,dlunit,0,0);
+}
diff --git a/src/arbits/output/slbt_au_output_mapfile.c b/src/arbits/output/slbt_au_output_mapfile.c
new file mode 100644
index 0000000..fb470df
--- /dev/null
+++ b/src/arbits/output/slbt_au_output_mapfile.c
@@ -0,0 +1,12 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+
+int slbt_au_output_mapfile(const struct slbt_archive_meta * meta)
+{
+ return slbt_ar_create_mapfile(meta,0,0);
+}
diff --git a/src/arbits/output/slbt_au_output_members.c b/src/arbits/output/slbt_au_output_members.c
new file mode 100644
index 0000000..88937b0
--- /dev/null
+++ b/src/arbits/output/slbt_au_output_members.c
@@ -0,0 +1,278 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <locale.h>
+#include <inttypes.h>
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_ar_impl.h"
+
+#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \
+ | SLBT_PRETTY_POSIX \
+ | SLBT_PRETTY_HEXDATA)
+
+#define PPRIU64 "%"PRIu64
+
+const char slbt_ar_perm_strs[8][4] = {
+ {'-','-','-','\0'},
+ {'-','-','x','\0'},
+ {'-','w','-','\0'},
+ {'-','w','x','\0'},
+ {'r','-','-','\0'},
+ {'r','-','x','\0'},
+ {'r','w','-','\0'},
+ {'r','w','x','\0'}
+};
+
+static unsigned slbt_au_output_decimal_len_from_val(size_t val, unsigned min)
+{
+ unsigned ret;
+
+ for (ret=0; val; ret++)
+ val /= 10;
+
+ return (ret > min) ? ret : min;
+}
+
+static int slbt_au_output_one_member_posix(
+ int fdout,
+ struct ar_meta_member_info * memberp)
+{
+ return slbt_dprintf(
+ fdout,"%s\n",
+ memberp->ar_file_header.ar_member_name);
+}
+
+static int slbt_au_output_one_member_posix_verbose(
+ int fdout,
+ struct ar_meta_member_info * memberp,
+ const char * fmtstr,
+ locale_t arlocale)
+{
+ unsigned ownerbits;
+ unsigned groupbits;
+ unsigned worldbits;
+ time_t artimeval;
+ struct tm artimeloc;
+ char artimestr[64] = {0};
+
+ ownerbits = (memberp->ar_file_header.ar_file_mode & 0700) >> 6;
+ groupbits = (memberp->ar_file_header.ar_file_mode & 0070) >> 3;
+ worldbits = (memberp->ar_file_header.ar_file_mode & 0007);
+ artimeval = memberp->ar_file_header.ar_time_date_stamp;
+
+ if (localtime_r(&artimeval,&artimeloc))
+ strftime_l(
+ artimestr,sizeof(artimestr),
+ "%b %e %H:%M %Y",&artimeloc,
+ arlocale);
+
+ return slbt_dprintf(
+ fdout,fmtstr,
+ slbt_ar_perm_strs[ownerbits],
+ slbt_ar_perm_strs[groupbits],
+ slbt_ar_perm_strs[worldbits],
+ memberp->ar_file_header.ar_uid,
+ memberp->ar_file_header.ar_gid,
+ memberp->ar_object_size,
+ artimestr,
+ memberp->ar_file_header.ar_member_name);
+}
+
+static int slbt_au_output_members_posix(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_archive_meta * meta,
+ const struct slbt_fd_ctx * fdctx)
+{
+ struct ar_meta_member_info ** memberp;
+ int fdout;
+ size_t testval;
+ size_t sizelen;
+ size_t uidlen;
+ size_t gidlen;
+ locale_t arloc;
+ char fmtstr[64];
+
+ fdout = fdctx->fdout;
+ arloc = 0;
+
+ if (dctx->cctx->fmtflags & SLBT_PRETTY_VERBOSE) {
+ for (sizelen=0,memberp=meta->a_memberv; *memberp; memberp++)
+ if ((testval = memberp[0]->ar_object_size) > sizelen)
+ sizelen = testval;
+
+ for (uidlen=0,memberp=meta->a_memberv; *memberp; memberp++)
+ if ((testval = memberp[0]->ar_file_header.ar_uid) > uidlen)
+ uidlen = testval;
+
+ for (gidlen=0,memberp=meta->a_memberv; *memberp; memberp++)
+ if ((testval = memberp[0]->ar_file_header.ar_gid) > gidlen)
+ gidlen = testval;
+
+ sizelen = slbt_au_output_decimal_len_from_val(sizelen,6);
+ uidlen = slbt_au_output_decimal_len_from_val(uidlen,1);
+ gidlen = slbt_au_output_decimal_len_from_val(gidlen,1);
+ arloc = newlocale(LC_ALL,setlocale(LC_ALL,0),0);
+
+ sprintf(
+ fmtstr,
+ "%%s%%s%%s "
+ "%%" PPRIU64 "u"
+ "/%%-" PPRIU64 "u "
+ "%%" PPRIU64 "u "
+ "%%s "
+ "%%s\n",
+ uidlen,
+ gidlen,
+ sizelen);
+ }
+
+ for (memberp=meta->a_memberv; *memberp; memberp++) {
+ switch ((*memberp)->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ case AR_MEMBER_ATTR_LINKINFO:
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ if (arloc) {
+ if (slbt_au_output_one_member_posix_verbose(
+ fdout,*memberp,fmtstr,arloc) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else {
+ if (slbt_au_output_one_member_posix(
+ fdout,*memberp) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+ }
+
+ if (arloc)
+ freelocale(arloc);
+
+ return 0;
+}
+
+static int slbt_au_output_one_member_yaml(
+ int fdout,
+ struct ar_meta_member_info * memberp)
+{
+ return slbt_dprintf(
+ fdout,
+ " - [ member: %s ]\n",
+ memberp->ar_file_header.ar_member_name);
+}
+
+static int slbt_au_output_one_member_yaml_verbose(
+ int fdout,
+ struct ar_meta_member_info * memberp,
+ locale_t arlocale)
+{
+ time_t artimeval;
+ struct tm artimeloc;
+ char artimestr[64] = {0};
+
+ artimeval = memberp->ar_file_header.ar_time_date_stamp;
+
+ if (localtime_r(&artimeval,&artimeloc))
+ strftime_l(
+ artimestr,sizeof(artimestr),
+ "%Y/%m/%d @ %H:%M",&artimeloc,
+ arlocale);
+
+ return slbt_dprintf(
+ fdout,
+ " - Member:\n"
+ " - [ name: " "%s" " ]\n"
+ " - [ timestamp: " "%s" " ]\n"
+ " - [ filesize: " PPRIU64 " ]\n"
+ " - [ uid: " "%d" " ]\n"
+ " - [ gid: " "%d" " ]\n"
+ " - [ mode: " "%d" " ]\n\n",
+ memberp->ar_file_header.ar_member_name,
+ artimestr,
+ memberp->ar_object_size,
+ memberp->ar_file_header.ar_uid,
+ memberp->ar_file_header.ar_gid,
+ memberp->ar_file_header.ar_file_mode);
+}
+
+static int slbt_au_output_members_yaml(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_archive_meta * meta,
+ const struct slbt_fd_ctx * fdctx)
+{
+ struct ar_meta_member_info ** memberp;
+ int fdout;
+ locale_t arloc;
+
+ fdout = fdctx->fdout;
+ arloc = 0;
+
+ if (dctx->cctx->fmtflags & SLBT_PRETTY_VERBOSE) {
+ arloc = newlocale(LC_ALL,setlocale(LC_ALL,0),0);
+ }
+
+ if (slbt_dprintf(fdctx->fdout," - Members:\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ for (memberp=meta->a_memberv; *memberp; memberp++) {
+ switch ((*memberp)->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ case AR_MEMBER_ATTR_LINKINFO:
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ if (arloc) {
+ if (slbt_au_output_one_member_yaml_verbose(
+ fdout,*memberp,arloc) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else {
+ if (slbt_au_output_one_member_yaml(
+ fdout,*memberp) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+ }
+
+ if (arloc)
+ freelocale(arloc);
+
+ return 0;
+}
+
+int slbt_au_output_members(const struct slbt_archive_meta * meta)
+{
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_fd_ctx fdctx;
+
+ dctx = (slbt_archive_meta_ictx(meta))->dctx;
+
+ if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (!meta->a_memberv)
+ return 0;
+
+ switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) {
+ case SLBT_PRETTY_YAML:
+ return slbt_au_output_members_yaml(
+ dctx,meta,&fdctx);
+
+ case SLBT_PRETTY_POSIX:
+ return slbt_au_output_members_posix(
+ dctx,meta,&fdctx);
+
+ default:
+ return slbt_au_output_members_yaml(
+ dctx,meta,&fdctx);
+ }
+}
diff --git a/src/arbits/output/slbt_au_output_symbols.c b/src/arbits/output/slbt_au_output_symbols.c
new file mode 100644
index 0000000..950cde8
--- /dev/null
+++ b/src/arbits/output/slbt_au_output_symbols.c
@@ -0,0 +1,201 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <locale.h>
+#include <regex.h>
+#include <inttypes.h>
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_pecoff_impl.h"
+#include "slibtool_tmpfile_impl.h"
+#include "slibtool_ar_impl.h"
+
+#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \
+ | SLBT_PRETTY_POSIX \
+ | SLBT_PRETTY_HEXDATA)
+
+static int slbt_au_output_symbols_posix(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx,
+ int fdout)
+{
+ bool fsort;
+ bool fcoff;
+ const char * dot;
+ const char * mark;
+ const char * regex;
+ const char ** symv;
+ const char ** symstrv;
+ regex_t regctx;
+ regmatch_t pmatch[2] = {{0,0},{0,0}};
+ char strbuf[4096];
+
+ fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT);
+ fcoff = (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ if (fsort && !mctx->mapstrv)
+ if (slbt_update_mapstrv(dctx,mctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if ((regex = dctx->cctx->regex))
+ if (regcomp(&regctx,regex,REG_EXTENDED|REG_NEWLINE))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ symstrv = fsort ? mctx->mapstrv : mctx->symstrv;
+
+ for (symv=symstrv; *symv; symv++) {
+ if (!fcoff || slbt_is_strong_coff_symbol(*symv)) {
+ if (!regex || !regexec(&regctx,*symv,1,pmatch,0)) {
+ if (slbt_dprintf(fdout,"%s\n",*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* coff weak symbols: expsym = .weak.alias.strong */
+ } else if (fcoff && !strncmp(*symv,".weak.",6)) {
+ mark = &(*symv)[6];
+ dot = strchr(mark,'.');
+
+ strncpy(strbuf,mark,dot-mark);
+ strbuf[dot-mark] = '\0';
+
+ if (!regex || !regexec(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout,"%s\n",strbuf) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ return 0;
+}
+
+static int slbt_au_output_one_symbol_yaml(
+ int fdout,
+ struct slbt_archive_meta_impl * mctx,
+ const char * symname)
+{
+ struct ar_meta_symbol_info ** syminfv;
+
+ for (syminfv=mctx->syminfv; *syminfv; syminfv++)
+ if (!strcmp(syminfv[0]->ar_symbol_name,symname))
+ return slbt_dprintf(
+ fdout,
+ " - Symbol:\n"
+ " - [ object_name: " "%s" " ]\n"
+ " - [ symbol_name: " "%s" " ]\n"
+ " - [ symbol_type: " "%s" " ]\n\n",
+ syminfv[0]->ar_object_name,
+ symname,
+ syminfv[0]->ar_symbol_type);
+
+ return 0;
+}
+
+static int slbt_au_output_symbols_yaml(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx,
+ int fdout)
+{
+ int fdtmp;
+ bool fsort;
+ bool fcoff;
+ const char * dot;
+ const char * mark;
+ const char * regex;
+ const char ** symv;
+ const char ** symstrv;
+ regex_t regctx;
+ regmatch_t pmatch[2] = {{0,0},{0,0}};
+ char strbuf[4096];
+
+ fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT);
+ fcoff = (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ if ((fdtmp = slbt_tmpfile()) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (fsort && !mctx->mapstrv)
+ if (slbt_update_mapstrv(dctx,mctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (slbt_ar_update_syminfo_ex(mctx->actx,fdtmp) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if ((regex = dctx->cctx->regex))
+ if (regcomp(&regctx,regex,REG_EXTENDED|REG_NEWLINE))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ symstrv = fsort ? mctx->mapstrv : mctx->symstrv;
+
+ if (slbt_dprintf(fdout," - Symbols:\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ for (symv=symstrv; *symv; symv++) {
+ if (!fcoff || slbt_is_strong_coff_symbol(*symv)) {
+ if (!regex || !regexec(&regctx,*symv,1,pmatch,0)) {
+ if (slbt_au_output_one_symbol_yaml(
+ fdout,mctx,*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* coff weak symbols: expsym = .weak.alias.strong */
+ } else if (fcoff && !strncmp(*symv,".weak.",6)) {
+ mark = &(*symv)[6];
+ dot = strchr(mark,'.');
+
+ strncpy(strbuf,mark,dot-mark);
+ strbuf[dot-mark] = '\0';
+
+ if (!regex || !regexec(&regctx,strbuf,1,pmatch,0))
+ if (slbt_au_output_one_symbol_yaml(
+ fdout,mctx,strbuf) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ return 0;
+}
+
+int slbt_au_output_symbols(const struct slbt_archive_meta * meta)
+{
+ struct slbt_archive_meta_impl * mctx;
+ const struct slbt_driver_ctx * dctx;
+ int fdout;
+
+ mctx = slbt_archive_meta_ictx(meta);
+ dctx = (slbt_archive_meta_ictx(meta))->dctx;
+
+ fdout = slbt_driver_fdout(dctx);
+
+ if (!meta->a_memberv)
+ return 0;
+
+ switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) {
+ case SLBT_PRETTY_YAML:
+ return slbt_au_output_symbols_yaml(
+ dctx,mctx,fdout);
+
+ case SLBT_PRETTY_POSIX:
+ return slbt_au_output_symbols_posix(
+ dctx,mctx,fdout);
+
+ default:
+ return slbt_au_output_symbols_yaml(
+ dctx,mctx,fdout);
+ }
+}
diff --git a/src/arbits/slbt_archive_ctx.c b/src/arbits/slbt_archive_ctx.c
new file mode 100644
index 0000000..575374c
--- /dev/null
+++ b/src/arbits/slbt_archive_ctx.c
@@ -0,0 +1,117 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_ar_impl.h"
+
+static int slbt_map_raw_archive(
+ const struct slbt_driver_ctx * dctx,
+ int fd,
+ const char * path,
+ int prot,
+ struct slbt_raw_archive * map)
+{
+ struct slbt_input mapinfo = {0,0};
+
+ if (slbt_fs_map_input(dctx,fd,path,prot,&mapinfo) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (mapinfo.size == 0)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_EMPTY_FILE);
+
+ map->map_addr = mapinfo.addr;
+ map->map_size = mapinfo.size;
+
+ return 0;
+}
+
+static int slbt_unmap_raw_archive(struct slbt_raw_archive * map)
+{
+ struct slbt_input mapinfo;
+
+ mapinfo.addr = map->map_addr;
+ mapinfo.size = map->map_size;
+
+ return slbt_fs_unmap_input(&mapinfo);
+}
+
+static int slbt_ar_free_archive_ctx_impl(struct slbt_archive_ctx_impl * ctx, int ret)
+{
+ if (ctx) {
+ slbt_ar_free_archive_meta(ctx->meta);
+ slbt_unmap_raw_archive(&ctx->map);
+ free(ctx->pathbuf);
+ free(ctx);
+ }
+
+ return ret;
+}
+
+int slbt_ar_get_archive_ctx(
+ const struct slbt_driver_ctx * dctx,
+ const char * path,
+ struct slbt_archive_ctx ** pctx)
+{
+ struct slbt_archive_ctx_impl * ctx;
+ struct slbt_archive_meta_impl * mctx;
+ int prot;
+
+ if (!(ctx = calloc(1,sizeof(*ctx))))
+ return SLBT_BUFFER_ERROR(dctx);
+
+ slbt_driver_set_arctx(
+ dctx,0,path);
+
+ prot = (dctx->cctx->actflags & SLBT_ACTION_MAP_READWRITE)
+ ? PROT_READ | PROT_WRITE
+ : PROT_READ;
+
+ if (slbt_map_raw_archive(dctx,-1,path,prot,&ctx->map))
+ return slbt_ar_free_archive_ctx_impl(ctx,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (slbt_ar_get_archive_meta(dctx,&ctx->map,&ctx->meta))
+ return slbt_ar_free_archive_ctx_impl(ctx,
+ SLBT_NESTED_ERROR(dctx));
+
+ if (!(ctx->pathbuf = strdup(path)))
+ return slbt_ar_free_archive_ctx_impl(ctx,
+ SLBT_NESTED_ERROR(dctx));
+
+ mctx = slbt_archive_meta_ictx(ctx->meta);
+
+ ctx->dctx = dctx;
+ ctx->path = ctx->pathbuf;
+ ctx->actx.path = &ctx->path;
+ ctx->actx.map = &ctx->map;
+ ctx->actx.meta = ctx->meta;
+ mctx->actx = &ctx->actx;
+
+ *pctx = &ctx->actx;
+ return 0;
+}
+
+void slbt_ar_free_archive_ctx(struct slbt_archive_ctx * ctx)
+{
+ struct slbt_archive_ctx_impl * ictx;
+ uintptr_t addr;
+
+ if (ctx) {
+ addr = (uintptr_t)ctx - offsetof(struct slbt_archive_ctx_impl,actx);
+ ictx = (struct slbt_archive_ctx_impl *)addr;
+ slbt_ar_free_archive_ctx_impl(ictx,0);
+ }
+}
diff --git a/src/arbits/slbt_archive_dlsyms.c b/src/arbits/slbt_archive_dlsyms.c
new file mode 100644
index 0000000..ed07602
--- /dev/null
+++ b/src/arbits/slbt_archive_dlsyms.c
@@ -0,0 +1,458 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <slibtool/slibtool.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+static const char * slbt_strong_symname(
+ const char * symname,
+ bool fcoff,
+ char (*strbuf)[4096])
+{
+ const char * dot;
+ const char * mark;
+ char * sym;
+
+ if (fcoff) {
+ if (!strncmp(symname,"__imp_",6))
+ return 0;
+
+ if (strncmp(symname,".weak.",6))
+ return symname;
+
+ sym = *strbuf;
+ mark = &symname[6];
+ dot = strchr(mark,'.');
+
+ strncpy(sym,mark,dot-mark);
+ sym[dot-mark] = '\0';
+
+ return sym;
+ }
+
+ return symname;
+}
+
+
+static int slbt_ar_dlsyms_define_by_type(
+ int fdout,
+ const char * arname,
+ struct slbt_archive_meta_impl * mctx,
+ const char * desc,
+ const char stype)
+{
+ uint64_t idx;
+ uint64_t nsyms;
+ bool fcoff;
+ const char * symname;
+ char strbuf[4096];
+
+ for (idx=0,nsyms=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (mctx->syminfv[idx]->ar_symbol_type[0] == stype)
+ nsyms++;
+
+ if (nsyms == 0)
+ return 0;
+
+ fcoff = slbt_host_objfmt_is_coff(mctx->dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ if (slbt_dprintf(fdout,"/* %s (%s) */\n",desc,arname) < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (mctx->syminfv[idx]->ar_symbol_type[0] == stype)
+ if ((symname = slbt_strong_symname(
+ mctx->syminfv[idx]->ar_symbol_name,
+ fcoff,&strbuf)))
+ if (slbt_dprintf(fdout,
+ (stype == 'T')
+ ? "extern int %s();\n"
+ : "extern char %s[];\n",
+ symname) < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ if (slbt_dprintf(fdout,"\n") < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ return 0;
+}
+
+static int slbt_ar_dlsyms_get_max_len_by_type(
+ int mlen,
+ struct slbt_archive_meta_impl * mctx,
+ const char stype)
+{
+ int len;
+ uint64_t idx;
+ bool fcoff;
+ const char * symname;
+ char strbuf[4096];
+
+ fcoff = slbt_host_objfmt_is_coff(mctx->dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (mctx->syminfv[idx]->ar_symbol_type[0] == stype)
+ if ((symname = slbt_strong_symname(
+ mctx->syminfv[idx]->ar_symbol_name,
+ fcoff,&strbuf)))
+ if ((len = strlen(symname)) > mlen)
+ mlen = len;
+
+ return mlen;
+}
+
+static int slbt_ar_dlsyms_add_by_type(
+ int fdout,
+ struct slbt_archive_meta_impl * mctx,
+ const char * fmt,
+ const char stype,
+ char (*namebuf)[4096])
+{
+ uint64_t idx;
+ uint64_t nsyms;
+ bool fcoff;
+ const char * symname;
+ char strbuf[4096];
+
+ nsyms = 0;
+ symname = *namebuf;
+
+ fcoff = slbt_host_objfmt_is_coff(mctx->dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (mctx->syminfv[idx]->ar_symbol_type[0] == stype)
+ nsyms++;
+
+ if (nsyms == 0)
+ return 0;
+
+ if (slbt_dprintf(fdout,"\n") < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++) {
+ if (mctx->syminfv[idx]->ar_symbol_type[0] == stype) {
+ symname = slbt_strong_symname(
+ mctx->syminfv[idx]->ar_symbol_name,
+ fcoff,&strbuf);
+
+ if (symname) {
+ if (slbt_snprintf(*namebuf,sizeof(*namebuf),
+ "%s\",",symname) < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ if (slbt_dprintf(fdout,fmt,
+ *namebuf,
+ (stype == 'T') ? "&" : "",
+ symname) < 0)
+ return SLBT_NESTED_ERROR(mctx->dctx);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int slbt_ar_output_dlsyms_impl(
+ int fdout,
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_ctx ** arctxv,
+ const char * dsounit)
+{
+ int ret;
+ int idx;
+ unsigned len;
+ unsigned cmp;
+ const char * arname;
+ const char * soname;
+ struct slbt_archive_ctx * actx;
+ struct slbt_archive_ctx ** parctx;
+ struct slbt_archive_ctx_impl * ictx;
+ struct slbt_archive_meta_impl * mctx;
+ const struct slbt_source_version * verinfo;
+ char dlsymfmt[32];
+ char cline[6][73];
+ char symname[4096];
+
+ /* init */
+ actx = arctxv[0];
+ verinfo = slbt_api_source_version();
+
+ /* preamble */
+ memset(cline[0],'*',72);
+ memset(cline[1],' ',72);
+ memset(cline[2],' ',72);
+ memset(cline[3],' ',72);
+ memset(cline[4],'*',72);
+
+ memset(cline[5],0,72);
+ cline[5][0] = '\n';
+
+ len = snprintf(&cline[1][3],69,
+ "backward-compatible dlsym table");
+
+ cline[1][3+len] = ' ';
+
+ len = snprintf(&cline[2][3],69,
+ "Generated by %s (slibtool %d.%d.%d)",
+ dctx->program,
+ verinfo->major,verinfo->minor,verinfo->revision);
+
+ cline[2][3+len] = ' ';
+
+ len = snprintf(&cline[3][3],69,
+ "[commit reference: %s]",
+ verinfo->commit);
+
+ cline[3][3+len] = ' ';
+
+ for (idx=0; idx<5; idx++) {
+ cline[idx][0] = '/';
+ cline[idx][1] = '*';
+
+ cline[idx][70] = '*';
+ cline[idx][71] = '/';
+
+ cline[idx][72] = '\n';
+ }
+
+ if (slbt_dprintf(fdout,"%s",&cline[0]) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_dprintf(fdout,
+ "#ifdef __cplusplus\n"
+ "extern \"C\" {\n"
+ "#endif\n\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* declarations */
+ for (parctx=arctxv; *parctx; parctx++) {
+ actx = *parctx;
+ ictx = slbt_get_archive_ictx(actx);
+ mctx = slbt_archive_meta_ictx(ictx->meta);
+
+ if ((arname = strrchr(*actx->path,'/')))
+ arname++;
+
+ if (!arname)
+ arname = *actx->path;
+
+ ret = slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Absolute Values", 'A');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: BSS Section", 'B');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Common Section", 'C');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Initialized Data", 'D');
+
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Small Globals", 'G');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Indirect References", 'I');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Read-Only Section", 'R');
+
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Small Objects", 'S');
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Data Symbols: Weak Symbols", 'W');
+
+ ret |= slbt_ar_dlsyms_define_by_type(fdout,arname,mctx,"Text Section: Public Interfaces", 'T');
+
+ if (ret < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ }
+
+ /* vtable struct definition */
+ if (slbt_dprintf(fdout,
+ "/* name-address Public ABI struct definition */\n"
+ "struct lt_dlsym_symdef {\n"
+ "\tconst char * dlsym_name;\n"
+ "\tvoid * dlsym_addr;\n"
+ "};\n\n") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ soname = (strcmp(dsounit,"@PROGRAM@")) ? dsounit : "_PROGRAM_";
+
+ if (slbt_dprintf(fdout,
+ "/* dlsym vtable */\n"
+ "extern const struct lt_dlsym_symdef "
+ "lt_%s_LTX_preloaded_symbols[];\n\n"
+ "const struct lt_dlsym_symdef "
+ "lt_%s_LTX_preloaded_symbols[] = {\n",
+ soname,soname) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* align dlsym_name and dlsym_addr columsn (because we can) */
+ for (parctx=arctxv,len=0; *parctx; parctx++) {
+ actx = *parctx;
+ ictx = slbt_get_archive_ictx(actx);
+ mctx = slbt_archive_meta_ictx(ictx->meta);
+
+ if ((arname = strrchr(*actx->path,'/')))
+ arname++;
+
+ if (!arname)
+ arname = *actx->path;
+
+ if (len < (cmp = strlen(arname)))
+ len = cmp;
+
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'A');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'B');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'C');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'D');
+
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'G');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'I');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'R');
+
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'S');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'T');
+ len = slbt_ar_dlsyms_get_max_len_by_type(len,mctx,'W');
+ }
+
+ /* quote, comma */
+ len += 2;
+
+ if (len >= sizeof(symname))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ /* aligned print format */
+ snprintf(dlsymfmt,sizeof(dlsymfmt),"\t{\"%%-%ds %%s%%s},\n",len);
+
+ /* dso unit */
+ if (slbt_snprintf(symname,sizeof(symname),"%s\",",dsounit) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (slbt_dprintf(fdout,dlsymfmt,symname,"","0") < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* (-dlopen force) */
+ if (!arctxv[0]->meta->a_memberv)
+ if (!strcmp(*arctxv[0]->path,"@PROGRAM@"))
+ arctxv++;
+
+ /* at long last */
+ for (parctx=arctxv; *parctx; parctx++) {
+ actx = *parctx;
+ ictx = slbt_get_archive_ictx(actx);
+ mctx = slbt_archive_meta_ictx(ictx->meta);
+
+ if ((arname = strrchr(*actx->path,'/')))
+ arname++;
+
+ if (!arname)
+ arname = *actx->path;
+
+ if (slbt_dprintf(fdout,"\n") < 0)
+ return SLBT_NESTED_ERROR(mctx->dctx);
+
+ if (slbt_snprintf(symname,sizeof(symname),"%s\",",arname) < 0)
+ return SLBT_SYSTEM_ERROR(mctx->dctx,0);
+
+ if (slbt_dprintf(fdout,dlsymfmt,symname,"","0") < 0)
+ return SLBT_NESTED_ERROR(mctx->dctx);
+
+ ret = slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'A',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'B',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'C',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'D',&symname);
+
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'G',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'I',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'R',&symname);
+
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'S',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'S',&symname);
+ ret |= slbt_ar_dlsyms_add_by_type(fdout,mctx,dlsymfmt,'T',&symname);
+
+ if (ret < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* null-terminate the vtable */
+ if (slbt_dprintf(fdout,"\n\t{%d,%*c%d}\n",0,len,' ',0) < 0)
+ return SLBT_NESTED_ERROR(mctx->dctx);
+
+ /* close vtable, wrap translation unit */
+ if (slbt_dprintf(fdout,
+ "};\n\n"
+ "#ifdef __cplusplus\n"
+ "}\n"
+ "#endif\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+
+static int slbt_ar_create_dlsyms_impl(
+ struct slbt_archive_ctx ** arctxv,
+ const char * dlunit,
+ const char * path,
+ mode_t mode)
+{
+ int ret;
+ struct slbt_archive_ctx ** actx;
+ struct slbt_exec_ctx * ectx;
+ struct slbt_archive_meta_impl * mctx;
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_fd_ctx fdctx;
+ int fdout;
+
+ mctx = slbt_archive_meta_ictx(arctxv[0]->meta);
+ dctx = mctx->dctx;
+ ectx = 0;
+
+ if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (path) {
+ if ((fdout = openat(
+ fdctx.fdcwd,path,
+ O_WRONLY|O_CREAT|O_TRUNC,
+ mode)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,path);
+ } else {
+ fdout = fdctx.fdout;
+ }
+
+ for (actx=arctxv; *actx; actx++) {
+ mctx = slbt_archive_meta_ictx((*actx)->meta);
+
+ if (!mctx->syminfo && !ectx)
+ if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (!mctx->syminfo)
+ if (slbt_ar_update_syminfo(*actx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ if (ectx)
+ slbt_ectx_free_exec_ctx(ectx);
+
+ ret = slbt_ar_output_dlsyms_impl(
+ fdout,dctx,arctxv,dlunit);
+
+ if (path) {
+ close(fdout);
+ }
+
+ return ret;
+}
+
+
+int slbt_ar_create_dlsyms(
+ struct slbt_archive_ctx ** arctxv,
+ const char * dlunit,
+ const char * path,
+ mode_t mode)
+{
+ return slbt_ar_create_dlsyms_impl(arctxv,dlunit,path,mode);
+}
diff --git a/src/arbits/slbt_archive_mapfile.c b/src/arbits/slbt_archive_mapfile.c
new file mode 100644
index 0000000..18f94dc
--- /dev/null
+++ b/src/arbits/slbt_archive_mapfile.c
@@ -0,0 +1,162 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <locale.h>
+#include <regex.h>
+#include <inttypes.h>
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_pecoff_impl.h"
+#include "slibtool_ar_impl.h"
+
+/********************************************************/
+/* Generate a symbol mapfile (aka version script) that */
+/* could be passed to the host linker. */
+/* */
+/* Since the symbol list is directly derived from the */
+/* archive's armap member, prepending symbol names with */
+/* an underscore (where relevant) is not necessary. */
+/********************************************************/
+
+static int slbt_ar_output_mapfile_impl(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx,
+ int fdout)
+{
+ bool fsort;
+ bool fcoff;
+ bool fmach;
+ const char * dot;
+ const char * mark;
+ const char * regex;
+ const char ** symv;
+ const char ** symstrv;
+ regex_t regctx;
+ regmatch_t pmatch[2] = {{0,0},{0,0}};
+ char strbuf[4096];
+
+ fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT);
+
+ fmach = slbt_host_objfmt_is_macho(dctx);
+ fmach |= (mctx->ofmtattr & AR_OBJECT_ATTR_MACHO);
+
+ fcoff = slbt_host_objfmt_is_coff(dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ if (fcoff) {
+ if (slbt_dprintf(fdout,"EXPORTS\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else if (fmach) {
+ if (slbt_dprintf(fdout,"# export_list, armap underscores\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else {
+ if (slbt_dprintf(fdout,"{\n" "\t" "global:\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ if (fsort && !mctx->mapstrv)
+ if (slbt_update_mapstrv(dctx,mctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if ((regex = dctx->cctx->regex))
+ if (regcomp(&regctx,regex,REG_EXTENDED|REG_NEWLINE))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ symstrv = fsort ? mctx->mapstrv : mctx->symstrv;
+
+ for (symv=symstrv; *symv; symv++) {
+ if (!fcoff || slbt_is_strong_coff_symbol(*symv)) {
+ if (!regex || !regexec(&regctx,*symv,1,pmatch,0)) {
+ if (fcoff) {
+ if (slbt_dprintf(fdout," %s\n",*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else if (fmach) {
+ if (slbt_dprintf(fdout,"%s\n",*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ } else {
+ if (slbt_dprintf(fdout,"\t\t%s;\n",*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+ /* coff weak symbols: expsym = .weak.alias.strong */
+ } else if (fcoff && !strncmp(*symv,".weak.",6)) {
+ mark = &(*symv)[6];
+ dot = strchr(mark,'.');
+
+ strncpy(strbuf,mark,dot-mark);
+ strbuf[dot-mark] = '\0';
+
+ if (!regex || !regexec(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ if (!fcoff && !fmach)
+ if (slbt_dprintf(fdout,"\n\t" "local:\n" "\t\t*;\n" "};\n") < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+
+static int slbt_ar_create_mapfile_impl(
+ const struct slbt_archive_meta * meta,
+ const char * path,
+ mode_t mode)
+{
+ int ret;
+ struct slbt_archive_meta_impl * mctx;
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_fd_ctx fdctx;
+ int fdout;
+
+ mctx = slbt_archive_meta_ictx(meta);
+ dctx = (slbt_archive_meta_ictx(meta))->dctx;
+
+ if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (!meta->a_memberv)
+ return 0;
+
+ if (path) {
+ if ((fdout = openat(
+ fdctx.fdcwd,path,
+ O_WRONLY|O_CREAT|O_TRUNC,
+ mode)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,path);
+ } else {
+ fdout = fdctx.fdout;
+ }
+
+ ret = slbt_ar_output_mapfile_impl(
+ dctx,mctx,fdout);
+
+ if (path) {
+ close(fdout);
+ }
+
+ return ret;
+}
+
+
+int slbt_ar_create_mapfile(
+ const struct slbt_archive_meta * meta,
+ const char * path,
+ mode_t mode)
+{
+ return slbt_ar_create_mapfile_impl(meta,path,mode);
+}
diff --git a/src/arbits/slbt_archive_mapstrv.c b/src/arbits/slbt_archive_mapstrv.c
new file mode 100644
index 0000000..e97db76
--- /dev/null
+++ b/src/arbits/slbt_archive_mapstrv.c
@@ -0,0 +1,47 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <slibtool/slibtool.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+#include "slibtool_ar_impl.h"
+#include "slibtool_coff_impl.h"
+
+static int slbt_qsort_strcmp(const void * a, const void * b)
+{
+ return strcmp(*(const char **)a,*(const char **)b);
+}
+
+slbt_hidden int slbt_update_mapstrv(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx)
+{
+ bool fcoff;
+ size_t nsyms;
+ const char ** symv;
+ const char ** mapstrv;
+
+ fcoff = slbt_host_objfmt_is_coff(dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ for (nsyms=0,symv=mctx->symstrv; *symv; symv++)
+ nsyms++;
+
+ if (!(mapstrv = calloc(nsyms+1,sizeof(const char *))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ for (nsyms=0,symv=mctx->symstrv; *symv; symv++)
+ mapstrv[nsyms++] = *symv;
+
+ qsort(mapstrv,nsyms,sizeof(const char *),fcoff ? slbt_coff_qsort_strcmp : slbt_qsort_strcmp);
+
+ mctx->mapstrv = mapstrv;
+
+ return 0;
+}
diff --git a/src/arbits/slbt_archive_merge.c b/src/arbits/slbt_archive_merge.c
new file mode 100644
index 0000000..5f29235
--- /dev/null
+++ b/src/arbits/slbt_archive_merge.c
@@ -0,0 +1,734 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+/* anonymous fun */
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* time stamp format specifier */
+#define PPRII64 "%"PRIi64
+
+/* file size format specifier */
+#define PPRIU64 "%"PRIu64
+
+/* dlopen self/force */
+static const char slbt_ar_self_dlunit[] = "@PROGRAM@";
+
+struct armap_buffer_32 {
+ uint32_t moffset;
+ const char * symname;
+ uint32_t baseidx;
+};
+
+struct armap_buffer_64 {
+ uint64_t moffset;
+ const char * symname;
+ uint64_t baseidx;
+};
+
+static const char ar_signature[] = AR_SIGNATURE;
+
+static int slbt_create_anonymous_archive_ctx(
+ const struct slbt_driver_ctx * dctx,
+ size_t size,
+ struct slbt_archive_ctx ** pctx)
+{
+ struct slbt_archive_ctx_impl * ctx;
+
+ if (!(ctx = calloc(1,sizeof(*ctx))))
+ return SLBT_BUFFER_ERROR(dctx);
+
+ ctx->map.map_size = size;
+ ctx->map.map_addr = mmap(
+ 0,size,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1,0);
+
+ if (ctx->map.map_addr == MAP_FAILED) {
+ free(ctx);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ ctx->dctx = dctx;
+ ctx->actx.map = &ctx->map;
+
+ *pctx = &ctx->actx;
+
+ return 0;
+}
+
+static off_t slbt_armap_write_be_32(unsigned char * mark, uint32_t val)
+{
+ mark[0] = val >> 24;
+ mark[1] = val >> 16;
+ mark[2] = val >> 8;
+ mark[3] = val;
+
+ return sizeof(uint32_t);
+}
+
+static off_t slbt_armap_write_le_32(unsigned char * mark, uint32_t val)
+{
+ mark[0] = val;
+ mark[1] = val >> 8;
+ mark[2] = val >> 16;
+ mark[3] = val >> 24;
+
+ return sizeof(uint32_t);
+}
+
+static off_t slbt_armap_write_be_64(unsigned char * mark, uint64_t val)
+{
+ slbt_armap_write_be_32(&mark[0],val >> 32);
+ slbt_armap_write_be_32(&mark[4],val);
+
+ return sizeof(uint64_t);
+}
+
+static off_t slbt_armap_write_le_64(unsigned char * mark, uint64_t val)
+{
+ slbt_armap_write_be_32(&mark[0],val);
+ slbt_armap_write_be_32(&mark[4],val >> 32);
+
+ return sizeof(uint64_t);
+}
+
+
+static int slbt_ar_merge_archives_fail(
+ struct slbt_archive_ctx * arctx,
+ struct armap_buffer_32 * bsdmap32,
+ struct armap_buffer_64 * bsdmap64,
+ int ret)
+{
+ if (bsdmap32)
+ free(bsdmap32);
+
+ if (bsdmap64)
+ free(bsdmap64);
+
+ if (arctx)
+ slbt_ar_free_archive_ctx(arctx);
+
+ return ret;
+}
+
+
+int slbt_ar_merge_archives(
+ struct slbt_archive_ctx * const arctxv[],
+ struct slbt_archive_ctx ** arctxm)
+{
+ struct slbt_archive_ctx * const * arctxp;
+ struct slbt_archive_ctx * arctx;
+
+ const struct slbt_driver_ctx * dctx;
+ const struct slbt_archive_meta * meta;
+
+ struct ar_raw_file_header * arhdr;
+ struct ar_meta_member_info ** memberp;
+ struct ar_meta_member_info * meminfo;
+
+ struct ar_meta_member_info * armap;
+ struct ar_meta_member_info * arnames;
+
+ const struct ar_meta_armap_common_32 * armap32;
+ const struct ar_meta_armap_common_64 * armap64;
+ const struct ar_meta_armap_ref_32 * symref32;
+ const struct ar_meta_armap_ref_64 * symref64;
+
+ struct armap_buffer_32 * bsdmap32;
+ struct armap_buffer_64 * bsdmap64;
+ struct armap_buffer_32 * bsdsort32;
+ struct armap_buffer_64 * bsdsort64;
+
+ size_t nbytes;
+ ssize_t nwritten;
+
+ uint32_t mapattr;
+ uint64_t nmembers;
+ uint64_t nsymrefs;
+
+ uint64_t sarmap;
+ uint64_t sarname;
+ uint64_t sarchive;
+ uint64_t smembers;
+ uint64_t ssymrefs;
+ uint64_t ssymstrs;
+ uint64_t snamestrs;
+
+ int64_t omembers;
+ int64_t osymrefs;
+ int64_t onamestrs;
+ int64_t omemfixup;
+
+ char * base;
+ unsigned char * ubase;
+
+ char * ch;
+ unsigned char * uch;
+
+ char * namebase;
+ char * namestr;
+ char * strtbl;
+
+ uint64_t idx;
+ uint64_t mapidx;
+ uint64_t cmpidx;
+
+ off_t (*armap_write_uint32)(
+ unsigned char *,
+ uint32_t);
+
+ off_t (*armap_write_uint64)(
+ unsigned char *,
+ uint64_t);
+
+ /* init */
+ nmembers = nsymrefs = ssymstrs = mapattr = 0;
+ sarchive = smembers = ssymrefs = snamestrs = 0;
+ omembers = osymrefs = onamestrs = 0;
+
+ if (!arctxv || !arctxv[0])
+ return -1;
+
+ if (!(dctx = slbt_get_archive_ictx(arctxv[0])->dctx))
+ return -1;
+
+ /* determine armap type and size of archive elements */
+ for (armap=0,arnames=0,arctxp=arctxv; *arctxp; arctxp++) {
+ if (slbt_get_archive_ictx(*arctxp)->dctx != dctx)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_DRIVER_MISMATCH);
+
+ meta = (*arctxp)->meta;
+ armap32 = meta->a_armap_primary.ar_armap_common_32;
+ armap64 = meta->a_armap_primary.ar_armap_common_64;
+
+ for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ if (armap32) {
+ if (mapattr == 0) {
+ armap = meminfo;
+ mapattr = armap32->ar_armap_attr;
+ } else if (mapattr != armap32->ar_armap_attr) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ARMAP_MISMATCH);
+ }
+
+ nsymrefs += armap32->ar_num_of_symbols;
+ ssymstrs += armap32->ar_size_of_strs;
+
+ } else if (armap64) {
+ if (mapattr == 0) {
+ armap = meminfo;
+ mapattr = armap64->ar_armap_attr;
+ } else if (mapattr != armap64->ar_armap_attr) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ARMAP_MISMATCH);
+ }
+
+ nsymrefs += armap64->ar_num_of_symbols;
+ }
+
+ break;
+
+ case AR_MEMBER_ATTR_LINKINFO:
+ break;
+
+ case AR_MEMBER_ATTR_NAMESTRS:
+ snamestrs += meminfo->ar_object_size;
+
+ if (!arnames)
+ arnames = meminfo;
+
+ break;
+
+ default:
+ smembers += sizeof(struct ar_raw_file_header);
+ smembers += meminfo->ar_file_header.ar_file_size;
+ smembers += 1;
+ smembers |= 1;
+ smembers ^= 1;
+ nmembers++;
+
+ break;
+ }
+ }
+ }
+
+ /* armap size */
+ if (sarmap = 0, sarname = 0, (mapattr == 0)) {
+ (void)0;
+
+ } else if (mapattr & AR_ARMAP_ATTR_SYSV) {
+ if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
+ sarmap += sizeof(uint32_t);
+ sarmap += sizeof(uint32_t) * nsymrefs;
+ } else {
+ sarmap += sizeof(uint64_t);
+ sarmap += sizeof(uint64_t) * nsymrefs;
+ }
+
+ } else if (mapattr & AR_ARMAP_ATTR_BSD) {
+ if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
+ sarmap += 2 * sizeof(uint32_t);
+ sarmap += 2 * sizeof(uint32_t) * nsymrefs;
+ } else {
+ sarmap += 2 * sizeof(uint64_t);
+ sarmap += 2 * sizeof(uint64_t) * nsymrefs;
+ }
+
+ sarname += armap->ar_file_header.ar_file_size;
+ sarname -= armap->ar_object_size;
+ } else {
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);
+ }
+
+ ssymstrs += 1;
+ ssymstrs |= 1;
+ ssymstrs ^= 1;
+
+ /* (debugging) */
+ (void)nmembers;
+
+ /* long-names member alignment */
+ snamestrs += 1;
+ snamestrs |= 1;
+ snamestrs ^= 1;
+
+ /* archive size */
+ sarchive = sizeof(struct ar_raw_signature);
+ sarchive += armap ? sizeof(struct ar_raw_file_header) : 0;
+ sarchive += arnames ? sizeof(struct ar_raw_file_header) : 0;
+ sarchive += sarname;
+ sarchive += sarmap;
+ sarchive += ssymstrs;
+ sarchive += snamestrs;
+ sarchive += smembers;
+
+ /* offset from archive base to first public member */
+ omembers = sarchive;
+ omembers -= smembers;
+
+
+ /* create in-memory archive */
+ if (slbt_create_anonymous_archive_ctx(dctx,sarchive,&arctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+
+ /* get ready for writing */
+ base = arctx->map->map_addr;
+ ubase = arctx->map->map_addr;
+
+
+ /* archive header */
+ ch = base;
+ memcpy(ch,ar_signature,sizeof(struct ar_raw_signature));
+ ch += sizeof(struct ar_raw_signature);
+
+
+ /* armap header */
+ if (armap) {
+ arhdr = (struct ar_raw_file_header *)ch;
+ memcpy(arhdr,armap->ar_member_data,sizeof(*arhdr)+sarname);
+
+ nwritten = armap->ar_file_header.ar_time_date_stamp
+ ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
+ : 0;
+
+ if (nwritten < 0)
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
+ arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
+
+ nwritten = sprintf(
+ arhdr->ar_file_size,PPRIU64,
+ sarname + sarmap + ssymstrs);
+
+ if (nwritten < 0)
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
+ arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
+ }
+
+
+ /* arnames header (sysv only) */
+ if (arnames) {
+ ch = base;
+ ch += omembers;
+ ch -= snamestrs;
+ ch -= sizeof(struct ar_raw_file_header);
+
+ namebase = ch;
+ namebase += sizeof(struct ar_raw_file_header);
+
+ memset(namebase,0,snamestrs);
+ namestr = namebase;
+
+ arhdr = (struct ar_raw_file_header *)ch;
+ memcpy(arhdr,arnames->ar_member_data,sizeof(*arhdr));
+
+ nwritten = arnames->ar_file_header.ar_time_date_stamp
+ ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
+ : 0;
+
+ if (nwritten < 0)
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
+ arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
+
+ nwritten = sprintf(
+ arhdr->ar_file_size,PPRIU64,
+ snamestrs);
+
+ if (nwritten < 0)
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
+ arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
+ }
+
+
+ /* armap data (preparation) */
+ armap_write_uint32 = 0;
+ armap_write_uint64 = 0;
+
+ bsdmap32 = 0;
+ bsdmap64 = 0;
+
+ if (mapattr & AR_ARMAP_ATTR_BE_32)
+ armap_write_uint32 = slbt_armap_write_be_32;
+
+ else if (mapattr & AR_ARMAP_ATTR_LE_32)
+ armap_write_uint32 = slbt_armap_write_le_32;
+
+ else if (mapattr & AR_ARMAP_ATTR_BE_64)
+ armap_write_uint64 = slbt_armap_write_be_64;
+
+ else if (mapattr & AR_ARMAP_ATTR_LE_64)
+ armap_write_uint64 = slbt_armap_write_le_64;
+
+ uch = ubase;
+ uch += sizeof(struct ar_raw_signature);
+ uch += sizeof(struct ar_raw_file_header);
+ uch += sarname;
+
+ if (mapattr & AR_ARMAP_ATTR_SYSV) {
+ if (armap_write_uint32) {
+ uch += armap_write_uint32(uch,nsymrefs);
+
+ ch = base;
+ ch += uch - ubase;
+ ch += sizeof(uint32_t) * nsymrefs;
+ } else {
+ uch += armap_write_uint64(uch,nsymrefs);
+
+ ch = base;
+ ch += uch - ubase;
+ ch += sizeof(uint64_t) * nsymrefs;
+ }
+
+ } else if (mapattr & AR_ARMAP_ATTR_BSD) {
+ strtbl = base;
+ strtbl += omembers;
+ strtbl -= ssymstrs;
+
+ memset(strtbl,0,ssymstrs);
+
+ if (armap_write_uint32) {
+ if (!(bsdmap32 = calloc(2*nsymrefs,sizeof(struct armap_buffer_32))))
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ bsdsort32 = &bsdmap32[nsymrefs];
+
+ } else {
+ if (!(bsdmap64 = calloc(2*nsymrefs,sizeof(struct armap_buffer_64))))
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ bsdsort64 = &bsdmap64[nsymrefs];
+ }
+ }
+
+ /* main iteration (armap data, long-names, public members) */
+ for (mapidx=0,arctxp=arctxv; *arctxp; arctxp++) {
+ meta = (*arctxp)->meta;
+ armap32 = meta->a_armap_primary.ar_armap_common_32;
+ armap64 = meta->a_armap_primary.ar_armap_common_64;
+
+ if ((memberp = meta->a_memberv)) {
+ for (omemfixup=0; *memberp && !omemfixup; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ case AR_MEMBER_ATTR_LINKINFO:
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ omemfixup = (int64_t)meminfo->ar_member_data;
+ omemfixup -= (int64_t)meta->r_archive.map_addr;
+ break;
+ }
+ }
+ }
+
+ for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ if (armap32 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
+ symref32 = armap32->ar_symrefs;
+
+ for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
+ uch += armap_write_uint32(
+ uch,
+ symref32[idx].ar_member_offset + omembers - omemfixup);
+
+ strcpy(ch,&armap32->ar_string_table[symref32[idx].ar_name_offset]);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ } else if (armap64 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
+ symref64 = armap64->ar_symrefs;
+
+ for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
+ uch += armap_write_uint64(
+ uch,
+ symref64[idx].ar_member_offset + omembers - omemfixup);
+
+ strcpy(ch,&armap64->ar_string_table[symref64[idx].ar_name_offset]);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ } else if (armap32 && (mapattr & AR_ARMAP_ATTR_BSD)) {
+ symref32 = armap32->ar_symrefs;
+
+ for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
+ bsdmap32[mapidx].moffset = symref32[idx].ar_member_offset;
+ bsdmap32[mapidx].moffset += omembers - omemfixup;
+
+ bsdmap32[mapidx].symname = armap32->ar_string_table;
+ bsdmap32[mapidx].symname += symref32[idx].ar_name_offset;
+
+ mapidx++;
+ }
+
+ } else if (armap64 && (mapattr & AR_ARMAP_ATTR_BSD)) {
+ symref64 = armap64->ar_symrefs;
+
+ for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
+ bsdmap64[mapidx].moffset = symref64[idx].ar_member_offset;
+ bsdmap64[mapidx].moffset += omembers - omemfixup;
+
+ bsdmap64[mapidx].symname = armap64->ar_string_table;
+ bsdmap64[mapidx].symname += symref64[idx].ar_name_offset;
+
+ mapidx++;
+ }
+ }
+
+ break;
+
+ case AR_MEMBER_ATTR_LINKINFO:
+ break;
+
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ arhdr = meminfo->ar_member_data;
+
+ memcpy(
+ &base[omembers],arhdr,
+ sizeof(*arhdr) + meminfo->ar_file_header.ar_file_size);
+
+ if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_SYSV) {
+ if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_NAME_REF) {
+ nwritten = sprintf(
+ &base[omembers],"/"PPRII64,
+ namestr - namebase);
+
+ if (nwritten < 0)
+ SLBT_SYSTEM_ERROR(dctx,0);
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_id); nbytes++)
+ base[omembers + nbytes] = AR_DEC_PADDING;
+
+ strcpy(namestr,meminfo->ar_file_header.ar_member_name);
+ namestr += strlen(namestr);
+ *namestr++ = '/';
+ *namestr++ = AR_OBJ_PADDING;
+ }
+ }
+
+ omembers += sizeof(*arhdr);
+ omembers += meminfo->ar_file_header.ar_file_size;
+ omembers += 1;
+ omembers |= 1;
+ omembers ^= 1;
+ break;
+ }
+ }
+ }
+
+ /* bsd variant: also sort the string table (because we can:=)) */
+ if (bsdmap32) {
+ for (mapidx=0; mapidx<nsymrefs; mapidx++)
+ for (cmpidx=0; cmpidx<nsymrefs; cmpidx++)
+ if (strcmp(bsdmap32[cmpidx].symname,bsdmap32[mapidx].symname) < 0)
+ bsdmap32[mapidx].baseidx++;
+
+ /* a symbol might be present in more than one member; */
+ /* see whether ar_member_offset has already been set) */
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ idx = bsdmap32[mapidx].baseidx;
+
+ for (; bsdsort32[idx].moffset; )
+ idx++;
+
+ bsdsort32[idx].moffset = bsdmap32[mapidx].moffset;
+ bsdsort32[idx].symname = bsdmap32[mapidx].symname;
+ }
+
+ uch += armap_write_uint32(uch,2*sizeof(uint32_t)*nsymrefs);
+
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ uch += armap_write_uint32(uch,ch-strtbl);
+ uch += armap_write_uint32(uch,bsdsort32[mapidx].moffset);
+
+ strcpy(ch,bsdsort32[mapidx].symname);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ uch += armap_write_uint32(uch,ssymstrs);
+
+ free(bsdmap32);
+
+ } else if (bsdmap64) {
+ for (mapidx=0; mapidx<nsymrefs; mapidx++)
+ for (cmpidx=0; cmpidx<nsymrefs; cmpidx++)
+ if (strcmp(bsdmap64[cmpidx].symname,bsdmap64[mapidx].symname) < 0)
+ bsdmap64[mapidx].baseidx++;
+
+ /* a symbol might be present in more than one member; */
+ /* see whether ar_member_offset has already been set) */
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ idx = bsdmap64[mapidx].baseidx;
+
+ for (; bsdsort64[idx].moffset; )
+ idx++;
+
+ bsdsort64[idx].moffset = bsdmap64[mapidx].moffset;
+ bsdsort64[idx].symname = bsdmap64[mapidx].symname;
+ }
+
+ uch += armap_write_uint64(uch,2*sizeof(uint64_t)*nsymrefs);
+
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ uch += armap_write_uint64(uch,ch-strtbl);
+ uch += armap_write_uint64(uch,bsdsort64[mapidx].moffset);
+
+ strcpy(ch,bsdsort64[mapidx].symname);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ uch += armap_write_uint64(uch,ssymstrs);
+
+ free(bsdmap64);
+ }
+
+ struct slbt_archive_ctx_impl * ictx;
+ ictx = slbt_get_archive_ictx(arctx);
+
+ if (slbt_ar_get_archive_meta(dctx,arctx->map,&ictx->meta) < 0)
+ return slbt_ar_merge_archives_fail(
+ arctx,0,0,
+ SLBT_NESTED_ERROR(dctx));
+
+ ictx->actx.meta = ictx->meta;
+
+ *arctxm = arctx;
+
+ return 0;
+}
+
+
+int slbt_ar_get_varchive_ctx(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_ctx ** pctx)
+{
+ struct slbt_archive_ctx * ctx;
+ struct slbt_archive_ctx_impl * ictx;
+ void * base;
+ size_t size;
+
+ size = sizeof(struct ar_raw_signature);
+
+ if (slbt_create_anonymous_archive_ctx(dctx,size,&ctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ ictx = slbt_get_archive_ictx(ctx);
+
+ base = ctx->map->map_addr;
+ memcpy(base,ar_signature,size);
+
+ if (slbt_ar_get_archive_meta(dctx,ctx->map,&ictx->meta) < 0) {
+ slbt_ar_free_archive_ctx(ctx);
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ ictx->path = slbt_ar_self_dlunit;
+ ictx->actx.meta = ictx->meta;
+ ictx->actx.path = &ictx->path;
+
+ *pctx = ctx;
+
+ return 0;
+}
diff --git a/src/arbits/slbt_archive_meta.c b/src/arbits/slbt_archive_meta.c
new file mode 100644
index 0000000..8ef816c
--- /dev/null
+++ b/src/arbits/slbt_archive_meta.c
@@ -0,0 +1,888 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+
+/* transient header info vector */
+struct ar_header_info {
+ struct ar_raw_file_header * phdr;
+ uint32_t attr;
+};
+
+static const char ar_signature[] = AR_SIGNATURE;
+
+static int slbt_ar_free_archive_meta_impl(struct slbt_archive_meta_impl * meta, int ret)
+{
+ if (meta) {
+ if (meta->armaps.armap_symrefs_32)
+ free(meta->armaps.armap_symrefs_32);
+
+ if (meta->armaps.armap_symrefs_64)
+ free(meta->armaps.armap_symrefs_64);
+
+ if (meta->hdrinfov)
+ free(meta->hdrinfov);
+
+ if (meta->namestrs)
+ free(meta->namestrs);
+
+ if (meta->syminfo)
+ free(meta->syminfo);
+
+ if (meta->syminfv)
+ free(meta->syminfv);
+
+ if (meta->memberv)
+ free(meta->memberv);
+
+ if (meta->offsetv)
+ free(meta->offsetv);
+
+ if (meta->members)
+ free(meta->members);
+
+ if (meta->symstrv)
+ free(meta->symstrv);
+
+ if (meta->mapstrv)
+ free(meta->mapstrv);
+
+ if (meta->nminfo)
+ slbt_lib_free_txtfile_ctx(meta->nminfo);
+
+ free(meta);
+ }
+
+ return ret;
+}
+
+
+static int slbt_ar_read_octal(const char * mark, int len, uint32_t * dec)
+{
+ int i;
+ uint64_t res;
+
+ for (; len && (mark[len-1]==AR_DEC_PADDING); )
+ len--;
+
+ for (i=0,res=0; i<len; i++) {
+ if ((mark[i] >= '0') && (mark[i] <= '7')) {
+ res *= 8;
+ res += (mark[i] - '0');
+ } else {
+ return -1;
+ }
+ }
+
+ *dec = res;
+
+ return 0;
+}
+
+static int slbt_ar_read_decimal_64(const char * mark, int len, uint64_t * dec)
+{
+ int i;
+ uint64_t res;
+
+ for (; len && (mark[len-1]==AR_DEC_PADDING); )
+ len--;
+
+ for (i=0,res=0; i<len; i++) {
+ if ((mark[i] >= '0') && (mark[i] <= '9')) {
+ res *= 10;
+ res += (mark[i] - '0');
+ } else {
+ return -1;
+ }
+ }
+
+ *dec = res;
+
+ return 0;
+}
+
+static int slbt_ar_read_decimal_32(const char * mark, int len, uint32_t * dec)
+{
+ uint64_t res;
+
+ if (slbt_ar_read_decimal_64(mark,len,&res) < 0)
+ return -1;
+
+ *dec = res;
+
+ return 0;
+}
+
+static uint32_t slbt_ar_get_member_attr(struct ar_meta_member_info * m)
+{
+ const char * hdrname;
+ uint32_t hdrattr;
+ const char * data;
+ const char * data_cap;
+ const unsigned char * udata;
+ unsigned char uch;
+ const size_t siglen = sizeof(struct ar_raw_signature);
+
+ hdrname = m->ar_file_header.ar_member_name;
+ hdrattr = m->ar_file_header.ar_header_attr;
+
+ data = m->ar_object_data;
+ data_cap = &data[m->ar_file_header.ar_file_size];
+
+ if (hdrattr & AR_HEADER_ATTR_SYSV) {
+ /* long names member? */
+ if ((hdrname[0] == '/') && (hdrname[1] == '/'))
+ return AR_MEMBER_ATTR_NAMESTRS;
+
+ /* mips 64-bit armap member? */
+ else if (!strncmp(hdrname,"/SYM64/",7))
+ return AR_MEMBER_ATTR_ARMAP;
+
+ /* armap member? */
+ else if (hdrname[0] == '/' && (hdrname[1] == '\0'))
+ return AR_MEMBER_ATTR_ARMAP;
+
+ /* nested archive? */
+ else if (m->ar_file_header.ar_file_size >= siglen)
+ if (!strncmp(data,ar_signature,siglen))
+ return AR_MEMBER_ATTR_ARCHIVE;
+
+ } else if (hdrattr & AR_HEADER_ATTR_BSD) {
+ if (!strcmp(hdrname,"__.SYMDEF"))
+ return AR_MEMBER_ATTR_ARMAP;
+
+ else if (!strcmp(hdrname,"__.SYMDEF SORTED"))
+ return AR_MEMBER_ATTR_ARMAP;
+
+ else if (!strcmp(hdrname,"__.SYMDEF_64"))
+ return AR_MEMBER_ATTR_ARMAP;
+
+ else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED"))
+ return AR_MEMBER_ATTR_ARMAP;
+ }
+
+ /* ascii only data? */
+ for (; data<data_cap; ) {
+ if ((uch = *data) >= 0x80)
+ break;
+
+ data++;
+ }
+
+ if (data == data_cap)
+ return AR_MEMBER_ATTR_ASCII;
+
+ data = m->ar_object_data;
+ udata = (unsigned char *)data;
+
+ /* elf object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 5)
+ if ((udata[0] == 0x7f)
+ && (udata[1] == 'E')
+ && (udata[2] == 'L')
+ && (udata[3] == 'F'))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_ELF))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* coff i386 object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 2)
+ if ((udata[0] == 0x4c) && (udata[1] == 0x01))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* coff x86_64 object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 2)
+ if ((udata[0] == 0x64) && (udata[1] == 0x86))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* big endian 32-bit macho object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 4)
+ if ((udata[0] == 0xfe) && (udata[1] == 0xed))
+ if ((udata[2] == 0xfa) && (udata[3] == 0xce))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* big endian 64-bit macho object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 4)
+ if ((udata[0] == 0xfe) && (udata[1] == 0xed))
+ if ((udata[2] == 0xfa) && (udata[3] == 0xcf))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* little endian 32-bit macho object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 4)
+ if ((udata[3] == 0xfe) && (udata[2] == 0xed))
+ if ((udata[1] == 0xfa) && (udata[0] == 0xce))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* little endian 64-bit macho object? [quick and dirty] */
+ if (m->ar_file_header.ar_file_size >= 4)
+ if ((udata[3] == 0xfe) && (udata[2] == 0xed))
+ if ((udata[1] == 0xfa) && (udata[0] == 0xcf))
+ if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
+ return AR_MEMBER_ATTR_OBJECT;
+
+ /* all other */
+ return AR_MEMBER_ATTR_DEFAULT;
+}
+
+static int slbt_ar_parse_primary_armap(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * m)
+
+{
+ struct ar_meta_member_info * memberp;
+ const char * hdrname;
+ uint32_t hdrattr;
+
+ memberp = m->memberv[0];
+ hdrname = memberp->ar_file_header.ar_member_name;
+ hdrattr = memberp->ar_file_header.ar_header_attr;
+
+ if (!(memberp->ar_member_attr & AR_MEMBER_ATTR_ARMAP))
+ return 0;
+
+ if (hdrattr & AR_HEADER_ATTR_SYSV) {
+ /* mips 64-bit armap member? */
+ if (!strncmp(hdrname,"/SYM64/",7))
+ return slbt_ar_parse_primary_armap_sysv_64(
+ dctx,m);
+
+ /* sysv 32-bit armap member */
+ return slbt_ar_parse_primary_armap_sysv_32(
+ dctx,m);
+
+ } else if (hdrattr & AR_HEADER_ATTR_BSD) {
+ if (!strcmp(hdrname,"__.SYMDEF"))
+ return slbt_ar_parse_primary_armap_bsd_32(
+ dctx,m);
+
+ else if (!strcmp(hdrname,"__.SYMDEF SORTED"))
+ return slbt_ar_parse_primary_armap_bsd_32(
+ dctx,m);
+
+ else if (!strcmp(hdrname,"__.SYMDEF_64"))
+ return slbt_ar_parse_primary_armap_bsd_64(
+ dctx,m);
+
+ else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED"))
+ return slbt_ar_parse_primary_armap_bsd_64(
+ dctx,m);
+ }
+
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);
+}
+
+slbt_hidden struct ar_meta_member_info * slbt_archive_member_from_offset(
+ struct slbt_archive_meta_impl * meta,
+ off_t offset)
+{
+ intptr_t l,r,m;
+ off_t * offsetv;
+
+ l = 0;
+ r = meta->nentries - 1;
+
+ offsetv = meta->offsetv;
+
+ while (l != r) {
+ m = (l + r) / 2;
+ m += (l + r) % 2;
+
+ if (offsetv[m] > offset) {
+ r = --m;
+ } else {
+ l = m;
+ }
+ }
+
+ return (offsetv[l] == offset) ? meta->memberv[l] : 0;
+}
+
+int slbt_ar_get_archive_meta(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_raw_archive * archive,
+ struct slbt_archive_meta ** meta)
+{
+ const char * mark;
+ const char * cap;
+ struct slbt_archive_meta_impl * m;
+ const char * slash;
+ const char * ch;
+ const char * fldcap;
+ size_t nelements;
+ uint64_t nentries;
+ uint64_t nmembers;
+ uint64_t stblsize;
+ uint64_t filesize;
+ uint64_t namelen;
+ uint64_t nameoff;
+ uint32_t attr;
+ void * s_addr;
+ void * m_addr;
+ const char * s_ptr;
+ const char * m_ptr;
+ struct ar_raw_file_header * arhdr;
+ struct ar_raw_file_header * arlongnames;
+ struct ar_meta_member_info * memberp;
+ char * longnamep;
+ size_t idx;
+ struct ar_meta_armap_ref_32 * symrefs_32;
+ struct ar_meta_armap_ref_64 * symrefs_64;
+ struct ar_header_info * hdrinfov;
+ struct ar_header_info * hdrinfov_cap;
+ struct ar_header_info * hdrinfov_next;
+ struct ar_header_info hdrinfobuf[AR_STACK_VECTOR_ELEMENTS];
+
+ /* init */
+ hdrinfov = hdrinfobuf;
+ hdrinfov_cap = &hdrinfobuf[AR_STACK_VECTOR_ELEMENTS];
+ nelements = AR_STACK_VECTOR_ELEMENTS;
+
+ memset(hdrinfobuf,0,sizeof(hdrinfobuf));
+
+ mark = archive->map_addr;
+ cap = &mark[archive->map_size];
+
+ /* preliminary validation */
+ if (archive->map_size < sizeof(struct ar_raw_signature))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_SIGNATURE);
+
+ else if (strncmp(mark,ar_signature,sizeof(struct ar_raw_signature)))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_SIGNATURE);
+
+ /* alloc */
+ if (!(m = calloc(1,sizeof(*m))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* associated driver context */
+ m->dctx = dctx;
+
+ /* archive map info */
+ m->armeta.r_archive.map_addr = archive->map_addr;
+ m->armeta.r_archive.map_size = archive->map_size;
+
+ /* archive signature */
+ m->armeta.r_signature = (struct ar_raw_signature *)mark;
+ m->armeta.m_signature = (struct ar_meta_signature *)ar_signature;
+
+ /* signature only? */
+ if (archive->map_size == sizeof(struct ar_raw_signature)) {
+ *meta = &m->armeta;
+ return 0;
+ }
+
+ mark += sizeof(struct ar_raw_signature);
+
+ /* only trailing null characters past the signature? */
+ if (cap < &mark[sizeof(*arhdr)])
+ for (ch=mark; ch<cap; ch++)
+ if (*ch)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ /* count entries, calculate string table size */
+ for (nentries=0,stblsize=0,arlongnames=0; mark<cap; nentries++) {
+ arhdr = (struct ar_raw_file_header *)mark;
+
+ /* file size */
+ if ((slbt_ar_read_decimal_64(
+ arhdr->ar_file_size,
+ sizeof(arhdr->ar_file_size),
+ &filesize)) < 0)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ mark += sizeof(struct ar_raw_file_header);
+
+ /* stblsize, member name type */
+ fldcap = &arhdr->ar_file_id[sizeof(arhdr->ar_file_id)];
+
+ /* sysv long names table? */
+ if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) {
+ for (ch=&arhdr->ar_file_id[2]; ch<fldcap; ch++)
+ if (*ch != AR_DEC_PADDING)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ if (slbt_ar_read_decimal_64(
+ arhdr->ar_file_size,
+ sizeof(arhdr->ar_file_size),
+ &namelen) < 0)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+
+ /* duplicate long names member? */
+ if (arlongnames)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_DUPLICATE_LONG_NAMES));
+
+ attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
+
+ stblsize++;
+ stblsize++;
+ stblsize++;
+
+ stblsize += namelen;
+
+ arlongnames = arhdr;
+
+ /* the /SYM64/ string must be special cased, also below when it gets copied */
+ } else if (!strncmp(arhdr->ar_file_id,"/SYM64/",7)) {
+ for (ch=&arhdr->ar_file_id[7]; ch<fldcap; ch++)
+ if (*ch != AR_DEC_PADDING)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
+ stblsize += 8;
+
+ /* sysv armap member or sysv long name reference? */
+ } else if (arhdr->ar_file_id[0] == '/') {
+ if (slbt_ar_read_decimal_64(
+ &arhdr->ar_file_id[1],
+ sizeof(arhdr->ar_file_id)-1,
+ &nameoff) < 0)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ if (arhdr->ar_file_id[1] == AR_DEC_PADDING) {
+ attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
+ stblsize++;
+ stblsize++;
+ } else {
+ attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV;
+ }
+
+ /* bsd long name reference? */
+ } else if ((arhdr->ar_file_id[0] == '#')
+ && (arhdr->ar_file_id[1] == '1')
+ && (arhdr->ar_file_id[2] == '/')) {
+ if (slbt_ar_read_decimal_64(
+ &arhdr->ar_file_id[3],
+ sizeof(arhdr->ar_file_id)-3,
+ &namelen) < 0)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD;
+
+ stblsize += namelen + 1;
+
+ /* must be either a sysv short member name, or a (legacy) bsd short name */
+ } else {
+ for (ch=arhdr->ar_file_id,slash=0; (ch<fldcap) && !slash; ch++)
+ if (*ch == '/')
+ slash = ch;
+
+ if (slash) {
+ attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
+ stblsize += (slash - arhdr->ar_file_id) + 1;
+ } else {
+ attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD;
+ stblsize += sizeof(arhdr->ar_file_id) + 1;
+ }
+
+ for (; ch<fldcap; )
+ if (*ch++ != AR_DEC_PADDING)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ }
+
+ /* truncated data? */
+ if (cap < &mark[filesize])
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_TRUNCATED_DATA));
+
+ /* ar member alignment */
+ filesize += 1;
+ filesize |= 1;
+ filesize ^= 1;
+
+ mark += filesize;
+
+ /* only trailing null characters past the signature? */
+ if (cap < &mark[sizeof(*arhdr)])
+ for (; mark<cap; )
+ if (*mark++)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_HEADER));
+
+ /* transient header info vector */
+ if (&hdrinfov[nentries] == hdrinfov_cap) {
+ nelements = (nelements == AR_STACK_VECTOR_ELEMENTS)
+ ? (nelements << 4) : (nelements << 1);
+
+ if (!(hdrinfov_next = calloc(nelements,sizeof(*hdrinfov))))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_TRUNCATED_DATA));
+
+ for (idx=0; idx<nentries; idx++) {
+ hdrinfov_next[idx].phdr = hdrinfov[idx].phdr;
+ hdrinfov_next[idx].attr = hdrinfov[idx].attr;
+ };
+
+ if (hdrinfov != hdrinfobuf)
+ free(hdrinfov);
+
+ hdrinfov = hdrinfov_next;
+ hdrinfov_cap = &hdrinfov_next[nelements];
+ m->hdrinfov = hdrinfov;
+ }
+
+ hdrinfov[nentries].phdr = arhdr;
+ hdrinfov[nentries].attr = attr;
+ }
+
+ /* allocate name strings, member vector */
+ if (!(m->namestrs = calloc(1,stblsize)))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_SYSTEM_ERROR(dctx,0));
+
+ if (!(m->offsetv = calloc(nentries+1,sizeof(*m->offsetv))))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_SYSTEM_ERROR(dctx,0));
+
+ if (!(m->memberv = calloc(nentries+1,sizeof(*m->memberv))))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_SYSTEM_ERROR(dctx,0));
+
+ if (!(m->members = calloc(nentries,sizeof(*m->members))))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_SYSTEM_ERROR(dctx,0));
+
+ /* archive signature reference */
+ s_addr = archive->map_addr;
+ s_ptr = s_addr;
+
+ /* iterate, store meta data in library-friendly form */
+ for (idx=0,longnamep=m->namestrs; idx<nentries; idx++) {
+ arhdr = hdrinfov[idx].phdr;
+ attr = hdrinfov[idx].attr;
+
+ m_addr = arhdr;
+ m_ptr = m_addr;
+
+ memberp = &m->members[idx];
+ m->offsetv[idx] = m_ptr - s_ptr;
+ m->memberv[idx] = memberp;
+
+ memberp->ar_file_header.ar_header_attr = attr;
+
+ slbt_ar_read_decimal_64(
+ arhdr->ar_time_date_stamp,
+ sizeof(arhdr->ar_time_date_stamp),
+ &memberp->ar_file_header.ar_time_date_stamp);
+
+ slbt_ar_read_decimal_32(
+ arhdr->ar_uid,
+ sizeof(arhdr->ar_uid),
+ &memberp->ar_file_header.ar_uid);
+
+ slbt_ar_read_decimal_32(
+ arhdr->ar_gid,
+ sizeof(arhdr->ar_gid),
+ &memberp->ar_file_header.ar_gid);
+
+ slbt_ar_read_octal(
+ arhdr->ar_file_mode,
+ sizeof(arhdr->ar_file_mode),
+ &memberp->ar_file_header.ar_file_mode);
+
+ slbt_ar_read_decimal_64(
+ arhdr->ar_file_size,
+ sizeof(arhdr->ar_file_size),
+ &memberp->ar_file_header.ar_file_size);
+
+ memberp->ar_file_header.ar_member_name = longnamep;
+
+ if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV)) {
+ if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) {
+ *longnamep++ = '/';
+ *longnamep++ = '/';
+ longnamep++;
+
+ } else if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == 'S')) {
+ *longnamep++ = '/';
+ *longnamep++ = 'S';
+ *longnamep++ = 'Y';
+ *longnamep++ = 'M';
+ *longnamep++ = '6';
+ *longnamep++ = '4';
+ *longnamep++ = '/';
+ longnamep++;
+
+ } else if (arhdr->ar_file_id[0] == '/') {
+ *longnamep++ = '/';
+ longnamep++;
+
+ } else {
+ ch = arhdr->ar_file_id;
+
+ for (; (*ch != '/'); )
+ *longnamep++ = *ch++;
+
+ longnamep++;
+ }
+
+ } else if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD)) {
+ ch = arhdr->ar_file_id;
+ fldcap = &ch[sizeof(arhdr->ar_file_id)];
+
+ for (; (ch<fldcap) && (*ch != AR_DEC_PADDING); )
+ *longnamep++ = *ch++;
+
+ longnamep++;
+
+ } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV)) {
+ slbt_ar_read_decimal_64(
+ &arhdr->ar_file_id[1],
+ sizeof(arhdr->ar_file_id) - 1,
+ &nameoff);
+
+ ch = arlongnames->ar_file_id;
+ ch += sizeof(*arlongnames);
+ ch += nameoff;
+
+ for (; *ch && (*ch != '/') && (*ch != AR_OBJ_PADDING); )
+ *longnamep++ = *ch++;
+
+ longnamep++;
+
+ } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) {
+ slbt_ar_read_decimal_64(
+ &arhdr->ar_file_id[3],
+ sizeof(arhdr->ar_file_id) - 3,
+ &namelen);
+
+ mark = arhdr->ar_file_id;
+ mark += sizeof(*arhdr);
+
+ memcpy(longnamep,mark,namelen);
+
+ longnamep += namelen;
+ longnamep++;
+ }
+
+ /* member raw header, object size, object data */
+ mark = arhdr->ar_file_id;
+ mark += sizeof(*arhdr);
+ namelen = 0;
+
+ if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) {
+ slbt_ar_read_decimal_64(
+ &arhdr->ar_file_id[3],
+ sizeof(arhdr->ar_file_id)-3,
+ &namelen);
+
+ namelen += 1;
+ namelen |= 1;
+ namelen ^= 1;
+
+ mark += namelen;
+ };
+
+ memberp->ar_member_data = arhdr;
+ memberp->ar_object_data = (void *)mark;
+ memberp->ar_object_size = memberp->ar_file_header.ar_file_size - namelen;
+
+ /* member attribute */
+ memberp->ar_member_attr = slbt_ar_get_member_attr(memberp);
+
+ /* pe/coff second linker member? */
+ if ((idx == 1) && (memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP))
+ if (hdrinfov[0].attr & AR_HEADER_ATTR_SYSV)
+ if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP)
+ if (attr & AR_HEADER_ATTR_SYSV)
+ memberp->ar_member_attr = AR_MEMBER_ATTR_LINKINFO;
+
+ /* armap member must be the first */
+ if ((memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP) && (idx > 0)) {
+ if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER));
+
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER));
+ }
+ }
+
+ /* number of archive members, including internal ones */
+ m->nentries = nentries;
+
+ /* primary armap (first linker member) */
+ if (slbt_ar_parse_primary_armap(dctx,m) < 0)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_NESTED_ERROR(dctx));
+
+ for (idx=0,ch=m->symstrs; idx<m->armaps.armap_nsyms; idx++) {
+ m->symstrv[idx] = ch;
+ ch += strlen(ch);
+ ch++;
+ }
+
+ if (m->armaps.armap_common_32.ar_member) {
+ symrefs_32 = m->armaps.armap_symrefs_32;
+
+ for (idx=0; idx<m->armaps.armap_nsyms; idx++) {
+ if (m->armaps.armap_common_32.ar_armap_attr & AR_ARMAP_ATTR_SYSV)
+ symrefs_32[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0];
+
+ if (!slbt_archive_member_from_offset(m,symrefs_32[idx].ar_member_offset))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET));
+
+ if (symrefs_32[idx].ar_name_offset) {
+ ch = &m->symstrs[symrefs_32[idx].ar_name_offset];
+
+ if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET));
+ }
+
+ }
+ }
+
+ if (m->armaps.armap_common_64.ar_member) {
+ symrefs_64 = m->armaps.armap_symrefs_64;
+
+ for (idx=0; idx<m->armaps.armap_nsyms; idx++) {
+ if (m->armaps.armap_common_64.ar_armap_attr & AR_ARMAP_ATTR_SYSV)
+ symrefs_64[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0];
+
+ if (!slbt_archive_member_from_offset(m,symrefs_64[idx].ar_member_offset))
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET));
+
+ if (symrefs_64[idx].ar_name_offset) {
+ ch = &m->symstrs[symrefs_64[idx].ar_name_offset];
+
+ if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch)
+ return slbt_ar_free_archive_meta_impl(
+ m,SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET));
+ }
+
+ }
+ }
+
+ /* number of public archive members */
+ for (idx=0,nmembers=0; idx<nentries; idx++) {
+ switch (m->memberv[idx]->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ case AR_MEMBER_ATTR_LINKINFO:
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ nmembers++;
+ }
+ }
+
+ if (m->armaps.armap_common_32.ar_member)
+ m->armaps.armap_common_32.ar_num_of_members = nmembers;
+
+ if (m->armaps.armap_common_64.ar_member)
+ m->armaps.armap_common_64.ar_num_of_members = nmembers;
+
+ /* pe/coff armap attributes (second linker member) */
+ (void)m->armeta.a_armap_pecoff;
+
+ /* reference to the long names member */
+ if (arlongnames)
+ for (idx=0; idx<nentries && !m->armeta.a_arref_longnames; idx++)
+ if (m->memberv[idx]->ar_member_data == arlongnames)
+ m->armeta.a_arref_longnames = m->memberv[idx];
+
+ /* common binary format (information only) */
+ for (idx=0,nmembers=0; idx<nentries; idx++) {
+ if (m->memberv[idx]->ar_member_attr == AR_MEMBER_ATTR_OBJECT) {
+ if (m->ofmtattr && (m->ofmtattr != m->memberv[idx]->ar_object_attr)) {
+ m->ofmtattr = 0;
+ idx = nentries;
+ } else if (!m->ofmtattr) {
+ m->ofmtattr = m->memberv[idx]->ar_object_attr;
+ }
+ }
+ }
+
+ /* member vector */
+ m->armeta.a_memberv = m->memberv;
+
+ /* all done */
+ if (m->hdrinfov) {
+ free(m->hdrinfov);
+ m->hdrinfov = 0;
+ }
+
+ *meta = &m->armeta;
+
+ return 0;
+}
+
+void slbt_ar_free_archive_meta(struct slbt_archive_meta * meta)
+{
+ struct slbt_archive_meta_impl * m;
+
+ if (meta) {
+ m = slbt_archive_meta_ictx(meta);
+ slbt_ar_free_archive_meta_impl(m,0);
+ }
+}
diff --git a/src/arbits/slbt_archive_store.c b/src/arbits/slbt_archive_store.c
new file mode 100644
index 0000000..d09a3f0
--- /dev/null
+++ b/src/arbits/slbt_archive_store.c
@@ -0,0 +1,145 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+/****************************************************/
+/* As elsewhere in slibtool, file-system operations */
+/* utilizie the _at variants of the relevant posix */
+/* interfaces. In the case of archives, that means */
+/* passing dctx->fdctx->fdcwd as the _fdat_ param, */
+/* where dctx is the driver context which was used */
+/* with slbt_ar_get_archive_ctx(). */
+/************************************************** */
+
+#define PPRIX64 "%"PRIx64
+
+int slbt_ar_store_archive(
+ struct slbt_archive_ctx * arctx,
+ const char * path,
+ mode_t mode)
+{
+ const struct slbt_driver_ctx * dctx;
+ struct stat st;
+ int fdat;
+ int fdtmp;
+ void * addr;
+ char * mark;
+ char * slash;
+ size_t buflen;
+ size_t nbytes;
+ ssize_t written;
+ char buf[PATH_MAX];
+
+ /* init dctx */
+ if (!(dctx = slbt_get_archive_ictx(arctx)->dctx))
+ return -1;
+
+ /* validation */
+ if (strlen(path) >= PATH_MAX)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ /**************************************************/
+ /* create temporary file in the target directory */
+ /* */
+ /* the tmpfile name pattern involes the inode */
+ /* of the target directory, a local stack address */
+ /* in the calling thread, the current time, and */
+ /* finally the pid of the current process. */
+ /**************************************************/
+
+ memset(buf,0,sizeof(buf));
+ strcpy(buf,path);
+
+ fdat = slbt_driver_fdcwd(dctx);
+
+ addr = buf;
+ mark = (slash = strrchr(buf,'/'))
+ ? slash : buf;
+
+ if (slash) {
+ *++mark = '\0';
+
+ if (fstatat(fdat,buf,&st,0) < 0)
+ return SLBT_SYSTEM_ERROR(
+ dctx,buf);
+ } else {
+ if (fstatat(fdat,".",&st,0) < 0)
+ return SLBT_SYSTEM_ERROR(
+ dctx,0);
+ }
+
+ buflen = sizeof(buf) - (mark - buf);
+ nbytes = snprintf(
+ mark,
+ buflen,
+ ".slibtool.tmpfile"
+ ".inode."PPRIX64
+ ".time."PPRIX64
+ ".salt.%p"
+ ".pid.%d"
+ ".tmp",
+ st.st_ino,
+ time(0),addr,
+ getpid());
+
+ if (nbytes >= buflen)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ if ((fdtmp = openat(fdat,buf,O_WRONLY|O_CREAT|O_EXCL,mode)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,buf);
+
+ /* set archive size */
+ if (ftruncate(fdtmp,arctx->map->map_size) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* write archive */
+ mark = arctx->map->map_addr;
+ nbytes = arctx->map->map_size;
+
+ for (; nbytes; ) {
+ written = write(fdtmp,mark,nbytes);
+
+ while ((written < 0) && (errno == EINTR))
+ written = write(fdtmp,mark,nbytes);
+
+ if (written < 0) {
+ unlinkat(fdat,buf,0);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ };
+
+ nbytes -= written;
+ mark += written;
+ }
+
+ /* finalize (atomically) */
+ if (renameat(fdat,buf,fdat,path) < 0) {
+ unlinkat(fdat,buf,0);
+ return SLBT_SYSTEM_ERROR(dctx,buf);
+ }
+
+ /* yay */
+ return 0;
+}
diff --git a/src/arbits/slbt_archive_symfile.c b/src/arbits/slbt_archive_symfile.c
new file mode 100644
index 0000000..49d2ff0
--- /dev/null
+++ b/src/arbits/slbt_archive_symfile.c
@@ -0,0 +1,138 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <locale.h>
+#include <regex.h>
+#include <inttypes.h>
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_output.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_pecoff_impl.h"
+#include "slibtool_ar_impl.h"
+
+/********************************************************/
+/* Generate a symbol list that could be used by a build */
+/* system for code generation or any other purpose. */
+/* */
+/* The output matches the -Wposix variant of symbol */
+/* printing, but the interface should be kept separate */
+/* since the _au_output_ functions implement several */
+/* output format, whereas here only a single, plain */
+/* output is expected. */
+/********************************************************/
+
+static int slbt_ar_output_symfile_impl(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx,
+ int fdout)
+{
+ bool fsort;
+ bool fcoff;
+ const char * dot;
+ const char * mark;
+ const char * regex;
+ const char ** symv;
+ const char ** symstrv;
+ regex_t regctx;
+ regmatch_t pmatch[2] = {{0,0},{0,0}};
+ char strbuf[4096];
+
+ fsort = !(dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_NOSORT);
+
+ fcoff = slbt_host_objfmt_is_coff(dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ if (fsort && !mctx->mapstrv)
+ if (slbt_update_mapstrv(dctx,mctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if ((regex = dctx->cctx->regex))
+ if (regcomp(&regctx,regex,REG_EXTENDED|REG_NEWLINE))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ symstrv = fsort ? mctx->mapstrv : mctx->symstrv;
+
+ for (symv=symstrv; *symv; symv++) {
+ if (!fcoff || slbt_is_strong_coff_symbol(*symv)) {
+ if (!regex || !regexec(&regctx,*symv,1,pmatch,0)) {
+ if (slbt_dprintf(fdout,"%s\n",*symv) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* coff weak symbols: expsym = .weak.alias.strong */
+ } else if (fcoff && !strncmp(*symv,".weak.",6)) {
+ mark = &(*symv)[6];
+ dot = strchr(mark,'.');
+
+ strncpy(strbuf,mark,dot-mark);
+ strbuf[dot-mark] = '\0';
+
+ if (!regex || !regexec(&regctx,strbuf,1,pmatch,0))
+ if (slbt_dprintf(fdout," %s = %s\n",strbuf,++dot) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+ }
+
+ if (regex)
+ regfree(&regctx);
+
+ return 0;
+}
+
+
+static int slbt_ar_create_symfile_impl(
+ const struct slbt_archive_meta * meta,
+ const char * path,
+ mode_t mode)
+{
+ int ret;
+ struct slbt_archive_meta_impl * mctx;
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_fd_ctx fdctx;
+ int fdout;
+
+ mctx = slbt_archive_meta_ictx(meta);
+ dctx = (slbt_archive_meta_ictx(meta))->dctx;
+
+ if (slbt_lib_get_driver_fdctx(dctx,&fdctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ if (!meta->a_memberv)
+ return 0;
+
+ if (path) {
+ if ((fdout = openat(
+ fdctx.fdcwd,path,
+ O_WRONLY|O_CREAT|O_TRUNC,
+ mode)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,path);
+ } else {
+ fdout = fdctx.fdout;
+ }
+
+ ret = slbt_ar_output_symfile_impl(
+ dctx,mctx,fdout);
+
+ if (path) {
+ close(fdout);
+ }
+
+ return ret;
+}
+
+
+int slbt_ar_create_symfile(
+ const struct slbt_archive_meta * meta,
+ const char * path,
+ mode_t mode)
+{
+ return slbt_ar_create_symfile_impl(meta,path,mode);
+}
diff --git a/src/arbits/slbt_archive_syminfo.c b/src/arbits/slbt_archive_syminfo.c
new file mode 100644
index 0000000..09c90a8
--- /dev/null
+++ b/src/arbits/slbt_archive_syminfo.c
@@ -0,0 +1,345 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_coff_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_spawn_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+static const char ar_symbol_type_A[] = "A";
+static const char ar_symbol_type_B[] = "B";
+static const char ar_symbol_type_C[] = "C";
+static const char ar_symbol_type_D[] = "D";
+static const char ar_symbol_type_G[] = "G";
+static const char ar_symbol_type_I[] = "I";
+static const char ar_symbol_type_R[] = "R";
+static const char ar_symbol_type_S[] = "S";
+static const char ar_symbol_type_T[] = "T";
+static const char ar_symbol_type_W[] = "W";
+
+static const char * const ar_symbol_type['Z'-'A'] = {
+ ['A'-'A'] = ar_symbol_type_A,
+ ['B'-'A'] = ar_symbol_type_B,
+ ['C'-'A'] = ar_symbol_type_C,
+ ['D'-'A'] = ar_symbol_type_D,
+ ['G'-'A'] = ar_symbol_type_G,
+ ['I'-'A'] = ar_symbol_type_I,
+ ['R'-'A'] = ar_symbol_type_R,
+ ['S'-'A'] = ar_symbol_type_S,
+ ['T'-'A'] = ar_symbol_type_T,
+ ['W'-'A'] = ar_symbol_type_W,
+};
+
+static void slbt_ar_update_syminfo_child(
+ char * program,
+ char * arname,
+ int fdout)
+{
+ char * argv[6];
+
+ argv[0] = program;
+ argv[1] = "-P";
+ argv[2] = "-A";
+ argv[3] = "-g";
+ argv[4] = arname;
+ argv[5] = 0;
+
+ if (dup2(fdout,1) == 1)
+ execvp(program,argv);
+
+ _exit(EXIT_FAILURE);
+}
+
+static int slbt_obtain_nminfo(
+ struct slbt_archive_ctx_impl * ictx,
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx,
+ int fdout)
+{
+ int ret;
+ int pos;
+ int fdcwd;
+ int fdarg;
+ pid_t pid;
+ pid_t rpid;
+ int ecode;
+ char ** argv;
+ char arname [PATH_MAX];
+ char output [PATH_MAX];
+ char program[PATH_MAX];
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* tool-specific argument vector */
+ argv = (slbt_get_driver_ictx(dctx))->host.nm_argv;
+
+ /* ar alternate argument vector */
+ if (argv) {
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",argv[0]) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+ } else {
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.nm) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+ }
+
+ /* arname (.nm suffix, buf treat as .syminfo) */
+ pos = slbt_snprintf(
+ arname,sizeof(arname)-8,"%s",
+ ictx->path);
+
+ /* output */
+ if ((fdarg = fdout) < 0) {
+ strcpy(output,arname);
+ strcpy(&output[pos],".nm");
+
+ if ((fdout = openat(fdcwd,output,O_CREAT|O_TRUNC|O_RDWR,0644)) < 0)
+ return SLBT_SYSTEM_ERROR(dctx,output);
+ } else {
+ strcpy(output,"@nminfo@");
+ }
+
+ /* fork */
+ if ((pid = slbt_fork()) < 0) {
+ close(fdout);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* child */
+ if (pid == 0)
+ slbt_ar_update_syminfo_child(
+ program,arname,fdout);
+
+ /* parent */
+ rpid = waitpid(
+ pid,
+ &ecode,
+ 0);
+
+ /* nm output */
+ if ((rpid > 0) && (ecode == 0))
+ ret = slbt_impl_get_txtfile_ctx(
+ dctx,output,fdout,
+ &mctx->nminfo);
+
+ if (fdarg < 0)
+ close(fdout);
+
+ if (rpid < 0) {
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ } else if (ecode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0;
+}
+
+static int slbt_get_symbol_nm_info(
+ struct slbt_archive_ctx * actx,
+ struct slbt_archive_meta_impl * mctx,
+ uint64_t idx)
+{
+ int cint;
+ const char ** pline;
+ const char * mark;
+ const char * cap;
+ const char * objname;
+ const char * symname;
+ struct ar_meta_symbol_info * syminfo;
+ struct ar_meta_member_info ** pmember;
+
+ symname = mctx->symstrv[idx];
+ syminfo = &mctx->syminfo[idx];
+
+ for (pline=mctx->nminfo->txtlinev; *pline; pline++) {
+ mark = *pline;
+
+ if (!(mark = strchr(mark,']')))
+ return -1;
+
+ if ((*++mark != ':') || (*++mark != ' '))
+ return -1;
+
+ cap = ++mark;
+
+ for (; *cap && !isspace((cint = *cap)); )
+ cap++;
+
+ if (*cap != ' ')
+ return -1;
+
+ if (!(strncmp(symname,mark,cap-mark))) {
+ mark = ++cap;
+
+ /* space only according to posix, but ... */
+ if (mark[1] && (mark[1] != ' '))
+ return -1;
+
+ switch (mark[0]) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'G':
+ case 'I':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'W':
+ syminfo->ar_symbol_type = ar_symbol_type[mark[0]-'A'];
+ break;
+
+ default:
+ break;
+ }
+
+ if (syminfo->ar_symbol_type) {
+ syminfo->ar_archive_name = *actx->path;
+ syminfo->ar_symbol_name = symname;
+
+ if (!(mark = strchr(*pline,'[')))
+ return -1;
+
+ if (!(cap = strchr(++mark,']')))
+ return -1;
+ }
+
+ pmember = mctx->memberv;
+
+ for (; *pmember && !syminfo->ar_object_name; ) {
+ objname = (*pmember)->ar_file_header.ar_member_name;
+
+ if (!(strncmp(objname,mark,cap-mark)))
+ syminfo->ar_object_name = objname;
+
+ pmember++;
+ }
+
+ mctx->syminfv[idx] = syminfo;
+ }
+ }
+
+ return (mctx->syminfv[idx] ? 0 : (-1));
+}
+
+static int slbt_qsort_syminfo_cmp(const void * a, const void * b)
+{
+ struct ar_meta_symbol_info ** syminfoa;
+ struct ar_meta_symbol_info ** syminfob;
+
+ syminfoa = (struct ar_meta_symbol_info **)a;
+ syminfob = (struct ar_meta_symbol_info **)b;
+
+ return strcmp(
+ (*syminfoa)->ar_symbol_name,
+ (*syminfob)->ar_symbol_name);
+}
+
+static int slbt_coff_qsort_syminfo_cmp(const void * a, const void * b)
+{
+ struct ar_meta_symbol_info ** syminfoa;
+ struct ar_meta_symbol_info ** syminfob;
+
+ syminfoa = (struct ar_meta_symbol_info **)a;
+ syminfob = (struct ar_meta_symbol_info **)b;
+
+ return slbt_coff_qsort_strcmp(
+ &(*syminfoa)->ar_symbol_name,
+ &(*syminfob)->ar_symbol_name);
+}
+
+static int slbt_ar_update_syminfo_impl(
+ struct slbt_archive_ctx * actx,
+ int fdout)
+{
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_archive_ctx_impl * ictx;
+ struct slbt_archive_meta_impl * mctx;
+ uint64_t idx;
+ bool fcoff;
+
+ /* driver context, etc. */
+ ictx = slbt_get_archive_ictx(actx);
+ mctx = slbt_archive_meta_ictx(ictx->meta);
+ dctx = ictx->dctx;
+
+ /* nm -P -A -g */
+ if (mctx->armaps.armap_nsyms) {
+ if (slbt_obtain_nminfo(ictx,dctx,mctx,fdout) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ } else {
+ if (slbt_lib_get_txtfile_ctx(
+ dctx,"/dev/null",
+ &mctx->nminfo) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* free old syminfo vector */
+ if (mctx->syminfv)
+ free(mctx->syminfv);
+
+ /* syminfo vector: armap symbols only */
+ if (!(mctx->syminfo = calloc(
+ mctx->armaps.armap_nsyms + 1,
+ sizeof(*mctx->syminfo))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(mctx->syminfv = calloc(
+ mctx->armaps.armap_nsyms + 1,
+ sizeof(*mctx->syminfv))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* do the thing */
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (slbt_get_symbol_nm_info(actx,mctx,idx) < 0)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+
+ /* coff-aware sorting */
+ fcoff = slbt_host_objfmt_is_coff(dctx);
+ fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
+
+ qsort(mctx->syminfv,mctx->armaps.armap_nsyms,sizeof(*mctx->syminfv),
+ fcoff ? slbt_coff_qsort_syminfo_cmp : slbt_qsort_syminfo_cmp);
+
+ /* yay */
+ return 0;
+}
+
+slbt_hidden int slbt_ar_update_syminfo(
+ struct slbt_archive_ctx * actx)
+{
+ return slbt_ar_update_syminfo_impl(actx,(-1));
+}
+
+slbt_hidden int slbt_ar_update_syminfo_ex(
+ struct slbt_archive_ctx * actx,
+ int fdout)
+{
+ return slbt_ar_update_syminfo_impl(actx,fdout);
+}
diff --git a/src/arbits/slbt_armap_bsd_32.c b/src/arbits/slbt_armap_bsd_32.c
new file mode 100644
index 0000000..ee94b70
--- /dev/null
+++ b/src/arbits/slbt_armap_bsd_32.c
@@ -0,0 +1,157 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_ar_parse_primary_armap_bsd_32(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * m)
+
+{
+ struct ar_raw_armap_bsd_32 * armap;
+ struct ar_meta_member_info * memberp;
+ struct ar_meta_armap_common_32 *armapref;
+ struct ar_meta_armap_ref_32 * symrefs;
+ uint32_t idx;
+ uint32_t uref;
+ uint32_t attr;
+ uint32_t nsyms;
+ uint32_t nstrs;
+ uint32_t sizeofrefs_le;
+ uint32_t sizeofrefs_be;
+ uint32_t sizeofrefs;
+ uint32_t sizeofstrs;
+ const char * ch;
+ const char * cap;
+ unsigned char * uch;
+ unsigned char (*mark)[0x04];
+
+ armap = &m->armaps.armap_bsd_32;
+ memberp = m->memberv[0];
+
+ mark = memberp->ar_object_data;
+
+ armap->ar_size_of_refs = mark;
+ uch = *mark++;
+
+ armap->ar_first_name_offset = mark;
+
+ sizeofrefs_le = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+ sizeofrefs_be = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+
+ if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) {
+ sizeofrefs = sizeofrefs_le;
+ attr = AR_ARMAP_ATTR_LE_32;
+
+ } else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) {
+ sizeofrefs = sizeofrefs_be;
+ attr = AR_ARMAP_ATTR_BE_32;
+ } else {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS);
+ }
+
+ nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_32);
+ mark += (sizeofrefs / sizeof(*mark));
+
+ armap->ar_size_of_strs = mark;
+ uch = *mark++;
+
+ sizeofstrs = (attr == AR_ARMAP_ATTR_LE_32)
+ ? (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]
+ : (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+
+ if (sizeofstrs > memberp->ar_object_size - 2*sizeof(*mark) - sizeofrefs)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_STRS);
+
+ m->symstrs = (const char *)mark;
+
+ cap = m->symstrs;
+ cap += sizeofstrs;
+
+ if ((cap == m->symstrs) && nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (nsyms && !m->symstrs[0])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) {
+ if (!ch[0] && !ch[-1] && (nstrs < nsyms))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!ch[0] && ch[-1] && (nstrs < nsyms))
+ nstrs++;
+ }
+
+ if (nstrs != nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(m->armaps.armap_symrefs_32 = calloc(nsyms + 1,sizeof(*symrefs))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ mark = armap->ar_first_name_offset;
+ symrefs = m->armaps.armap_symrefs_32;
+
+ for (idx=0; idx<nsyms; idx++) {
+ uch = *mark++;
+
+ uref = (attr == AR_ARMAP_ATTR_BE_32)
+ ? (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]
+ : (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+
+ symrefs[idx].ar_name_offset = uref;
+
+ uch = *mark++;
+
+ uref = (attr == AR_ARMAP_ATTR_BE_32)
+ ? (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]
+ : (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+
+ symrefs[idx].ar_member_offset = uref;
+ }
+
+ armap->ar_string_table = m->symstrv;
+
+ armapref = &m->armaps.armap_common_32;
+ armapref->ar_member = memberp;
+ armapref->ar_symrefs = symrefs;
+ armapref->ar_armap_bsd = armap;
+ armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr;
+ armapref->ar_num_of_symbols = nsyms;
+ armapref->ar_size_of_refs = sizeofrefs;
+ armapref->ar_size_of_strs = sizeofstrs;
+ armapref->ar_string_table = m->symstrs;
+
+ m->armaps.armap_nsyms = nsyms;
+
+ m->armeta.a_armap_primary.ar_armap_common_32 = armapref;
+
+ return 0;
+}
diff --git a/src/arbits/slbt_armap_bsd_64.c b/src/arbits/slbt_armap_bsd_64.c
new file mode 100644
index 0000000..8f214b9
--- /dev/null
+++ b/src/arbits/slbt_armap_bsd_64.c
@@ -0,0 +1,174 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_ar_parse_primary_armap_bsd_64(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * m)
+{
+ struct ar_raw_armap_bsd_64 * armap;
+ struct ar_meta_member_info * memberp;
+ struct ar_meta_armap_common_64 *armapref;
+ struct ar_meta_armap_ref_64 * symrefs;
+ uint64_t idx;
+ uint64_t uref_hi;
+ uint64_t uref_lo;
+ uint32_t attr;
+ uint64_t u64_lo;
+ uint64_t u64_hi;
+ uint64_t nsyms;
+ uint64_t nstrs;
+ uint64_t sizeofrefs_le;
+ uint64_t sizeofrefs_be;
+ uint64_t sizeofrefs;
+ uint64_t sizeofstrs;
+ const char * ch;
+ const char * cap;
+ unsigned char * uch;
+ unsigned char (*mark)[0x08];
+
+ armap = &m->armaps.armap_bsd_64;
+ memberp = m->memberv[0];
+
+ mark = memberp->ar_object_data;
+
+ armap->ar_size_of_refs = mark;
+ uch = *mark++;
+
+ armap->ar_first_name_offset = mark;
+
+ u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+ u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
+
+ sizeofrefs_le = u64_lo + (u64_hi << 32);
+
+ u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+
+ sizeofrefs_be = (u64_hi << 32) + u64_lo;
+
+ if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) {
+ sizeofrefs = sizeofrefs_le;
+ attr = AR_ARMAP_ATTR_LE_64;
+
+ } else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) {
+ sizeofrefs = sizeofrefs_be;
+ attr = AR_ARMAP_ATTR_BE_64;
+ } else {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS);
+ }
+
+ nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_64);
+ mark += (sizeofrefs / sizeof(*mark));
+
+ armap->ar_size_of_strs = mark;
+ uch = *mark++;
+
+ if (attr == AR_ARMAP_ATTR_LE_64) {
+ u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+ u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
+ } else {
+ u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+ }
+
+ sizeofstrs = u64_lo + (u64_hi << 32);
+ m->symstrs = (const char *)mark;
+
+ cap = m->symstrs;
+ cap += sizeofstrs;
+
+ if ((cap == m->symstrs) && nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (nsyms && !m->symstrs[0])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) {
+ if (!ch[0] && !ch[-1] && (nstrs < nsyms))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!ch[0] && ch[-1] && (nstrs < nsyms))
+ nstrs++;
+ }
+
+ if (nstrs != nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(m->armaps.armap_symrefs_64 = calloc(nsyms + 1,sizeof(*symrefs))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ mark = armap->ar_first_name_offset;
+ symrefs = m->armaps.armap_symrefs_64;
+
+ for (idx=0; idx<nsyms; idx++) {
+ uch = *mark++;
+
+ if (attr == AR_ARMAP_ATTR_BE_64) {
+ uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+ } else {
+ uref_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+ uref_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
+ }
+
+ symrefs[idx].ar_name_offset = (uref_hi << 32) + uref_lo;
+
+ uch = *mark++;
+
+ if (attr == AR_ARMAP_ATTR_BE_64) {
+ uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+ } else {
+ uref_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
+ uref_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
+ }
+
+ symrefs[idx].ar_member_offset = (uref_hi << 32) + uref_lo;
+ }
+
+ armap->ar_string_table = m->symstrv;
+
+ armapref = &m->armaps.armap_common_64;
+ armapref->ar_member = memberp;
+ armapref->ar_symrefs = symrefs;
+ armapref->ar_armap_bsd = armap;
+ armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr;
+ armapref->ar_num_of_symbols = nsyms;
+ armapref->ar_size_of_refs = sizeofrefs;
+ armapref->ar_size_of_strs = sizeofstrs;
+ armapref->ar_string_table = m->symstrs;
+
+ m->armaps.armap_nsyms = nsyms;
+
+ m->armeta.a_armap_primary.ar_armap_common_64 = armapref;
+
+ return 0;
+}
diff --git a/src/arbits/slbt_armap_sysv_32.c b/src/arbits/slbt_armap_sysv_32.c
new file mode 100644
index 0000000..bc5a0d5
--- /dev/null
+++ b/src/arbits/slbt_armap_sysv_32.c
@@ -0,0 +1,120 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_ar_parse_primary_armap_sysv_32(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * m)
+{
+ struct ar_raw_armap_sysv_32 * armap;
+ struct ar_meta_member_info * memberp;
+ struct ar_meta_armap_common_32 *armapref;
+ struct ar_meta_armap_ref_32 * symrefs;
+ uint32_t idx;
+ uint32_t uref;
+ uint32_t nsyms;
+ uint32_t nstrs;
+ const char * ch;
+ const char * cap;
+ unsigned char * uch;
+ unsigned char (*mark)[0x04];
+
+ armap = &m->armaps.armap_sysv_32;
+ memberp = m->memberv[0];
+
+ mark = memberp->ar_object_data;
+
+ armap->ar_num_of_syms = mark;
+ uch = *mark++;
+
+ armap->ar_first_ref_offset = mark;
+
+ nsyms = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ mark += nsyms;
+
+ if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark))))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS);
+
+ m->symstrs = (const char *)mark;
+
+ cap = memberp->ar_object_data;
+ cap += memberp->ar_object_size;
+
+ if ((cap == m->symstrs) && nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (nsyms && !m->symstrs[0])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) {
+ if (!ch[0] && !ch[-1] && (nstrs < nsyms))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!ch[0] && ch[-1])
+ nstrs++;
+ }
+
+ if (nstrs != nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (cap[-1])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(m->armaps.armap_symrefs_32 = calloc(nsyms + 1,sizeof(*symrefs))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ mark = armap->ar_first_ref_offset;
+ symrefs = m->armaps.armap_symrefs_32;
+
+ for (idx=0,uch=*mark; idx<nsyms; idx++,uch=*++mark) {
+ uref = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ symrefs[idx].ar_member_offset = uref;
+ }
+
+ armap->ar_string_table = m->symstrv;
+
+ armapref = &m->armaps.armap_common_32;
+ armapref->ar_member = memberp;
+ armapref->ar_symrefs = symrefs;
+ armapref->ar_armap_sysv = armap;
+ armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_32;
+ armapref->ar_num_of_symbols = nsyms;
+ armapref->ar_size_of_refs = nsyms * sizeof(*mark);
+ armapref->ar_size_of_strs = cap - m->symstrs;
+ armapref->ar_string_table = m->symstrs;
+
+ m->armaps.armap_nsyms = nsyms;
+
+ m->armeta.a_armap_primary.ar_armap_common_32 = armapref;
+
+ return 0;
+}
diff --git a/src/arbits/slbt_armap_sysv_64.c b/src/arbits/slbt_armap_sysv_64.c
new file mode 100644
index 0000000..961ee20
--- /dev/null
+++ b/src/arbits/slbt_armap_sysv_64.c
@@ -0,0 +1,128 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_visibility_impl.h"
+
+slbt_hidden int slbt_ar_parse_primary_armap_sysv_64(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * m)
+{
+ struct ar_raw_armap_sysv_64 * armap;
+ struct ar_meta_member_info * memberp;
+ struct ar_meta_armap_common_64 *armapref;
+ struct ar_meta_armap_ref_64 * symrefs;
+ uint64_t idx;
+ uint64_t uref_hi;
+ uint64_t uref_lo;
+ uint64_t nsyms_hi;
+ uint64_t nsyms_lo;
+ uint64_t nsyms;
+ uint64_t nstrs;
+ const char * ch;
+ const char * cap;
+ unsigned char * uch;
+ unsigned char (*mark)[0x08];
+
+ armap = &m->armaps.armap_sysv_64;
+ memberp = m->memberv[0];
+
+ mark = memberp->ar_object_data;
+
+ armap->ar_num_of_syms = mark;
+ uch = *mark++;
+
+ armap->ar_first_ref_offset = mark;
+
+ nsyms_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ nsyms_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+
+ nsyms = (nsyms_hi << 32) + nsyms_lo;
+ mark += nsyms;
+
+ if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark))))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS);
+
+ m->symstrs = (const char *)mark;
+
+ cap = memberp->ar_object_data;
+ cap += memberp->ar_object_size;
+
+ if ((cap == m->symstrs) && nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (nsyms && !m->symstrs[0])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ for (ch=&m->symstrs[1],nstrs=0; ch<cap; ch++) {
+ if (!ch[0] && !ch[-1] && (nstrs < nsyms))
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!ch[0] && ch[-1])
+ nstrs++;
+ }
+
+ if (nstrs != nsyms)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (cap[-1])
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
+
+ if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(m->armaps.armap_symrefs_64 = calloc(nsyms + 1,sizeof(*symrefs))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ mark = armap->ar_first_ref_offset;
+ symrefs = m->armaps.armap_symrefs_64;
+
+ for (idx=0,uch=*mark; idx<nsyms; idx++,uch=*++mark) {
+ uref_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
+ uref_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
+
+ symrefs[idx].ar_member_offset = (uref_hi << 32) + uref_lo;
+ }
+
+ armap->ar_string_table = m->symstrv;
+
+ armapref = &m->armaps.armap_common_64;
+ armapref->ar_member = memberp;
+ armapref->ar_symrefs = symrefs;
+ armapref->ar_armap_sysv = armap;
+ armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_64;
+ armapref->ar_num_of_symbols = nsyms;
+ armapref->ar_size_of_refs = nsyms * sizeof(*mark);
+ armapref->ar_size_of_strs = cap - m->symstrs;
+ armapref->ar_string_table = m->symstrs;
+
+ m->armaps.armap_nsyms = nsyms;
+
+ m->armeta.a_armap_primary.ar_armap_common_64 = armapref;
+
+ return 0;
+}