summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sgs
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2009-09-18 09:00:12 -0600
committerAli Bahrami <Ali.Bahrami@Sun.COM>2009-09-18 09:00:12 -0600
commitcdcc71c09dccd8c66f98c710f068f0722fe6de56 (patch)
treebbdf9c159cf02355f3e1af18aeeb04ce56492787 /usr/src/cmd/sgs
parentd670ce0b8f4bf35907a3b851264a57e04d74d22d (diff)
downloadillumos-joyent-cdcc71c09dccd8c66f98c710f068f0722fe6de56.tar.gz
6850768 ld option to autogenerate wrappers/interposers similar to GNU ld --wrap
PSARC/2009/493 ld -z wrap option
Diffstat (limited to 'usr/src/cmd/sgs')
-rw-r--r--usr/src/cmd/sgs/include/debug.h3
-rw-r--r--usr/src/cmd/sgs/include/libld.h15
-rw-r--r--usr/src/cmd/sgs/libld/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/libld/common/_libld.h3
-rw-r--r--usr/src/cmd/sgs/libld/common/args.c27
-rw-r--r--usr/src/cmd/sgs/libld/common/ldmain.c3
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg7
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c42
-rw-r--r--usr/src/cmd/sgs/libld/common/util.c121
-rw-r--r--usr/src/cmd/sgs/libld/common/wrap.c131
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/liblddbg.msg1
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/llib-llddbg2
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/mapfile-vers4
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/syms.c10
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README2
15 files changed, 342 insertions, 33 deletions
diff --git a/usr/src/cmd/sgs/include/debug.h b/usr/src/cmd/sgs/include/debug.h
index 7de58465e2..d21f21bbaa 100644
--- a/usr/src/cmd/sgs/include/debug.h
+++ b/usr/src/cmd/sgs/include/debug.h
@@ -424,6 +424,7 @@ extern void Dbg_help(void);
#define Dbg_syms_spec_title Dbg64_syms_spec_title
#define Dbg_syms_updated Dbg64_syms_updated
#define Dbg_syms_up_title Dbg64_syms_up_title
+#define Dbg_syms_wrap Dbg64_syms_wrap
#define Dbg_util_call_array Dbg64_util_call_array
#define Dbg_util_call_fini Dbg64_util_call_fini
@@ -632,6 +633,7 @@ extern void Dbg_help(void);
#define Dbg_syms_spec_title Dbg32_syms_spec_title
#define Dbg_syms_updated Dbg32_syms_updated
#define Dbg_syms_up_title Dbg32_syms_up_title
+#define Dbg_syms_wrap Dbg32_syms_wrap
#define Dbg_util_call_array Dbg32_util_call_array
#define Dbg_util_call_fini Dbg32_util_call_fini
@@ -896,6 +898,7 @@ extern void Dbg_syms_sec_title(Lm_list *);
extern void Dbg_syms_spec_title(Lm_list *);
extern void Dbg_syms_updated(Ofl_desc *, Sym_desc *, const char *);
extern void Dbg_syms_up_title(Lm_list *);
+extern void Dbg_syms_wrap(Lm_list *, Word, const char *, const char *);
extern void Dbg_tls_modactivity(Lm_list *, void *, uint_t);
extern void Dbg_tls_static_block(Lm_list *, void *, ulong_t, ulong_t);
diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h
index 9e965feda2..b2188a91db 100644
--- a/usr/src/cmd/sgs/include/libld.h
+++ b/usr/src/cmd/sgs/include/libld.h
@@ -150,6 +150,20 @@ typedef struct sreloc_cache {
} Rlxrel_cache;
/*
+ * Nodes in an ofl_wrap AVL tree
+ *
+ * wsn_name is the name of the symbol to be wrapped. wsn_wrapname is used
+ * when we need to refer to the wrap symbol, and consists of the symbol
+ * name with a __wrap_ prefix.
+ */
+typedef struct wrap_sym_node {
+ avl_node_t wsn_avlnode; /* AVL book-keeping */
+ const char *wsn_name; /* Symbol name: XXX */
+ const char *wsn_wrapname; /* Wrap symbol name: __wrap_XXX */
+} WrapSymNode;
+
+
+/*
* Output file processing structure
*/
typedef Lword ofl_flag_t;
@@ -304,6 +318,7 @@ struct ofl_desc {
/* sloppy_comdat_reloc() */
APlist *ofl_maptext; /* mapfile added text sections */
APlist *ofl_mapdata; /* mapfile added data sections */
+ avl_tree_t *ofl_wrap; /* -z wrap symbols */
};
#define FLG_OF_DYNAMIC 0x00000001 /* generate dynamic output module */
diff --git a/usr/src/cmd/sgs/libld/Makefile.com b/usr/src/cmd/sgs/libld/Makefile.com
index cfa5fc3b6b..8453714c6a 100644
--- a/usr/src/cmd/sgs/libld/Makefile.com
+++ b/usr/src/cmd/sgs/libld/Makefile.com
@@ -33,14 +33,14 @@ COMOBJS32 = args32.o entry32.o exit32.o groups32.o \
libs32.o files32.o map32.o order32.o \
outfile32.o place32.o relocate32.o resolve32.o \
sections32.o sunwmove32.o support32.o syms32.o \
- update32.o unwind32.o version32.o
+ update32.o unwind32.o version32.o wrap32.o
COMOBJS64 = args64.o entry64.o exit64.o groups64.o \
ldentry64.o ldlibs64.o ldmachdep64.o ldmain64.o \
libs64.o files64.o map64.o order64.o \
outfile64.o place64.o relocate64.o resolve64.o \
sections64.o sunwmove64.o support64.o syms64.o \
- update64.o unwind64.o version64.o
+ update64.o unwind64.o version64.o wrap64.o
TOOLOBJS = alist.o assfail.o findprime.o string_table.o \
strhash.o
diff --git a/usr/src/cmd/sgs/libld/common/_libld.h b/usr/src/cmd/sgs/libld/common/_libld.h
index 3ca1237abd..0eb257ad1e 100644
--- a/usr/src/cmd/sgs/libld/common/_libld.h
+++ b/usr/src/cmd/sgs/libld/common/_libld.h
@@ -616,6 +616,7 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_vers_promote ld64_vers_promote
#define ld_vers_sym_process ld64_vers_sym_process
#define ld_vers_verify ld64_vers_verify
+#define ld_wrap_enter ld64_wrap_enter
#else
@@ -703,6 +704,7 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_vers_promote ld32_vers_promote
#define ld_vers_sym_process ld32_vers_sym_process
#define ld_vers_verify ld32_vers_verify
+#define ld_wrap_enter ld32_wrap_enter
#endif
@@ -831,6 +833,7 @@ extern void ld_vers_promote(Sym_desc *, Word, Ifl_desc *,
Ofl_desc *);
extern int ld_vers_sym_process(Lm_list *, Is_desc *, Ifl_desc *);
extern int ld_vers_verify(Ofl_desc *);
+extern WrapSymNode *ld_wrap_enter(Ofl_desc *, const char *);
extern uintptr_t add_regsym(Sym_desc *, Ofl_desc *);
extern Word hashbkts(Word);
diff --git a/usr/src/cmd/sgs/libld/common/args.c b/usr/src/cmd/sgs/libld/common/args.c
index d50fe53e7d..d83f2d4cfe 100644
--- a/usr/src/cmd/sgs/libld/common/args.c
+++ b/usr/src/cmd/sgs/libld/common/args.c
@@ -55,6 +55,21 @@
* -z nosighandler suppress the registration of the signal handler
* used to manage SIGBUS.
*/
+
+/*
+ * The following flags are committed, and will not be removed, but are
+ * not publically documented, either because they are obsolete, or because
+ * they exist to work around defects in other software and are not of
+ * sufficient interest otherwise.
+ *
+ * OPTION MEANING
+ *
+ * -Wl,... compiler drivers and configuration tools
+ * have been known to pass this compiler option
+ * to ld(1). Strip off the "-Wl," prefix and
+ * process the remainder (...) as a normal option.
+ */
+
#include <sys/link.h>
#include <stdio.h>
#include <fcntl.h>
@@ -198,6 +213,7 @@ usage_mesg(Boolean detail)
(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZT));
(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTO));
(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTW));
+ (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZWRAP));
(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZV));
}
@@ -1299,6 +1315,17 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error)
/* Don't report cascading errors */
ofl->ofl_ars_gsandx = -1;
}
+
+ /*
+ * If -z wrap is seen, enter the symbol to be wrapped
+ * into the wrap AVL tree.
+ */
+ } else if (strncmp(optarg, MSG_ORIG(MSG_ARG_WRAP),
+ MSG_ARG_WRAP_SIZE) == 0) {
+ if (ld_wrap_enter(ofl,
+ optarg + MSG_ARG_WRAP_SIZE) == NULL)
+ return (S_ERROR);
+
/*
* The following options just need validation as they
* are interpreted on the second pass through the
diff --git a/usr/src/cmd/sgs/libld/common/ldmain.c b/usr/src/cmd/sgs/libld/common/ldmain.c
index b71490bf94..3549b5c63b 100644
--- a/usr/src/cmd/sgs/libld/common/ldmain.c
+++ b/usr/src/cmd/sgs/libld/common/ldmain.c
@@ -404,9 +404,8 @@ ld_main(int argc, char **argv, Half mach)
* our memory consumption and freeing are doing. We should be able to
* free all the memory that has been allocated as part of the link-edit
* process.
- *
- * ofl_cleanup(ofl);
*/
+ /* ld_ofl_cleanup(ofl); */
return (0);
}
diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg
index e40bef08d5..58b256111b 100644
--- a/usr/src/cmd/sgs/libld/common/libld.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.msg
@@ -228,6 +228,8 @@
text\n"
@ MSG_ARG_DETAIL_ZTW "\t[-z textwarn]\twarn if there are relocations \
against text\n"
+@ MSG_ARG_DETAIL_ZWRAP "\t[-z wrap=symbol], [-wrap=symbol], [--wrap=symbol]\n\
+ \t\t\twrap symbol references\n"
@ MSG_ARG_DETAIL_ZV "\t[-z verbose]\t\
generate warnings for suspicious processings\n"
@@ -652,11 +654,14 @@
@ MSG_STR_ISALIST "$ISALIST"
@ MSG_STR_OSNAME "$OSNAME"
@ MSG_STR_OSREL "$OSREL"
+@ MSG_STR_UU_REAL_U "__real_"
+@ MSG_STR_UU_WRAP_U "__wrap_"
@ MSG_FMT_ARMEM "%s(%s)"
@ MSG_FMT_COLPATH "%s:%s"
@ MSG_FMT_SYMNAM "`%s'"
@ MSG_FMT_NULLSYMNAM "%s[%d]"
+@ MSG_FMT_STRCAT "%s%s"
@ MSG_PTH_RTLD "/usr/lib/ld.so.1"
@@ -1210,6 +1215,7 @@
@ MSG_ARG_NOSIGHANDLER "nosighandler"
@ MSG_ARG_GLOBAUDIT "globalaudit"
@ MSG_ARG_TARGET "target="
+@ MSG_ARG_WRAP "wrap="
@ MSG_ARG_HELP "help"
@ MSG_ARG_GROUP "group"
@ MSG_ARG_REDUCE "reduce"
@@ -1242,6 +1248,7 @@
@ MSG_ARG_T_UNDEF "-undefined"
@ MSG_ARG_T_VERSION "-version"
@ MSG_ARG_T_WHOLEARC "-whole-archive"
+@ MSG_ARG_T_WRAP "-wrap"
@ MSG_ARG_T_OPAR "("
@ MSG_ARG_T_CPAR ")"
diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c
index 71f75e9bd3..dc4fb16741 100644
--- a/usr/src/cmd/sgs/libld/common/syms.c
+++ b/usr/src/cmd/sgs/libld/common/syms.c
@@ -2312,6 +2312,48 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
}
/*
+ * The '-z wrap=XXX' option emulates the GNU ld --wrap=XXX
+ * option. When XXX is the symbol to be wrapped:
+ *
+ * - An undefined reference to XXX is converted to __wrap_XXX
+ * - An undefined reference to __real_XXX is converted to XXX
+ *
+ * The idea is that the user can supply a wrapper function
+ * __wrap_XXX that does some work, and then uses the name
+ * __real_XXX to pass the call on to the real function. The
+ * wrapper objects are linked with the original unmodified
+ * objects to produce a wrapped version of the output object.
+ */
+ if (ofl->ofl_wrap && name[0] && (shndx == SHN_UNDEF)) {
+ WrapSymNode wsn, *wsnp;
+
+ /*
+ * If this is the __real_XXX form, advance the
+ * pointer to reference the wrapped name.
+ */
+ wsn.wsn_name = name;
+ if ((*name == '_') &&
+ (strncmp(name, MSG_ORIG(MSG_STR_UU_REAL_U),
+ MSG_STR_UU_REAL_U_SIZE) == 0))
+ wsn.wsn_name += MSG_STR_UU_REAL_U_SIZE;
+
+ /*
+ * Is this symbol in the wrap AVL tree? If so, map
+ * XXX to __wrap_XXX, and __real_XXX to XXX. Note that
+ * wsn.wsn_name will equal the current value of name
+ * if the __real_ prefix is not present.
+ */
+ if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, 0)) != NULL) {
+ const char *old_name = name;
+
+ name = (wsn.wsn_name == name) ?
+ wsnp->wsn_wrapname : wsn.wsn_name;
+ DBG_CALL(Dbg_syms_wrap(ofl->ofl_lml, ndx,
+ old_name, name));
+ }
+ }
+
+ /*
* Determine and validate the symbols binding.
*/
bind = ELF_ST_BIND(sym->st_info);
diff --git a/usr/src/cmd/sgs/libld/common/util.c b/usr/src/cmd/sgs/libld/common/util.c
index 22b79fd685..c8529112a9 100644
--- a/usr/src/cmd/sgs/libld/common/util.c
+++ b/usr/src/cmd/sgs/libld/common/util.c
@@ -279,13 +279,48 @@ add_string(char *old, char *str)
}
/*
+ * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our
+ * '-z wrap=XXX'. When str2chr() does this conversion, we end up with
+ * the return character set to 'z' and optarg set to 'XXX'. This callback
+ * changes optarg to include the missing wrap= prefix.
+ *
+ * exit:
+ * Returns c on success, or '?' on error.
+ */
+static int
+str2chr_wrap_cb(int c)
+{
+ char *str;
+ size_t len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1;
+
+ if ((str = libld_malloc(len)) == NULL)
+ return ('?');
+ (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT),
+ MSG_ORIG(MSG_ARG_WRAP), optarg);
+ optarg = str;
+ return (c);
+}
+
+/*
* Determine whether this string, possibly with an associated option, should be
* translated to an option character. If so, update the optind and optarg
* as described for short options in getopt(3c).
+ *
+ * entry:
+ * lml - Link map list for debug messages
+ * ndx - Starting optind for current item
+ * argc, argv - Command line arguments
+ * arg - Option to be examined
+ * c, opt - Option character (c) and corresponding long name (opt)
+ * optsz - 0 if option does not accept a value. If option does
+ * accept a value, strlen(opt), giving the offset to the
+ * value if the option and value are combined in one string.
+ * cbfunc - NULL, or pointer to function to call if a translation is
+ * successful.
*/
static int
str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c,
- const char *opt, size_t optsz)
+ const char *opt, size_t optsz, int cbfunc(int))
{
if (optsz == 0) {
/*
@@ -331,6 +366,10 @@ str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c,
return ('?');
}
}
+
+ if (cbfunc != NULL)
+ c = (*cbfunc)(c);
+
return (c);
}
return (0);
@@ -362,20 +401,28 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
/* Translate -rpath <optarg> to -R <optarg> */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
MSG_ORIG(MSG_ARG_T_RPATH),
- MSG_ARG_T_RPATH_SIZE)) != 0) {
+ MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
return (c);
}
break;
case 's':
/* Translate -shared to -G */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
- MSG_ORIG(MSG_ARG_T_SHARED), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
return (c);
/* Translate -soname <optarg> to -h <optarg> */
} else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
MSG_ORIG(MSG_ARG_T_SONAME),
- MSG_ARG_T_SONAME_SIZE)) != 0) {
+ MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
+ return (c);
+ }
+ break;
+ case 'w':
+ /* Translate -wrap to -z wrap= */
+ if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
+ MSG_ORIG(MSG_ARG_T_WRAP) + 1,
+ MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
return (c);
}
break;
@@ -384,7 +431,8 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
* Translate -( to -z rescan-start
*/
if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
+ 0) {
optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
return (c);
}
@@ -394,7 +442,8 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
* Translate -) to -z rescan-end
*/
if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
+ 0) {
optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
return (c);
}
@@ -407,7 +456,8 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
* -zmuldefs
*/
if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
- MSG_ORIG(MSG_ARG_T_MULDEFS), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
+ 0) {
optarg =
(char *)MSG_ORIG(MSG_ARG_MULDEFS);
return (c);
@@ -418,7 +468,7 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
*/
} else if ((c = str2chr(lml, argc, ndx, argv,
arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
- MSG_ARG_T_AUXFLTR_SIZE)) != 0) {
+ MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
return (c);
}
break;
@@ -429,7 +479,7 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
*/
if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
MSG_ORIG(MSG_ARG_T_INTERP),
- MSG_ARG_T_INTERP_SIZE)) != 0) {
+ MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
return (c);
}
break;
@@ -437,15 +487,15 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
/* Translate --entry <optarg> to -e <optarg> */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
MSG_ORIG(MSG_ARG_T_ENTRY),
- MSG_ARG_T_ENTRY_SIZE)) != 0) {
+ MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
return (c);
}
/*
* Translate --end-group to -z rescan-end
*/
if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z',
- MSG_ORIG(MSG_ARG_T_ENDGROUP), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
+ 0, NULL)) != 0) {
optarg = (char *)
MSG_ORIG(MSG_ARG_RESCAN_END);
return (c);
@@ -455,14 +505,15 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
/* Translate --filter <optarg> to -F <optarg> */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
MSG_ORIG(MSG_ARG_T_STDFLTR),
- MSG_ARG_T_STDFLTR_SIZE)) != 0) {
+ MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
return (c);
}
break;
case 'h':
/* Translate --help to -zhelp */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
- MSG_ORIG(MSG_ARG_T_HELP), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
+ 0) {
optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
return (c);
}
@@ -473,7 +524,7 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
*/
if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
MSG_ORIG(MSG_ARG_T_LIBRARY),
- MSG_ARG_T_LIBRARY_SIZE)) != 0) {
+ MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
return (c);
/*
@@ -482,14 +533,15 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
*/
} else if ((c = str2chr(lml, ndx, argc, argv,
arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
- MSG_ARG_T_LIBPATH_SIZE)) != 0) {
+ MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
return (c);
}
break;
case 'n':
/* Translate --no-undefined to -zdefs */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
- MSG_ORIG(MSG_ARG_T_NOUNDEF), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
+ 0) {
optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
return (c);
@@ -498,8 +550,8 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
* -z defaultextract
*/
} else if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z',
- MSG_ORIG(MSG_ARG_T_NOWHOLEARC), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
+ 0, NULL)) != 0) {
optarg =
(char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
return (c);
@@ -509,29 +561,31 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
/* Translate --output <optarg> to -o <optarg> */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
MSG_ORIG(MSG_ARG_T_OUTPUT),
- MSG_ARG_T_OUTPUT_SIZE)) != 0) {
+ MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
return (c);
}
break;
case 'r':
/* Translate --relocatable to -r */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
- MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
+ NULL)) != 0) {
return (c);
}
break;
case 's':
/* Translate --strip-all to -s */
if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
- MSG_ORIG(MSG_ARG_T_STRIP), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
+ 0) {
return (c);
}
/*
* Translate --start-group to -z rescan-start
*/
if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z',
- MSG_ORIG(MSG_ARG_T_STARTGROUP), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
+ 0, NULL)) != 0) {
optarg = (char *)
MSG_ORIG(MSG_ARG_RESCAN_START);
return (c);
@@ -544,14 +598,15 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
*/
if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
MSG_ORIG(MSG_ARG_T_UNDEF),
- MSG_ARG_T_UNDEF_SIZE)) != 0) {
+ MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
return (c);
}
break;
case 'v':
/* Translate --version to -V */
if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
- MSG_ORIG(MSG_ARG_T_VERSION), 0)) != 0) {
+ MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
+ 0) {
return (c);
}
break;
@@ -560,17 +615,27 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
* Translate --whole-archive to -z alltextract
*/
if ((c = str2chr(lml, ndx, argc, argv,
- arg, 'z',
- MSG_ORIG(MSG_ARG_T_WHOLEARC), 0)) != 0) {
+ arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
+ 0, NULL)) != 0) {
optarg =
(char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
return (c);
}
+ /*
+ * Translate --wrap to -z wrap=
+ */
+ if ((c = str2chr(lml, ndx, argc, argv,
+ arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
+ MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
+ 0) {
+ return (c);
+ }
break;
}
break;
}
}
+
if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
/*
* It is possible that a "-Wl," argument has been used to
diff --git a/usr/src/cmd/sgs/libld/common/wrap.c b/usr/src/cmd/sgs/libld/common/wrap.c
new file mode 100644
index 0000000000..6a5ec5679f
--- /dev/null
+++ b/usr/src/cmd/sgs/libld/common/wrap.c
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "msg.h"
+#include "_libld.h"
+
+/*
+ * GNU ld --wrap support, also known as -z wrap.
+ *
+ * We maintain an AVL tree of wrapped symbol names. Every undefined
+ * symbol is tested against this tree, and those that match have
+ * their names modified to produce the wrapping effect:
+ *
+ * - An undefined reference to XXX is converted to __wrap_XXX
+ * - An undefined reference to __real_XXX is converted to XXX
+ *
+ * This operation has a cost, but that is mitigated by two factors:
+ *
+ * - This is a test feature, not used for production code, so somewhat
+ * longer link times are tolerable.
+ * - The cost of this feature is only paid when it is used. Otherwise,
+ * the sole overhead is the cost of testing the NULL AVL tree pointer
+ * during symbol processing.
+ */
+
+
+/*
+ * AVL comparison function for WrapSymNode items.
+ *
+ * entry:
+ * n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+wrap_cmp(const void *n1, const void *n2)
+{
+ int rc;
+
+ rc = strcmp(((WrapSymNode *)n1)->wsn_name,
+ ((WrapSymNode *)n2)->wsn_name);
+
+ if (rc > 0)
+ return (1);
+ if (rc < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Enter a -z wrap symbol into the ofl_wrap AVL tree
+ *
+ * entry:
+ * ofl - Output file descriptor
+ * name - Name of symbol to be entered. Caller must ensure that
+ * memory used to hold name remains available for the life
+ * of the link-edit process.
+ *
+ * exit:
+ * On success, updates ofl->wrap_cache with a pointer to the
+ * resulting WrapSymNode, and returns that pointer. On failure,
+ * returns NULL.
+ */
+WrapSymNode *
+ld_wrap_enter(Ofl_desc *ofl, const char *name)
+{
+ WrapSymNode *wsnp, wsn;
+ avl_index_t where;
+ size_t name_len, wrapname_len;
+ char *tmpname;
+
+ /* If this is the first wrap symbol, create the AVL tree */
+ if (ofl->ofl_wrap == NULL) {
+ ofl->ofl_wrap = libld_calloc(1, sizeof (*ofl->ofl_wrap));
+ if (ofl->ofl_wrap == NULL)
+ return (NULL);
+ avl_create(ofl->ofl_wrap, wrap_cmp, sizeof (WrapSymNode),
+ SGSOFFSETOF(WrapSymNode, wsn_avlnode));
+ }
+
+ /* Have we already entered this one? */
+ wsn.wsn_name = name;
+ if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, &where)) != NULL)
+ return (wsnp);
+
+ /*
+ * Allocate a new node, along with room for the wrapped name.
+ * Since strings have byte alignment, we can allocate it immediately
+ * following the AVL node without the need for alignment padding.
+ */
+ name_len = strlen(wsn.wsn_name);
+ wrapname_len = MSG_STR_UU_WRAP_U_SIZE + name_len + 1;
+ if ((wsnp = libld_calloc(1, sizeof (*wsnp) + wrapname_len)) == NULL)
+ return (NULL);
+ wsnp->wsn_name = name;
+
+ wsnp->wsn_wrapname = tmpname = (char *)(wsnp + 1);
+ (void) snprintf(tmpname, wrapname_len, MSG_ORIG(MSG_FMT_STRCAT),
+ MSG_ORIG(MSG_STR_UU_WRAP_U), name);
+
+ /* Insert the new node */
+ avl_insert(ofl->ofl_wrap, wsnp, where);
+ return (wsnp);
+}
diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
index bfd964a49c..18ab37ea63 100644
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
@@ -953,6 +953,7 @@
discarded file=%s"
@ MSG_SYM_DISCARD_DUP "symbol[%d]=%s; discarded duplicate: originates from \
file=%s"
+@ MSG_SYM_WRAP "symbol[%d]=%s renamed to %s (-z wrap)"
@ MSG_SYM_AOUT "symbol=%s; (original AOUT name)"
@ MSG_SYM_LOOKUP "symbol=%s; lookup in file=%s [ %s ]"
diff --git a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
index 15d459fa31..3768c7c72d 100644
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
@@ -404,6 +404,8 @@ void Dbg32_syms_updated(Ofl_desc *, Sym_desc *, const char *);
void Dbg64_syms_updated(Ofl_desc *, Sym_desc *, const char *);
void Dbg32_syms_up_title(Lm_list *);
void Dbg64_syms_up_title(Lm_list *);
+void Dbg32_syms_wrap(Lm_list *, Elf32_Word, const char *, const char *);
+void Dbg64_syms_wrap(Lm_list *, Elf64_Word, const char *, const char *);
void Dbg32_util_broadcast(Rt_map *);
void Dbg64_util_broadcast(Rt_map *);
diff --git a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
index b3074020bc..2ae1071a2c 100644
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
@@ -41,7 +41,7 @@
# MAPFILE HEADER END
#
-SUNWprivate_4.73 {
+SUNWprivate_4.74 {
global:
dbg_desc = NODIRECT; # interposed - ld.so.1(1)
dbg_print = NODIRECT; # interposed - ld(1) and ld.so.1(1)
@@ -399,6 +399,8 @@ SUNWprivate_4.73 {
Dbg64_syms_updated;
Dbg32_syms_up_title;
Dbg64_syms_up_title;
+ Dbg32_syms_wrap;
+ Dbg64_syms_wrap;
Dbg_tls_modactivity;
Dbg_tls_static_block;
diff --git a/usr/src/cmd/sgs/liblddbg/common/syms.c b/usr/src/cmd/sgs/liblddbg/common/syms.c
index 2f5e44dc48..97513d1a48 100644
--- a/usr/src/cmd/sgs/liblddbg/common/syms.c
+++ b/usr/src/cmd/sgs/liblddbg/common/syms.c
@@ -284,6 +284,16 @@ Dbg_syms_global(Lm_list *lml, Word ndx, const char *name)
}
void
+Dbg_syms_wrap(Lm_list *lml, Word ndx, const char *orig_name, const char *name)
+{
+ if (DBG_NOTCLASS(DBG_C_SYMBOLS))
+ return;
+
+ dbg_print(lml, MSG_INTL(MSG_SYM_WRAP), EC_WORD(ndx),
+ Dbg_demangle_name(orig_name), Dbg_demangle_name(name));
+}
+
+void
Dbg_syms_sec_title(Lm_list *lml)
{
if (DBG_NOTCLASS(DBG_C_SYMBOLS))
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 23297cd248..6bb180bc52 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1531,3 +1531,5 @@ Bugid Risk Synopsis
6834197 ld pukes when given an empty plate
6516644 per-symbol filtering shouldn't be allowed in executables
6878605 ld should accept '%' syntax when matching input SHT_PROGBITS sections
+6850768 ld option to autogenerate wrappers/interposers similar to GNU ld --wrap
+ PSARC/2009/493 ld -z wrap option