4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright (c) 1988 AT&T
39 #include <sys/types.h>
49 * libld_malloc() and dz_map() are used for both performance and for ease of
53 * The link-edit is a short lived process which doesn't really free much
54 * of the dynamic memory that it requests. Because of this, it is more
55 * important to optimize for quick memory allocations than the
56 * re-usability of the memory.
58 * By also mmaping blocks of pages in from /dev/zero we don't need to
59 * waste the overhead of zeroing out these pages for calloc() requests.
62 * By doing all libld memory management through the ld_malloc routine
63 * it's much easier to free up all memory at the end by simply unmaping
64 * all of the blocks that were mapped in through dz_map(). This is much
65 * simpler then trying to track all of the libld structures that were
66 * dynamically allocate and are actually pointers into the ELF files.
68 * It's important that we can free up all of our dynamic memory because
69 * libld is used by ld.so.1 when it performs dlopen()'s of relocatable
73 * The memory blocks for each allocation store the size of the allocation
74 * in the first 8 bytes of the block. The pointer that is returned by
75 * libld_malloc() is actually the address of (block + 8):
77 * (addr - 8) block_size
78 * (addr) <allocated block>
80 * The size is retained in order to implement realloc(), and to perform
81 * the required memcpy(). 8 bytes are uses, as the memory area returned
82 * by libld_malloc() must be 8 byte-aligned. Even in a 32-bit environment,
83 * u_longlog_t pointers are employed.
85 * Map anonymous memory via MAP_ANON (added in Solaris 8).
92 if ((addr
= mmap(0, size
, (PROT_READ
| PROT_WRITE
| PROT_EXEC
),
93 (MAP_PRIVATE
| MAP_ANON
), -1, 0)) == MAP_FAILED
) {
95 eprintf(NULL
, ERR_FATAL
, MSG_INTL(MSG_SYS_MMAPANON
),
103 libld_malloc(size_t size
)
105 Ld_heap
*chp
= ld_heap
;
107 size_t asize
= size
+ HEAPALIGN
;
110 * If this is the first allocation, or the allocation request is greater
111 * than the current free space available, allocate a new heap.
114 (((size_t)chp
->lh_end
- (size_t)chp
->lh_free
) <= asize
)) {
116 size_t hsize
= (size_t)S_ROUND(sizeof (Ld_heap
), HEAPALIGN
);
117 size_t tsize
= (size_t)S_ROUND((asize
+ hsize
), HEAPALIGN
);
120 * Allocate a block that is at minimum 'HEAPBLOCK' size
122 if (tsize
< HEAPBLOCK
)
125 if ((nhp
= dz_map(tsize
)) == MAP_FAILED
)
129 nhp
->lh_free
= (void *)((size_t)nhp
+ hsize
);
130 nhp
->lh_end
= (void *)((size_t)nhp
+ tsize
);
137 * Assign size to head of allocated block (used by realloc), and
138 * memory arena as then next 8-byte aligned offset.
140 *((size_t *)vptr
) = size
;
141 vptr
= (void *)((size_t)vptr
+ HEAPALIGN
);
144 * Increment free to point to next available block
146 chp
->lh_free
= (void *)S_ROUND((size_t)chp
->lh_free
+ asize
,
153 libld_realloc(void *ptr
, size_t size
)
159 return (libld_malloc(size
));
162 * Size of the allocated blocks is stored *just* before the blocks
165 psize
= *((size_t *)((size_t)ptr
- HEAPALIGN
));
168 * If the block actually fits then just return.
173 if ((vptr
= libld_malloc(size
)) != NULL
)
174 (void) memcpy(vptr
, ptr
, psize
);
181 libld_free(void *ptr
)
186 * Determine if a shared object definition structure already exists and if
187 * not create one. These definitions provide for recording information
188 * regarding shared objects that are still to be processed. Once processed
189 * shared objects are maintained on the ofl_sos list. The information
190 * recorded in this structure includes:
192 * o DT_USED requirements. In these cases definitions are added during
193 * mapfile processing of `-' entries (see map_dash()).
195 * o implicit NEEDED entries. As shared objects are processed from the
196 * command line so any of their dependencies are recorded in these
197 * structures for later processing (see process_dynamic()).
199 * o version requirements. Any explicit shared objects that have version
200 * dependencies on other objects have their version requirements recorded.
201 * In these cases definitions are added during mapfile processing of `-'
202 * entries (see map_dash()). Also, shared objects may have versioning
203 * requirements on their NEEDED entries. These cases are added during
204 * their version processing (see vers_need_process()).
206 * Note: Both process_dynamic() and vers_need_process() may generate the
207 * initial version definition structure because you can't rely on what
208 * section (.dynamic or .SUNW_version) may be processed first from any
212 sdf_find(const char *name
, APlist
*alp
)
217 for (APLIST_TRAVERSE(alp
, idx
, sdf
))
218 if (strcmp(name
, sdf
->sdf_name
) == 0)
225 sdf_add(const char *name
, APlist
**alpp
)
229 if ((sdf
= libld_calloc(sizeof (Sdf_desc
), 1)) == NULL
)
230 return ((Sdf_desc
*)S_ERROR
);
232 sdf
->sdf_name
= name
;
234 if (aplist_append(alpp
, sdf
, AL_CNT_OFL_LIBS
) == NULL
)
235 return ((Sdf_desc
*)S_ERROR
);
241 * Add a string, separated by a colon, to an existing string. Typically used
242 * to maintain filter, rpath and audit names, of which there is normally only
243 * one string supplied anyway.
246 add_string(char *old
, char *str
)
255 * If an original string exists, make sure this new string
256 * doesn't get duplicated.
258 if ((_str
= strstr(old
, str
)) != NULL
) {
259 if (((_str
== old
) ||
260 (*(_str
- 1) == *(MSG_ORIG(MSG_STR_COLON
)))) &&
261 (_str
+= strlen(str
)) &&
263 (*_str
== *(MSG_ORIG(MSG_STR_COLON
)))))
267 len
= strlen(old
) + strlen(str
) + 2;
268 if ((new = libld_calloc(1, len
)) == NULL
)
269 return ((char *)S_ERROR
);
270 (void) snprintf(new, len
, MSG_ORIG(MSG_FMT_COLPATH
), old
, str
);
272 if ((new = libld_malloc(strlen(str
) + 1)) == NULL
)
273 return ((char *)S_ERROR
);
274 (void) strcpy(new, str
);
281 * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our
282 * '-z wrap=XXX'. When str2chr() does this conversion, we end up with
283 * the return character set to 'z' and optarg set to 'XXX'. This callback
284 * changes optarg to include the missing wrap= prefix.
287 * Returns c on success, or '?' on error.
290 str2chr_wrap_cb(int c
)
293 size_t len
= MSG_ARG_WRAP_SIZE
+ strlen(optarg
) + 1;
295 if ((str
= libld_malloc(len
)) == NULL
)
297 (void) snprintf(str
, len
, MSG_ORIG(MSG_FMT_STRCAT
),
298 MSG_ORIG(MSG_ARG_WRAP
), optarg
);
304 * Determine whether this string, possibly with an associated option, should
305 * be translated to an option character. If so, update the optind and optarg
306 * and optopt as described for short options in getopt(3c).
309 * lml - Link map list for debug messages
310 * ndx - Starting optind for current item
311 * argc, argv - Command line arguments
312 * arg - Option to be examined
313 * c, opt - Option character (c) and corresponding long name (opt)
314 * optsz - 0 if option does not accept a value. If option does
315 * accept a value, strlen(opt), giving the offset to the
316 * value if the option and value are combined in one string.
317 * cbfunc - NULL, or pointer to function to call if a translation is
321 str2chr(Lm_list
*lml
, int ndx
, int argc
, char **argv
, char *arg
, int c
,
322 const char *opt
, size_t optsz
, int cbfunc(int))
326 * Compare a single option (ie. there's no associated option
329 if (strcmp(arg
, opt
) == 0) {
330 DBG_CALL(Dbg_args_str2chr(lml
, ndx
, opt
, c
));
335 } else if ((strcmp(arg
, opt
) == 0) ||
336 ((arg
[optsz
] == '=') && strncmp(arg
, opt
, optsz
) == 0)) {
338 * Otherwise, compare the option name, which may be
339 * concatenated with the option argument.
341 DBG_CALL(Dbg_args_str2chr(lml
, ndx
, opt
, c
));
343 if (arg
[optsz
] == '\0') {
345 * Optarg is the next argument (white space separated).
346 * Make sure an optarg is available, and if not return
347 * a failure to prevent any fall-through to the generic
348 * getopt() processing.
350 * Since we'll be completely failing this option we
351 * don't want to update optopt with the translation,
352 * but also need to set it to _something_. Setting it
353 * to the '-' of the argument causes us to behave
356 if ((++optind
+ 1) > argc
) {
360 optarg
= argv
[optind
];
364 * GNU option/option argument pairs can be represented
365 * with a "=" separator. If this is the case, remove
368 optarg
= &arg
[optsz
];
370 if (*optarg
== '=') {
371 if (*(++optarg
) == '\0') {
387 * Parse an individual option. The intent of this function is to determine if
388 * any known, non-Solaris options have been passed to ld(1). This condition
389 * can occur as a result of build configuration tools, because of users
390 * familiarity with other systems, or simply the users preferences. If a known
391 * non-Solaris option can be determined, translate that option into the Solaris
394 * This function will probably never be a complete solution, as new, non-Solaris
395 * options are discovered, their translation will have to be added. Other
396 * non-Solaris options are incompatible with the Solaris link-editor, and will
397 * never be recognized. We support what we can.
400 ld_getopt(Lm_list
*lml
, int ndx
, int argc
, char **argv
)
404 if ((optind
< argc
) && argv
[optind
] && (argv
[optind
][0] == '-')) {
405 char *arg
= &argv
[optind
][1];
409 /* Translate -rpath <optarg> to -R <optarg> */
410 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'R',
411 MSG_ORIG(MSG_ARG_T_RPATH
),
412 MSG_ARG_T_RPATH_SIZE
, NULL
)) != 0) {
417 /* Translate -shared to -G */
418 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'G',
419 MSG_ORIG(MSG_ARG_T_SHARED
), 0, NULL
)) != 0) {
422 /* Translate -soname <optarg> to -h <optarg> */
423 } else if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'h',
424 MSG_ORIG(MSG_ARG_T_SONAME
),
425 MSG_ARG_T_SONAME_SIZE
, NULL
)) != 0) {
430 /* Translate -wrap to -z wrap= */
431 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
432 MSG_ORIG(MSG_ARG_T_WRAP
) + 1,
433 MSG_ARG_T_WRAP_SIZE
- 1, str2chr_wrap_cb
)) != 0) {
439 * Translate -( to -z rescan-start
441 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
442 arg
, 'z', MSG_ORIG(MSG_ARG_T_OPAR
), 0, NULL
)) !=
444 optarg
= (char *)MSG_ORIG(MSG_ARG_RESCAN_START
);
450 * Translate -) to -z rescan-end
452 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
453 arg
, 'z', MSG_ORIG(MSG_ARG_T_CPAR
), 0, NULL
)) !=
455 optarg
= (char *)MSG_ORIG(MSG_ARG_RESCAN_END
);
460 switch (*(arg
+ 1)) {
463 * Translate --allow-multiple-definition to
466 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
467 MSG_ORIG(MSG_ARG_T_MULDEFS
), 0, NULL
)) !=
470 (char *)MSG_ORIG(MSG_ARG_MULDEFS
);
474 * Translate --auxiliary <optarg> to
477 } else if ((c
= str2chr(lml
, argc
, ndx
, argv
,
478 arg
, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR
),
479 MSG_ARG_T_AUXFLTR_SIZE
, NULL
)) != 0) {
485 * Translate --dynamic-linker <optarg> to
488 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'I',
489 MSG_ORIG(MSG_ARG_T_INTERP
),
490 MSG_ARG_T_INTERP_SIZE
, NULL
)) != 0) {
495 /* Translate --entry <optarg> to -e <optarg> */
496 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'e',
497 MSG_ORIG(MSG_ARG_T_ENTRY
),
498 MSG_ARG_T_ENTRY_SIZE
, NULL
)) != 0) {
502 * Translate --end-group to -z rescan-end
504 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
505 arg
, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP
),
508 MSG_ORIG(MSG_ARG_RESCAN_END
);
514 * Translate --fatal-warnings to
517 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
518 MSG_ORIG(MSG_ARG_T_FATWARN
),
521 MSG_ORIG(MSG_ARG_FATWARN
);
524 /* Translate --filter <optarg> to -F <optarg> */
525 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'F',
526 MSG_ORIG(MSG_ARG_T_STDFLTR
),
527 MSG_ARG_T_STDFLTR_SIZE
, NULL
)) != 0) {
532 /* Translate --help to -zhelp */
533 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
534 MSG_ORIG(MSG_ARG_T_HELP
), 0, NULL
)) !=
536 optarg
= (char *)MSG_ORIG(MSG_ARG_HELP
);
542 * Translate --library <optarg> to -l <optarg>
544 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'l',
545 MSG_ORIG(MSG_ARG_T_LIBRARY
),
546 MSG_ARG_T_LIBRARY_SIZE
, NULL
)) != 0) {
550 * Translate --library-path <optarg> to
553 } else if ((c
= str2chr(lml
, ndx
, argc
, argv
,
554 arg
, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH
),
555 MSG_ARG_T_LIBPATH_SIZE
, NULL
)) != 0) {
561 * Translate --no-fatal-warnings to
562 * -z nofatal-warnings.
564 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
565 MSG_ORIG(MSG_ARG_T_NOFATWARN
),
568 MSG_ORIG(MSG_ARG_NOFATWARN
);
572 /* Translate --no-undefined to -zdefs */
573 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'z',
574 MSG_ORIG(MSG_ARG_T_NOUNDEF
), 0, NULL
)) !=
576 optarg
= (char *)MSG_ORIG(MSG_ARG_DEFS
);
580 * Translate --no-whole-archive to
583 } else if ((c
= str2chr(lml
, ndx
, argc
, argv
,
584 arg
, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC
),
587 (char *)MSG_ORIG(MSG_ARG_DFLEXTRT
);
592 /* Translate --output <optarg> to -o <optarg> */
593 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'o',
594 MSG_ORIG(MSG_ARG_T_OUTPUT
),
595 MSG_ARG_T_OUTPUT_SIZE
, NULL
)) != 0) {
600 /* Translate --relocatable to -r */
601 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'r',
602 MSG_ORIG(MSG_ARG_T_RELOCATABLE
), 0,
608 /* Translate --strip-all to -s */
609 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 's',
610 MSG_ORIG(MSG_ARG_T_STRIP
), 0, NULL
)) !=
615 * Translate --start-group to -z rescan-start
617 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
618 arg
, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP
),
621 MSG_ORIG(MSG_ARG_RESCAN_START
);
627 * Translate --undefined <optarg> to
630 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'u',
631 MSG_ORIG(MSG_ARG_T_UNDEF
),
632 MSG_ARG_T_UNDEF_SIZE
, NULL
)) != 0) {
637 /* Translate --version to -V */
638 if ((c
= str2chr(lml
, ndx
, argc
, argv
, arg
, 'V',
639 MSG_ORIG(MSG_ARG_T_VERSION
), 0, NULL
)) !=
646 * Translate --whole-archive to -z alltextract
648 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
649 arg
, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC
),
652 (char *)MSG_ORIG(MSG_ARG_ALLEXTRT
);
656 * Translate --wrap to -z wrap=
658 if ((c
= str2chr(lml
, ndx
, argc
, argv
,
659 arg
, 'z', MSG_ORIG(MSG_ARG_T_WRAP
),
660 MSG_ARG_T_WRAP_SIZE
, str2chr_wrap_cb
)) !=
670 if ((c
= getopt(argc
, argv
, MSG_ORIG(MSG_STR_OPTIONS
))) != -1) {
672 * It is possible that a "-Wl," argument has been used to
673 * specify an option. This isn't advertized ld(1) syntax, but
674 * compiler drivers and configuration tools, have been known to
675 * pass this compiler option to ld(1). Strip off the "-Wl,"
676 * prefix and pass the option through.
678 if ((c
== 'W') && (strncmp(optarg
,
679 MSG_ORIG(MSG_ARG_T_WL
), MSG_ARG_T_WL_SIZE
) == 0)) {
680 DBG_CALL(Dbg_args_Wldel(lml
, ndx
, optarg
));
681 c
= optarg
[MSG_ARG_T_WL_SIZE
];
682 optarg
+= MSG_ARG_T_WL_SIZE
+ 1;
690 * A compare routine for Isd_node AVL trees.
693 isdavl_compare(const void *n1
, const void *n2
)
696 const char *st1
, *st2
;
699 hash1
= ((Isd_node
*)n1
)->isd_hash
;
700 hash2
= ((Isd_node
*)n2
)->isd_hash
;
707 st1
= ((Isd_node
*)n1
)->isd_name
;
708 st2
= ((Isd_node
*)n2
)->isd_name
;
710 rc
= strcmp(st1
, st2
);
719 * Messaging support - funnel everything through dgettext().
724 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS
), MSG_ORIG(mid
)));
728 * Determine whether a symbol name should be demangled.
731 demangle(const char *name
)
734 return (Elf_demangle_name(name
));
740 * Compare a series of platform or machine hardware names.
743 cap_names_match(Alist
*alp1
, Alist
*alp2
)
750 if ((nitems
= alist_nitems(alp1
)) != alist_nitems(alp2
))
753 for (ALIST_TRAVERSE(alp1
, idx1
, capstr1
)) {
757 for (ALIST_TRAVERSE(alp2
, idx2
, capstr2
)) {
758 if (strcmp(capstr1
->cs_str
, capstr2
->cs_str
))