From 3d55672811ed7f35d226ab714a5bd812729eb48b Mon Sep 17 00:00:00 2001 From: midipix Date: Feb 10 2024 04:33:07 +0000 Subject: link mode: move the argument vector logic to its own translation unit. --- diff --git a/project/common.mk b/project/common.mk index 971173d..e3ca463 100644 --- a/project/common.mk +++ b/project/common.mk @@ -28,6 +28,7 @@ API_SRCS = \ src/logic/slbt_exec_install.c \ src/logic/slbt_exec_link.c \ src/logic/slbt_exec_uninstall.c \ + src/logic/linkcmd/slbt_linkcmd_argv.c \ src/logic/linkcmd/slbt_linkcmd_deps.c \ src/output/slbt_output_config.c \ src/output/slbt_output_error.c \ diff --git a/src/internal/slibtool_linkcmd_impl.h b/src/internal/slibtool_linkcmd_impl.h index c2598f3..df5a731 100644 --- a/src/internal/slibtool_linkcmd_impl.h +++ b/src/internal/slibtool_linkcmd_impl.h @@ -21,4 +21,34 @@ int slbt_exec_link_create_dep_file( const char * libfilename, bool farchive); +bool slbt_adjust_object_argument( + char * arg, + bool fpic, + bool fany, + int fdcwd); + +bool slbt_adjust_wrapper_argument( + char * arg, + bool fpic); + +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 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 slbt_exec_link_finalize_argument_vector( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx); + #endif diff --git a/src/logic/linkcmd/slbt_linkcmd_argv.c b/src/logic/linkcmd/slbt_linkcmd_argv.c new file mode 100644 index 0000000..ec3b11e --- /dev/null +++ b/src/logic/linkcmd/slbt_linkcmd_argv.c @@ -0,0 +1,738 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2021 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_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" + + +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; +} + + +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; +} + + +bool slbt_adjust_wrapper_argument( + char * arg, + bool fpic) +{ + 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,".a"); + return true; +} + + +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]; + + if (*arg == '-') + return 0; + + if (!(dot = strrchr(arg,'.'))) + return 0; + + if (!(strcmp(dot,arsuffix))) { + *xarg = arg; + return slbt_get_deps_meta(dctx,arg,1,depsmeta); + } + + if (!(strcmp(dot,dsosuffix))) + return slbt_get_deps_meta(dctx,arg,1,depsmeta); + + if (strcmp(dot,".la")) + return 0; + + if (fpic) { + 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); + + /* 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); +} + + +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 * ldir; + 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; + 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 (mark[2]) { + ldir = &mark[2]; + } else { + *aarg++ = *carg++; + ldir = *carg; + } + + mark = ldir + strlen(ldir); + + if (mark[-1] == '/') + strcpy(mark,".libs"); + else + strcpy(mark,"/.libs"); + + if ((fd = openat(fdcwd,ldir,O_DIRECTORY,0)) < 0) + *mark = 0; + else { + close(fd); + + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s",ldir)) < 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) + *aarg++ = "-Wl,--whole-archive"; + + dpath = lib; + sprintf(lib,"%s.slibtool.deps",*carg); + *aarg++ = *carg++; + + if (flibrary && !fwholearchive) + *aarg++ = "-Wl,--no-whole-archive"; + + } 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)); + + *aarg++ = darg; + mark = darg; + + dlen = strlen(darg); + size -= dlen; + darg += dlen; + darg[-1] = 0; + + /* handle -L... 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] == 'L')) { + if ((ret = slbt_emit_fdwrap_amend_dl_path( + dctx,ectx,depsmeta, + "%s",&mark[2])) < 0) + return ret; + } + } + } + } + + if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC) + *aarg++ = "-Wl,--export-dynamic"; + + return 0; +} + + +int slbt_exec_link_finalize_argument_vector( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx) +{ + char * sargv[1024]; + char ** sargvbuf; + char ** base; + char ** parg; + char ** aarg; + char ** oarg; + char ** larg; + char ** darg; + char ** earg; + char ** rarg; + char ** aargv; + char ** oargv; + char ** cap; + char ** src; + char ** dst; + char * arg; + char * dot; + char * ccwrap; + const char * arsuffix; + + /* vector size */ + base = ectx->argv; + arsuffix = dctx->cctx->settings.arsuffix; + + for (parg=base; *parg; parg++) + (void)0; + + /* buffer */ + if (parg - base < 512) { + aargv = &sargv[0]; + oargv = &sargv[512]; + aarg = aargv; + oarg = oargv; + sargvbuf = 0; + + } else if (!(sargvbuf = calloc(2*(parg-base+1),sizeof(char *)))) { + return SLBT_SYSTEM_ERROR(dctx,0); + + } else { + aargv = &sargvbuf[0]; + oargv = &sargvbuf[parg-base+1]; + aarg = aargv; + oarg = oargv; + } + + /* (program name) */ + parg = &base[1]; + + /* split object args from all other args, record output */ + /* annotation, and remove redundant -l arguments */ + 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"))) { + *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)) { + *oarg++ = *parg++; + *oarg++ = *parg++; + *oarg++ = *parg++; + + /* local archive input argument? */ + } else if (dot && !strcmp(dot,arsuffix)) { + *oarg++ = *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 redundant. */ + + for (darg=&larg[1]; rarg && dargcctx->ccwrap)) { + base[1] = base[0]; + base[0] = ccwrap; + base++; + } + + /* join object args */ + src = oargv; + cap = oarg; + dst = &base[1]; + + for (; srclout[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; + } + + /* all done */ + if (sargvbuf) + free(sargvbuf); + + return 0; +} diff --git a/src/logic/slbt_exec_link.c b/src/logic/slbt_exec_link.c index cacbe44..c21af58 100644 --- a/src/logic/slbt_exec_link.c +++ b/src/logic/slbt_exec_link.c @@ -77,234 +77,6 @@ static int slbt_exec_link_exit( return ret; } -static 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; -} - -static bool slbt_adjust_wrapper_argument( - char * arg, - bool fpic) -{ - 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,".a"); - return true; -} - -static 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]; - - if (*arg == '-') - return 0; - - if (!(dot = strrchr(arg,'.'))) - return 0; - - if (!(strcmp(dot,arsuffix))) { - *xarg = arg; - return slbt_get_deps_meta(dctx,arg,1,depsmeta); - } - - if (!(strcmp(dot,dsosuffix))) - return slbt_get_deps_meta(dctx,arg,1,depsmeta); - - if (strcmp(dot,".la")) - return 0; - - if (fpic) { - 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); - - /* 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); -} - -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_exec_link_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_exec_link_exit( - depsmeta, - SLBT_SYSTEM_ERROR(dctx,0)); - } - } - - return 0; -} - static void slbt_emit_fdwrap_dl_path_fixup( char * cwd, char * dpfixup, @@ -337,473 +109,6 @@ static void slbt_emit_fdwrap_dl_path_fixup( strncat(dpfixup,"/",dpfixup_size-1); } -static 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 * ldir; - 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; - 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_exec_link_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 (mark[2]) { - ldir = &mark[2]; - } else { - *aarg++ = *carg++; - ldir = *carg; - } - - mark = ldir + strlen(ldir); - - if (mark[-1] == '/') - strcpy(mark,".libs"); - else - strcpy(mark,"/.libs"); - - if ((fd = openat(fdcwd,ldir,O_DIRECTORY,0)) < 0) - *mark = 0; - else { - close(fd); - - if ((ret = slbt_emit_fdwrap_amend_dl_path( - dctx,ectx,depsmeta, - "%s",ldir)) < 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) - *aarg++ = "-Wl,--whole-archive"; - - dpath = lib; - sprintf(lib,"%s.slibtool.deps",*carg); - *aarg++ = *carg++; - - if (flibrary && !fwholearchive) - *aarg++ = "-Wl,--no-whole-archive"; - - } 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_exec_link_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_exec_link_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_exec_link_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_exec_link_exit( - depsmeta, - SLBT_NESTED_ERROR(dctx)); - - *aarg++ = darg; - mark = darg; - - dlen = strlen(darg); - size -= dlen; - darg += dlen; - darg[-1] = 0; - - /* handle -L... as needed */ - if ((mark[0] == '-') - && (mark[1] == 'L') - && (mark[2] != '/')) { - if (strlen(mark) >= sizeof(depdir) - 1) - return slbt_exec_link_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] == 'L')) { - if ((ret = slbt_emit_fdwrap_amend_dl_path( - dctx,ectx,depsmeta, - "%s",&mark[2])) < 0) - return ret; - } - } - } - } - - if (dctx->cctx->drvflags & SLBT_DRIVER_EXPORT_DYNAMIC) - *aarg++ = "-Wl,--export-dynamic"; - - return 0; -} - -static int slbt_exec_link_finalize_argument_vector( - const struct slbt_driver_ctx * dctx, - struct slbt_exec_ctx * ectx) -{ - char * sargv[1024]; - char ** sargvbuf; - char ** base; - char ** parg; - char ** aarg; - char ** oarg; - char ** larg; - char ** darg; - char ** earg; - char ** rarg; - char ** aargv; - char ** oargv; - char ** cap; - char ** src; - char ** dst; - char * arg; - char * dot; - char * ccwrap; - const char * arsuffix; - - /* vector size */ - base = ectx->argv; - arsuffix = dctx->cctx->settings.arsuffix; - - for (parg=base; *parg; parg++) - (void)0; - - /* buffer */ - if (parg - base < 512) { - aargv = &sargv[0]; - oargv = &sargv[512]; - aarg = aargv; - oarg = oargv; - sargvbuf = 0; - - } else if (!(sargvbuf = calloc(2*(parg-base+1),sizeof(char *)))) { - return SLBT_SYSTEM_ERROR(dctx,0); - - } else { - aargv = &sargvbuf[0]; - oargv = &sargvbuf[parg-base+1]; - aarg = aargv; - oarg = oargv; - } - - /* (program name) */ - parg = &base[1]; - - /* split object args from all other args, record output */ - /* annotation, and remove redundant -l arguments */ - 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"))) { - *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)) { - *oarg++ = *parg++; - *oarg++ = *parg++; - *oarg++ = *parg++; - - /* local archive input argument? */ - } else if (dot && !strcmp(dot,arsuffix)) { - *oarg++ = *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 redundant. */ - - for (darg=&larg[1]; rarg && dargcctx->ccwrap)) { - base[1] = base[0]; - base[0] = ccwrap; - base++; - } - - /* join object args */ - src = oargv; - cap = oarg; - dst = &base[1]; - - for (; srclout[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; - } - - /* all done */ - if (sargvbuf) - free(sargvbuf); - - return 0; -} - static int slbt_exec_link_remove_file( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx,