diff options
Diffstat (limited to 'src/logic/linkcmd/slbt_linkcmd_argv.c')
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_argv.c | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/src/logic/linkcmd/slbt_linkcmd_argv.c b/src/logic/linkcmd/slbt_linkcmd_argv.c new file mode 100644 index 0000000..013317f --- /dev/null +++ b/src/logic/linkcmd/slbt_linkcmd_argv.c @@ -0,0 +1,1127 @@ +/*******************************************************************/ +/* 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 <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> + +#include <slibtool/slibtool.h> +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_spawn_impl.h" +#include "slibtool_linkcmd_impl.h" +#include "slibtool_mapfile_impl.h" +#include "slibtool_metafile_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_symlink_impl.h" +#include "slibtool_readlink_impl.h" +#include "slibtool_visibility_impl.h" +#include "slibtool_ar_impl.h" + + +static const char * slbt_ar_self_dlunit = "@PROGRAM@"; + +static int slbt_linkcmd_exit( + struct slbt_deps_meta * depsmeta, + int ret) +{ + if (depsmeta->altv) + free(depsmeta->altv); + + if (depsmeta->args) + free(depsmeta->args); + + return ret; +} + + +static int slbt_emit_fdwrap_amend_dl_path( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + struct slbt_deps_meta * depsmeta, + const char * fmt, + ...) +{ + va_list ap; + char * buf; + int cnt; + char dlpathbuf[2048]; + int fdwrap; + const char * fdwrap_fmt; + int size; + + va_start(ap,fmt); + + size = sizeof(dlpathbuf); + + buf = ((cnt = vsnprintf(dlpathbuf,size,fmt,ap)) < size) + ? dlpathbuf : malloc((size = cnt + 1)); + + va_end(ap); + + if (buf == dlpathbuf) { + (void)0; + + } else if (buf) { + va_start(ap,fmt); + vsprintf(buf,fmt,ap); + va_end(ap); + + } else { + return slbt_linkcmd_exit( + depsmeta, + SLBT_SYSTEM_ERROR(dctx,0)); + } + + if ((fdwrap = slbt_exec_get_fdwrapper(ectx)) >= 0) { + if (buf[0] == '/') { + fdwrap_fmt = + "DL_PATH=\"${DL_PATH}${COLON}%s\"\n" + "COLON=':'\n\n"; + } else { + fdwrap_fmt = + "DL_PATH=\"${DL_PATH}${COLON}${DL_PATH_FIXUP}%s\"\n" + "COLON=':'\n\n"; + } + + if (slbt_dprintf(fdwrap,fdwrap_fmt,buf) < 0) { + return slbt_linkcmd_exit( + depsmeta, + SLBT_SYSTEM_ERROR(dctx,0)); + } + } + + return 0; +} + + +slbt_hidden bool slbt_adjust_object_argument( + char * arg, + bool fpic, + bool fany, + int fdcwd) +{ + char * slash; + char * dot; + char base[PATH_MAX]; + + if (*arg == '-') + return false; + + /* object argument: foo.lo or foo.o */ + if (!(dot = strrchr(arg,'.'))) + return false; + + if ((dot[1]=='l') && (dot[2]=='o') && !dot[3]) { + dot[1] = 'o'; + dot[2] = 0; + + } else if ((dot[1]=='o') && !dot[2]) { + (void)0; + + } else { + return false; + } + + /* foo.o requested and is present? */ + if (!fpic && !faccessat(fdcwd,arg,0,0)) + return true; + + /* .libs/foo.o */ + if ((slash = strrchr(arg,'/'))) + slash++; + else + slash = arg; + + if (slbt_snprintf(base,sizeof(base), + "%s",slash) < 0) + return false; + + sprintf(slash,".libs/%s",base); + + if (!faccessat(fdcwd,arg,0,0)) + return true; + + /* foo.o requested and neither is present? */ + if (!fpic) { + strcpy(slash,base); + return true; + } + + /* .libs/foo.o explicitly requested and is not present? */ + if (!fany) + return true; + + /* use foo.o in place of .libs/foo.o */ + strcpy(slash,base); + + if (faccessat(fdcwd,arg,0,0)) + sprintf(slash,".libs/%s",base); + + return true; +} + + +slbt_hidden bool slbt_adjust_wrapper_argument( + char * arg, + bool fpic, + const char * suffix) +{ + char * slash; + char * dot; + char base[PATH_MAX]; + + if (*arg == '-') + return false; + + if (!(dot = strrchr(arg,'.'))) + return false; + + if (strcmp(dot,".la")) + return false; + + if (fpic) { + if ((slash = strrchr(arg,'/'))) + slash++; + else + slash = arg; + + if (slbt_snprintf(base,sizeof(base), + "%s",slash) < 0) + return false; + + sprintf(slash,".libs/%s",base); + dot = strrchr(arg,'.'); + } + + strcpy(dot,suffix); + return true; +} + + +slbt_hidden int slbt_adjust_linker_argument( + const struct slbt_driver_ctx * dctx, + char * arg, + char ** xarg, + bool fpic, + const char * dsosuffix, + const char * arsuffix, + struct slbt_deps_meta * depsmeta) +{ + int fdcwd; + int fdlib; + char * slash; + char * dot; + char base[PATH_MAX]; + + /* argv switch or non-library input argument? */ + if (*arg == '-') + return 0; + + if (!(dot = strrchr(arg,'.'))) + return 0; + + /* explicit .a input argument? */ + if (!(strcmp(dot,arsuffix))) { + *xarg = arg; + return slbt_get_deps_meta(dctx,arg,1,depsmeta); + } + + /* explicit .so input argument? */ + if (!(strcmp(dot,dsosuffix))) + return slbt_get_deps_meta(dctx,arg,1,depsmeta); + + /* not an .la library? */ + if (strcmp(dot,".la")) + return 0; + + /* .la file, associated .deps located under .libs */ + if ((slash = strrchr(arg,'/'))) { + slash++; + } else { + slash = arg; + } + + if (slbt_snprintf(base,sizeof(base), + "%s",slash) < 0) + return 0; + + sprintf(slash,".libs/%s",base); + dot = strrchr(arg,'.'); + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* .a preferred but a.disabled present? */ + sprintf(dot,"%s",arsuffix); + + if (slbt_symlink_is_a_placeholder(fdcwd,arg)) + fpic = true; + + /* shared library dependency? */ + if (fpic) { + sprintf(dot,"%s",dsosuffix); + + if (slbt_symlink_is_a_placeholder(fdcwd,arg)) { + sprintf(dot,"%s",arsuffix); + + } else if ((fdlib = openat(fdcwd,arg,O_RDONLY)) >= 0) { + close(fdlib); + + } else { + sprintf(dot,"%s",arsuffix); + } + + return slbt_get_deps_meta(dctx,arg,0,depsmeta); + } + + /* input archive */ + sprintf(dot,"%s",arsuffix); + return slbt_get_deps_meta(dctx,arg,0,depsmeta); +} + + +slbt_hidden int slbt_exec_link_adjust_argument_vector( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + struct slbt_deps_meta * depsmeta, + const char * cwd, + bool flibrary) +{ + int fd; + int fdcwd; + char ** carg; + char ** aarg; + char * slash; + char * mark; + char * darg; + char * dot; + char * base; + char * dpath; + int argc; + char arg[PATH_MAX]; + char lib[PATH_MAX]; + char depdir [PATH_MAX]; + char rpathdir[PATH_MAX]; + char rpathlnk[PATH_MAX]; + struct stat st; + size_t size; + size_t dlen; + struct slbt_map_info * mapinfo = 0; + bool fwholearchive = false; + int ret; + + for (argc=0,carg=ectx->cargv; *carg; carg++) + argc++; + + if (!(depsmeta->args = calloc(1,depsmeta->infolen))) + return SLBT_SYSTEM_ERROR(dctx,0); + + argc *= 3; + argc += depsmeta->depscnt; + + if (!(depsmeta->altv = calloc(argc,sizeof(char *)))) + return slbt_linkcmd_exit( + depsmeta, + SLBT_SYSTEM_ERROR(dctx,0)); + + fdcwd = slbt_driver_fdcwd(dctx); + + carg = ectx->cargv; + aarg = depsmeta->altv; + darg = depsmeta->args; + size = depsmeta->infolen; + + for (; *carg; ) { + dpath = 0; + + if (!strcmp(*carg,"-Wl,--whole-archive")) + fwholearchive = true; + else if (!strcmp(*carg,"-Wl,--no-whole-archive")) + fwholearchive = false; + + + + /* output annotation */ + if (carg == ectx->lout[0]) { + ectx->mout[0] = &aarg[0]; + ectx->mout[1] = &aarg[1]; + } + + /* argument translation */ + mark = *carg; + + if ((mark[0] == '-') && (mark[1] == 'L')) { + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s",&mark[2])) < 0) + return ret; + + *aarg++ = *carg++; + + } else if (**carg == '-') { + *aarg++ = *carg++; + + } else if (!(dot = strrchr(*carg,'.'))) { + *aarg++ = *carg++; + + } else if (ectx->xargv[carg - ectx->cargv]) { + *aarg++ = *carg++; + + } else if (!(strcmp(dot,".a"))) { + if (flibrary && !fwholearchive) { + strcpy(lib,*carg); + dot = strrchr(lib,'.'); + strcpy(dot,".lai"); + + if ((fd = openat(fdcwd,lib,O_RDONLY,0)) < 0) + *aarg++ = "-Wl,--whole-archive"; + } + + dpath = lib; + sprintf(lib,"%s.slibtool.deps",*carg); + *aarg++ = *carg++; + + if (flibrary && !fwholearchive) { + if (fd < 0) { + *aarg++ = "-Wl,--no-whole-archive"; + } else { + close(fd); + } + } + + } else if (strcmp(dot,dctx->cctx->settings.dsosuffix)) { + *aarg++ = *carg++; + + } else if (carg == ectx->lout[1]) { + /* ^^^hoppla^^^ */ + *aarg++ = *carg++; + } else { + /* -rpath */ + sprintf(rpathlnk,"%s.slibtool.rpath",*carg); + + if (!fstatat(fdcwd,rpathlnk,&st,AT_SYMLINK_NOFOLLOW)) { + if (slbt_readlinkat( + fdcwd, + rpathlnk, + rpathdir, + sizeof(rpathdir))) + return slbt_linkcmd_exit( + depsmeta, + SLBT_SYSTEM_ERROR(dctx,rpathlnk)); + + sprintf(darg,"-Wl,%s",rpathdir); + *aarg++ = "-Wl,-rpath"; + *aarg++ = darg; + darg += strlen(darg); + darg++; + } + + dpath = lib; + sprintf(lib,"%s.slibtool.deps",*carg); + + /* account for {'-','L','-','l'} */ + if (slbt_snprintf(arg, + sizeof(arg) - 4, + "%s",*carg) < 0) + return slbt_linkcmd_exit( + depsmeta, + SLBT_BUFFER_ERROR(dctx)); + + if ((slash = strrchr(arg,'/'))) { + sprintf(*carg,"-L%s",arg); + + mark = strrchr(*carg,'/'); + *mark = 0; + *slash = 0; + + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s%s%s", + ((arg[0] == '/') ? "" : cwd), + ((arg[0] == '/') ? "" : "/"), + arg)) < 0) { + return ret; + } + + dlen = strlen(dctx->cctx->settings.dsoprefix); + + /* -module? (todo: non-portable usage, display warning) */ + if (strncmp(++slash,dctx->cctx->settings.dsoprefix,dlen)) { + *--slash = '/'; + strcpy(*carg,arg); + *aarg++ = *carg++; + } else { + *aarg++ = *carg++; + *aarg++ = ++mark; + + slash += dlen; + + sprintf(mark,"-l%s",slash); + dot = strrchr(mark,'.'); + *dot = 0; + } + } else { + *aarg++ = *carg++; + } + } + + if (dpath && !fstatat(fdcwd,dpath,&st,0)) { + if (!(mapinfo = slbt_map_file( + fdcwd,dpath, + SLBT_MAP_INPUT))) + return slbt_linkcmd_exit( + depsmeta, + SLBT_SYSTEM_ERROR(dctx,dpath)); + + if (!(strncmp(lib,".libs/",6))) { + *aarg++ = "-L.libs"; + lib[1] = 0; + } else if ((base = strrchr(lib,'/'))) { + if (base - lib == 5) { + if (!(strncmp(&base[-5],".libs/",6))) + base -= 4; + + } else if (base - lib >= 6) { + if (!(strncmp(&base[-6],"/.libs/",7))) + base -= 6; + } + + *base = 0; + } else { + lib[0] = '.'; + lib[1] = 0; + } + + while (mapinfo->mark < mapinfo->cap) { + if (slbt_mapped_readline(dctx,mapinfo,darg,size)) + return slbt_linkcmd_exit( + depsmeta, + SLBT_NESTED_ERROR(dctx)); + + if (darg[0] != '#') { + *aarg++ = darg; + } + + mark = darg; + dlen = strlen(darg); + size -= dlen; + darg += dlen; + darg[-1] = 0; + + /* handle -L... and ::... as needed */ + if ((mark[0] == '-') + && (mark[1] == 'L') + && (mark[2] != '/')) { + if (strlen(mark) >= sizeof(depdir) - 1) + return slbt_linkcmd_exit( + depsmeta, + SLBT_BUFFER_ERROR(dctx)); + + darg = mark; + strcpy(depdir,&mark[2]); + sprintf(darg,"-L%s/%s",lib,depdir); + + darg += strlen(darg); + darg++; + + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s/%s",lib,depdir)) < 0) + return ret; + + } else if ((mark[0] == ':') && (mark[1] == ':')) { + if (strlen(mark) >= sizeof(depdir) - 1) + return slbt_linkcmd_exit( + depsmeta, + SLBT_BUFFER_ERROR(dctx)); + + darg = mark; + strcpy(depdir,&mark[2]); + + sprintf(darg,"%s/%s", + mark[2] == '/' ? "" : lib, + depdir); + + darg += strlen(darg); + darg++; + + } else if ((mark[0] == '-') && (mark[1] == 'L')) { + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s",&mark[2])) < 0) + return ret; + } + } + } + + if (mapinfo) { + slbt_unmap_file(mapinfo); + mapinfo = 0; + } + } + + if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC) + if (!slbt_host_objfmt_is_coff(dctx)) + *aarg++ = "-Wl,--export-dynamic"; + + return 0; +} + + +static int slbt_exec_link_remove_file( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * target) +{ + int fdcwd; + + (void)ectx; + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* remove target (if any) */ + if (!unlinkat(fdcwd,target,0) || (errno == ENOENT)) + return 0; + + return SLBT_SYSTEM_ERROR(dctx,0); +} + + +static int slbt_exec_link_create_expsyms_archive( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + char ** lobjv, + char ** cnvlv, + char (*arname)[PATH_MAX]) +{ + int ret; + char * dot; + char ** argv; + char ** aarg; + char ** parg; + struct slbt_archive_ctx * arctx; + char ** ectx_argv; + char * ectx_program; + char output [PATH_MAX]; + char program[PATH_MAX]; + + /* output */ + if (slbt_snprintf(output,sizeof(output), + "%s",ectx->mapfilename) < 0) + return SLBT_BUFFER_ERROR(dctx); + + if (!(dot = strrchr(output,'.'))) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + + /* .expsyms.xxx --> .expsyms.a */ + dot[1] = 'a'; + dot[2] = '\0'; + + if (arname) + strcpy(*arname,output); + + /* tool-specific argument vector */ + argv = (slbt_get_driver_ictx(dctx))->host.ar_argv; + + /* ar alternate argument vector */ + if (!argv) + if (slbt_snprintf(program,sizeof(program), + "%s",dctx->cctx->host.ar) < 0) + return SLBT_BUFFER_ERROR(dctx); + + /* ar command argument vector */ + aarg = lobjv; + + if ((parg = argv)) { + for (; *parg; ) + *aarg++ = *parg++; + } else { + *aarg++ = program; + } + + *aarg++ = "-crs"; + *aarg++ = output; + + ectx_argv = ectx->argv; + ectx_program = ectx->program; + + ectx->argv = lobjv; + ectx->program = ectx->argv[0]; + + /* step output */ + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) + if (slbt_output_link(ectx)) + return SLBT_NESTED_ERROR(dctx); + + /* remove old archive as needed */ + if (slbt_exec_link_remove_file(dctx,ectx,output)) + return SLBT_NESTED_ERROR(dctx); + + /* ar spawn */ + if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) { + return SLBT_SPAWN_ERROR(dctx); + + } else if (ectx->exitcode) { + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_ERROR); + } + + /* restore link command ectx */ + ectx->argv = ectx_argv; + ectx->program = ectx_program; + + /* input objects associated with .la archives */ + for (parg=cnvlv; *parg; parg++) + if (slbt_util_import_archive(ectx,output,*parg)) + return SLBT_NESTED_ERROR(dctx); + + /* do the thing */ + if (slbt_ar_get_archive_ctx(dctx,output,&arctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* .expsyms.a --> .exp */ + if ((*dot = '\0'), !(dot = strrchr(output,'.'))) { + slbt_ar_free_archive_ctx(arctx); + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + + dot[1] = 'e'; + dot[2] = 'x'; + dot[3] = 'p'; + dot[4] = '\0'; + + /* symfile */ + if (dctx->cctx->expsyms) { + struct slbt_symlist_ctx * sctx; + sctx = (slbt_get_exec_ictx(ectx))->sctx; + + ret = slbt_util_create_symfile( + sctx,output,0644); + } else { + ret = slbt_ar_create_symfile( + arctx->meta, + output, + 0644); + } + + /* mapfile */ + if ((ret == 0) && (dctx->cctx->regex)) { + ret = slbt_ar_create_mapfile( + arctx->meta, + ectx->mapfilename, + 0644); + } + + slbt_ar_free_archive_ctx(arctx); + + return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0; +} + + +slbt_hidden int slbt_exec_link_finalize_argument_vector( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx) +{ + size_t nargs; + char * sargv[1024]; + char ** sargvbuf; + char ** base; + char ** parg; + char ** pcap; + char ** argv; + char ** mark; + char ** aarg; + char ** oarg; + char ** lobj; + char ** cnvl; + char ** larg; + char ** darg; + char ** earg; + char ** rarg; + char ** aargv; + char ** oargv; + char ** lobjv; + char ** cnvlv; + char ** dlargv; + char ** cap; + char ** src; + char ** dst; + char * arg; + char * dot; + char * ccwrap; + char * program; + const char * arsuffix; + + /* vector size */ + base = ectx->argv; + arsuffix = dctx->cctx->settings.arsuffix; + + for (parg=base; *parg; parg++) + (void)0; + + if (dctx->cctx->regex) { + argv = (slbt_get_driver_ictx(dctx))->host.ar_argv; + + for (mark=argv; mark && *mark; mark++) + (void)0; + } else { + argv = 0; + mark = 0; + } + + /* buffer */ + if ((nargs = ((parg - base) + (mark - argv))) < 256) { + aargv = &sargv[0]; + oargv = &sargv[1*256]; + lobjv = &sargv[2*256]; + cnvlv = &sargv[3*256]; + sargvbuf = 0; + + parg = &sargv[0]; + pcap = &sargv[1024]; + + for (; parg<pcap; ) + *parg++ = 0; + + } else if (!(sargvbuf = calloc(4*(nargs+1),sizeof(char *)))) { + return SLBT_SYSTEM_ERROR(dctx,0); + + } else { + aargv = &sargvbuf[0]; + oargv = &sargvbuf[1*(nargs+1)]; + lobjv = &sargvbuf[2*(nargs+1)]; + cnvlv = &sargvbuf[3*(nargs+1)]; + } + + aarg = aargv; + oarg = oargv; + cnvl = cnvlv; + lobj = lobjv; + + /* -export-symbols-regex: lobjv in place: ar [arg] [arg] -crs <output> */ + if (dctx->cctx->regex && argv) + lobj += mark - argv + 2; + else + lobj += 3; + + /* (program name) */ + parg = &base[1]; + + /* split object args from all other args, record output */ + /* annotation, and remove redundant -l arguments; and */ + /* create additional vectors of all input objects as */ + /* convenience libraries for -export-symbols-regex. */ + for (; *parg; ) { + if (ectx->lout[0] == parg) { + ectx->lout[0] = &aarg[0]; + ectx->lout[1] = &aarg[1]; + } + + if (ectx->mout[0] == parg) { + ectx->mout[0] = &aarg[0]; + ectx->mout[1] = &aarg[1]; + } + + arg = *parg; + dot = strrchr(arg,'.'); + + /* object input argument? */ + if (dot && (!strcmp(dot,".o") || !strcmp(dot,".lo"))) { + *lobj++ = *parg; + *oarg++ = *parg++; + + /* --whole-archive input argument? */ + } else if ((arg[0] == '-') + && (arg[1] == 'W') + && (arg[2] == 'l') + && (arg[3] == ',') + && !strcmp(&arg[4],"--whole-archive") + && parg[1] && parg[2] + && !strcmp(parg[2],"-Wl,--no-whole-archive") + && (dot = strrchr(parg[1],'.')) + && !strcmp(dot,arsuffix)) { + *cnvl++ = parg[1]; + *oarg++ = *parg++; + *oarg++ = *parg++; + *oarg++ = *parg++; + + /* local archive input argument? */ + } else if (dot && !strcmp(dot,arsuffix)) { + *aarg++ = *parg++; + + /* -l argument? */ + } else if ((parg[0][0] == '-') && (parg[0][1] == 'l')) { + /* find the previous occurence of this -l argument */ + for (rarg=0, larg=&aarg[-1]; !rarg && (larg>=aargv); larg--) + if (!strcmp(*larg,*parg)) + rarg = larg; + + /* first occurence of this specific -l argument? */ + if (!rarg) { + *aarg++ = *parg++; + + } else { + larg = rarg; + + /* if all -l arguments following the previous */ + /* occurence had already appeared before the */ + /* previous argument, then the current */ + /* occurence is (possibly) redundant. */ + + for (darg=&larg[1]; rarg && darg<aarg; darg++) { + /* only test -l arguments */ + if ((darg[0][0] == '-') && (darg[0][1] == 'l')) { + for (rarg=0, earg=aargv; !rarg && earg<larg; earg++) + if (!strcmp(*earg,*darg)) + rarg = darg; + } + } + + /* any archive (.a) input arguments between the */ + /* current occurrence and the previous one? */ + for (darg=&larg[1]; rarg && darg<aarg; darg++) + if ((dot = strrchr(*darg,'.'))) + if (!(strcmp(dot,arsuffix))) + rarg = 0; + + /* final verdict: repeated -l argument? */ + if (rarg) { + parg++; + + } else { + *aarg++ = *parg++; + } + } + + /* -L argument? */ + } else if ((parg[0][0] == '-') && (parg[0][1] == 'L')) { + /* find a previous occurence of this -L argument */ + for (rarg=0, larg=aargv; !rarg && (larg<aarg); larg++) + if (!strcmp(*larg,*parg)) + rarg = larg; + + /* repeated -L argument? */ + if (rarg) { + parg++; + } else { + *aarg++ = *parg++; + } + + /* dlsyms vtable object must only be added once (see below) */ + } else if (!strcmp(*parg,"-dlpreopen")) { + parg++; + + /* placeholder argument? */ + } else if (!strncmp(*parg,"-USLIBTOOL_PLACEHOLDER_",23)) { + parg++; + + /* all other arguments */ + } else { + *aarg++ = *parg++; + } + } + + /* dlsyms vtable object inclusion */ + if (ectx->dlopenobj) + *oarg++ = ectx->dlopenobj; + + /* export-symbols-regex, proper dlpreopen support */ + if (dctx->cctx->libname) + if (slbt_exec_link_create_expsyms_archive( + dctx,ectx,lobjv,cnvlv,0) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* -dlpreopen self */ + if (dctx->cctx->drvflags & SLBT_DRIVER_DLPREOPEN_SELF) { + struct slbt_archive_ctx * arctx; + struct slbt_archive_ctx ** arctxv; + struct slbt_exec_ctx_impl * ictx; + char arname[PATH_MAX]; + + ictx = slbt_get_exec_ictx(ectx); + arctxv = ictx->dlactxv; + arctx = 0; + + /* add or repalce the archive context */ + for (; !arctx && *arctxv; ) + if (!strcmp(*arctxv[0]->path,slbt_ar_self_dlunit)) + arctx = *arctxv; + else + arctxv++; + + if (arctx) + slbt_ar_free_archive_ctx(arctx); + + if (slbt_exec_link_create_expsyms_archive( + dctx,ectx,lobjv,cnvlv,&arname) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (slbt_ar_get_archive_ctx(dctx,arname,arctxv) < 0) + return SLBT_NESTED_ERROR(dctx); + + arctx = *arctxv; + arctx->path = &slbt_ar_self_dlunit; + + if (slbt_ar_update_syminfo(arctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* regenerate the dlsyms vtable source */ + if (slbt_ar_create_dlsyms( + ictx->dlactxv, + ectx->dlunit, + ectx->dlopensrc, + 0644) < 0) + return SLBT_NESTED_ERROR(dctx); + } + + /* program name, ccwrap */ + if ((ccwrap = (char *)dctx->cctx->ccwrap)) { + base[1] = base[0]; + base[0] = ccwrap; + base++; + } + + /* join object args */ + src = oargv; + cap = oarg; + dst = &base[1]; + + for (; src<cap; ) + *dst++ = *src++; + + /* dlpreopen */ + if (ectx->dlpreopen) + *dst++ = ectx->dlpreopen; + + /* join all other args, eliminate no-op linker path args */ + src = aargv; + cap = aarg; + + for (; src<cap; ) { + if ((src[0][0] == '-') && (src[0][1] == 'L')) { + for (larg=0,rarg=src; *rarg && !larg; rarg++) + if ((rarg[0][0] == '-') && (rarg[0][1] == 'l')) + larg = rarg; + + if (larg) { + *dst++ = *src++; + } else { + src++; + } + } else { + *dst++ = *src++; + } + } + + /* properly null-terminate argv, accounting for redundant -l arguments */ + *dst = 0; + + /* output annotation */ + if (ectx->lout[0]) { + ectx->lout[0] = &base[1] + (oarg - oargv) + (ectx->lout[0] - aargv); + ectx->lout[1] = ectx->lout[0] + 1; + } + + if (ectx->mout[0]) { + ectx->mout[0] = &base[1] + (oarg - oargv) + (ectx->mout[0] - aargv); + ectx->mout[1] = ectx->mout[0] + 1; + } + + /* dlsyms vtable object compilation */ + if (ectx->dlopenobj) { + dlargv = (slbt_get_exec_ictx(ectx))->dlargv; + *dlargv = base[0]; + + src = aargv; + cap = aarg; + dst = &dlargv[1]; + + /* compile argv, based on the linkcmd argv */ + for (; src<cap; ) { + if ((src[0][0] == '-') && (src[0][1] == '-')) { + *dst++ = *src; + + } else if ((src[0][0] == '-') && (src[0][1] == 'L')) { + (void)0; + + } else if ((src[0][0] == '-') && (src[0][1] == 'l')) { + (void)0; + + } else if ((dot = strrchr(*src,'.')) && (dot[1] == 'a') && !dot[2]) { + (void)0; + + } else if ((src[0][0] == '-') && (src[0][1] == 'o')) { + src++; + + } else if ((src[0][0] == '-') && (src[0][1] == 'D')) { + if (!src[0][2]) + src++; + + } else if ((src[0][0] == '-') && (src[0][1] == 'U')) { + if (!src[0][2]) + src++; + + } else if ((src[0][0] == '-') && (src[0][1] == 'W')) { + if ((src[0][2] == 'a') && (src[0][3] == ',')) + *dst++ = *src; + + } else { + *dst++ = *src; + } + + src++; + } + + *dst++ = dctx->cctx->settings.picswitch + ? dctx->cctx->settings.picswitch + : *ectx->fpic; + + *dst++ = "-c"; + *dst++ = ectx->dlopensrc; + + *dst++ = "-o"; + *dst++ = ectx->dlopenobj; + + *dst++ = 0; + + /* nested compile step */ + program = ectx->program; + ectx->argv = dlargv; + ectx->program = dlargv[0]; + + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) + if (slbt_output_compile(ectx)) + return SLBT_NESTED_ERROR(dctx); + + if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if (ectx->exitcode) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_COMPILE_ERROR); + + ectx->argv = base; + ectx->program = program; + } + + /* all done */ + if (sargvbuf) + free(sargvbuf); + + return 0; +} |