blob: 51bcf7d25e9a9940ac2195a469130fee681a9769 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* vi: set sw=4 ts=4: */
2/*
3 * Program to load an ELF binary on a linux system, and run it
4 * after resolving ELF shared library symbols
5 *
6 * Copyright (C) 2000-2006 by Erik Andersen <andersen@uclibc.org>
7 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
8 * David Engel, Hongjiu Lu and Mitch D'Souza
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the above contributors may not be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32
33#include <ldso.h>
34#include <stdio.h>
35#include <string.h> /* Needed for 'strstr' prototype' */
36#include <stdbool.h>
37#include <bits/uClibc_mutex.h>
38
39#ifdef __UCLIBC_HAS_TLS__
40#include <tls.h>
41#endif
42
43#if defined(USE_TLS) && USE_TLS
44#include <ldsodefs.h>
45extern void _dl_add_to_slotinfo(struct link_map *l);
46#endif
47
48/* TODO: get rid of global lock and use more finegrained locking, or
49 * perhaps RCU for the global structures */
50__UCLIBC_MUTEX_STATIC(_dl_mutex, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
51
52#ifdef SHARED
53# if defined(USE_TLS) && USE_TLS
54# include <dl-tls.h>
55extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
56# endif
57
58/* When libdl is loaded as a shared library, we need to load in
59 * and use a pile of symbols from ldso... */
60#include <dl-elf.h>
61#if 0
62extern struct elf_resolve * _dl_load_shared_library(unsigned, struct dyn_elf **,
63 struct elf_resolve *, char *, int);
64extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
65extern void _dl_protect_relro(struct elf_resolve * tpnt);
66#endif
67extern int _dl_errno;
68extern struct dyn_elf *_dl_symbol_tables;
69extern struct dyn_elf *_dl_handles;
70extern struct elf_resolve *_dl_loaded_modules;
71extern void _dl_free (void *__ptr);
72extern struct r_debug *_dl_debug_addr;
73extern unsigned long _dl_error_number;
74extern void *(*_dl_malloc_function)(size_t);
75extern void (*_dl_free_function) (void *p);
76extern void _dl_run_init_array(struct elf_resolve *);
77extern void _dl_run_fini_array(struct elf_resolve *);
78#ifdef __LDSO_CACHE_SUPPORT__
79int _dl_map_cache(void);
80int _dl_unmap_cache(void);
81#endif
82#ifdef __mips__
83extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
84#endif
85#ifdef __SUPPORT_LD_DEBUG__
86extern char *_dl_debug;
87#endif
88
89#else /* !SHARED */
90
91#define _dl_malloc malloc
92#define _dl_free free
93
94/* When libdl is linked as a static library, we need to replace all
95 * the symbols that otherwise would have been loaded in from ldso... */
96
97#ifdef __SUPPORT_LD_DEBUG__
98char *_dl_debug = NULL;
99char *_dl_debug_symbols = NULL;
100char *_dl_debug_move = NULL;
101char *_dl_debug_reloc = NULL;
102char *_dl_debug_detail = NULL;
103char *_dl_debug_nofixups = NULL;
104char *_dl_debug_bindings = NULL;
105int _dl_debug_file = 2;
106#endif
107const char *_dl_progname = ""; /* Program name */
108void *(*_dl_malloc_function)(size_t);
109void (*_dl_free_function) (void *p);
110#ifdef __LDSO_LD_LIBRARY_PATH__
111char *_dl_library_path = NULL; /* Where we look for libraries */
112#endif
113int _dl_errno = 0; /* We can't use the real errno in ldso */
114size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later */
115/* This global variable is also to communicate with debuggers such as gdb. */
116struct r_debug *_dl_debug_addr = NULL;
117
118#include "../ldso/dl-array.c"
119#include "../ldso/dl-debug.c"
120
121
122# if defined(USE_TLS) && USE_TLS
123/*
124 * Giving this initialized value preallocates some surplus bytes in the
125 * static TLS area, see __libc_setup_tls (libc-tls.c).
126 */
127size_t _dl_tls_static_size = 2048;
128# endif
129#include LDSO_ELFINTERP
130#include "../ldso/dl-hash.c"
131#define _dl_trace_loaded_objects 0
132#include "../ldso/dl-elf.c"
133#endif /* SHARED */
134
135#ifdef __SUPPORT_LD_DEBUG__
136# define _dl_if_debug_print(fmt, args...) \
137 do { \
138 if (_dl_debug) \
139 fprintf(stderr, "%s():%i: " fmt, __func__, __LINE__, ## args); \
140 } while (0)
141#else
142# define _dl_if_debug_print(fmt, args...)
143#endif
144
145static int do_dlclose(void *, int need_fini);
146
147
148static const char *const dl_error_names[] = {
149 "",
150 "File not found",
151 "Unable to open /dev/zero",
152 "Not an ELF file",
153#if defined (__i386__)
154 "Not i386 binary",
155#elif defined (__sparc__)
156 "Not sparc binary",
157#elif defined (__mc68000__)
158 "Not m68k binary",
159#else
160 "Unrecognized binary type",
161#endif
162 "Not an ELF shared library",
163 "Unable to mmap file",
164 "No dynamic section",
165 "Library contains unsupported TLS",
166#ifdef ELF_USES_RELOCA
167 "Unable to process REL relocs",
168#else
169 "Unable to process RELA relocs",
170#endif
171 "Bad handle",
172 "Unable to resolve symbol"
173};
174
175
176#if defined(USE_TLS) && USE_TLS
177#ifdef SHARED
178/*
179 * Systems which do not have tls_index also probably have to define
180 * DONT_USE_TLS_INDEX.
181 */
182
183# ifndef __TLS_GET_ADDR
184# define __TLS_GET_ADDR __tls_get_addr
185# endif
186
187/*
188 * Return the symbol address given the map of the module it is in and
189 * the symbol record. This is used in dl-sym.c.
190 */
191static void *
192internal_function
193_dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
194{
195# ifndef DONT_USE_TLS_INDEX
196 tls_index tmp =
197 {
198 .ti_module = map->l_tls_modid,
199 .ti_offset = st_value
200 };
201
202 return __TLS_GET_ADDR (&tmp);
203# else
204 return __TLS_GET_ADDR (map->l_tls_modid, st_value);
205# endif
206}
207#endif
208
209/* Returns true when a non-empty entry was found. */
210static bool
211remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
212 bool should_be_there)
213{
214 if (idx - disp >= listp->len) {
215 if (listp->next == NULL) {
216 /*
217 * The index is not actually valid in the slotinfo list,
218 * because this object was closed before it was fully set
219 * up due to some error.
220 */
221 _dl_assert(!should_be_there);
222 } else {
223 if (remove_slotinfo(idx, listp->next, disp + listp->len,
224 should_be_there))
225 return true;
226
227 /*
228 * No non-empty entry. Search from the end of this element's
229 * slotinfo array.
230 */
231 idx = disp + listp->len;
232 }
233 } else {
234 struct link_map *old_map = listp->slotinfo[idx - disp].map;
235
236 /*
237 * The entry might still be in its unused state if we are
238 * closing an object that wasn't fully set up.
239 */
240 if (__builtin_expect(old_map != NULL, 1)) {
241 _dl_assert(old_map->l_tls_modid == idx);
242
243 /* Mark the entry as unused. */
244 listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
245 listp->slotinfo[idx - disp].map = NULL;
246 }
247
248 /*
249 * If this is not the last currently used entry no need to
250 * look further.
251 */
252 if (idx != _dl_tls_max_dtv_idx)
253 return true;
254 }
255
256 while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
257 --idx;
258
259 if (listp->slotinfo[idx - disp].map != NULL) {
260 /* Found a new last used index. */
261 _dl_tls_max_dtv_idx = idx;
262 return true;
263 }
264 }
265
266 /* No non-entry in this list element. */
267 return false;
268}
269#endif
270
271#ifndef __LDSO_NO_CLEANUP__
272void dl_cleanup(void) __attribute__ ((destructor));
273void dl_cleanup(void)
274{
275 struct dyn_elf *h, *n;
276
277 for (h = _dl_handles; h; h = n) {
278 n = h->next_handle;
279 do_dlclose(h, 1);
280 }
281}
282#endif
283
284static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
285 struct elf_resolve *map)
286{
287 struct elf_resolve **p = list;
288 struct init_fini_list *q;
289
290 *p++ = map;
291 map->init_flag |= DL_RESERVED;
292 if (map->init_fini)
293 for (q = map->init_fini; q; q = q->next)
294 if (! (q->tpnt->init_flag & DL_RESERVED))
295 p += _dl_build_local_scope (p, q->tpnt);
296 return p - list;
297}
298
299static void *do_dlopen(const char *libname, int flag)
300{
301 struct elf_resolve *tpnt, *tfrom;
302 struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
303 ElfW(Addr) from;
304 struct elf_resolve *tpnt1;
305 void (*dl_brk) (void);
306 int now_flag;
307 struct init_fini_list *tmp, *runp, *runp2, *dep_list;
308 unsigned int nlist, i;
309 struct elf_resolve **init_fini_list;
310 static bool _dl_init;
311 struct elf_resolve **local_scope;
312 struct r_scope_elem *ls;
313#if defined(USE_TLS) && USE_TLS
314 bool any_tls = false;
315#endif
316
317 /* A bit of sanity checking... */
318 if (!(flag & (RTLD_LAZY|RTLD_NOW|RTLD_NOLOAD))) {
319 _dl_error_number = LD_BAD_HANDLE;
320 return NULL;
321 }
322
323 from = (ElfW(Addr)) __builtin_return_address(0);
324
325 if (!_dl_init) {
326 _dl_init = true;
327 _dl_malloc_function = malloc;
328 _dl_free_function = free;
329 }
330 /* Cover the trivial case first */
331 if (!libname)
332 return _dl_symbol_tables;
333
334#ifndef SHARED
335# ifdef __SUPPORT_LD_DEBUG__
336 _dl_debug = getenv("LD_DEBUG");
337 if (_dl_debug) {
338 if (_dl_strstr(_dl_debug, "all")) {
339 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
340 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
341 } else {
342 _dl_debug_detail = strstr(_dl_debug, "detail");
343 _dl_debug_move = strstr(_dl_debug, "move");
344 _dl_debug_symbols = strstr(_dl_debug, "sym");
345 _dl_debug_reloc = strstr(_dl_debug, "reloc");
346 _dl_debug_nofixups = strstr(_dl_debug, "nofix");
347 _dl_debug_bindings = strstr(_dl_debug, "bind");
348 }
349 }
350# endif
351#endif
352
353 _dl_map_cache();
354
355 /*
356 * Try and locate the module we were called from - we
357 * need this so that we get the correct RPATH/RUNPATH. Note that
358 * this is the current behavior under Solaris, but the
359 * ABI+ specifies that we should only use the RPATH from
360 * the application. Thus this may go away at some time
361 * in the future.
362 */
363 {
364 struct dyn_elf *dpnt;
365 tfrom = NULL;
366 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
367 tpnt = dpnt->dyn;
368 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
369 tfrom = tpnt;
370 }
371 }
372 for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
373 continue;
374
375 relro_ptr = rpnt;
376 now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
377 if (getenv("LD_BIND_NOW"))
378 now_flag = RTLD_NOW;
379
380#if !defined SHARED && defined __LDSO_LIBRARY_PATH__
381 /* When statically linked, the _dl_library_path is not yet initialized */
382 _dl_library_path = getenv("LD_LIBRARY_PATH");
383#endif
384
385 /* Try to load the specified library */
386 _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
387 (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
388
389 tpnt = _dl_load_shared_library((flag & RTLD_NOLOAD) ? DL_RESOLVE_NOLOAD : 0,
390 &rpnt, tfrom, (char*)libname, 0);
391 if (tpnt == NULL) {
392 _dl_unmap_cache();
393 return NULL;
394 }
395 dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
396 _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
397 dyn_chain->dyn = tpnt;
398 tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
399
400 dyn_chain->next_handle = _dl_handles;
401 _dl_handles = dyn_ptr = dyn_chain;
402
403 if (tpnt->usage_count > 1) {
404 _dl_if_debug_print("Lib: %s already opened\n", libname);
405 /* see if there is a handle from a earlier dlopen */
406 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
407 if (handle->dyn == tpnt) {
408 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
409 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
410 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
411 dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
412 dyn_chain->next = handle->next;
413 break;
414 }
415 }
416 return dyn_chain;
417 }
418
419 tpnt->init_flag |= DL_OPENED;
420
421 _dl_if_debug_print("Looking for needed libraries\n");
422 nlist = 0;
423 runp = alloca(sizeof(*runp));
424 runp->tpnt = tpnt;
425 runp->next = NULL;
426 dep_list = runp2 = runp;
427 for (; runp; runp = runp->next) {
428 ElfW(Dyn) *dpnt;
429 char *lpntstr;
430
431 nlist++;
432 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
433 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
434 if (dpnt->d_tag == DT_NEEDED) {
435 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
436 dpnt->d_un.d_val);
437 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
438 lpntstr, runp->tpnt->libname);
439 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
440 if (!tpnt1)
441 goto oops;
442
443 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
444
445 /* This list is for dlsym() and relocation */
446 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
447 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
448 dyn_ptr = dyn_ptr->next;
449 dyn_ptr->dyn = tpnt1;
450 /* Used to record RTLD_LOCAL scope */
451 tmp = alloca(sizeof(struct init_fini_list));
452 tmp->tpnt = tpnt1;
453 tmp->next = runp->tpnt->init_fini;
454 runp->tpnt->init_fini = tmp;
455
456 for (tmp=dep_list; tmp; tmp = tmp->next) {
457 if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
458 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
459 tmp->tpnt->libname);
460 tpnt1->usage_count--;
461 break;
462 }
463 }
464 if (!tmp) { /* Don't add if circular dependency detected */
465 runp2->next = alloca(sizeof(*runp));
466 runp2 = runp2->next;
467 runp2->tpnt = tpnt1;
468 runp2->next = NULL;
469 }
470 }
471 }
472 }
473 init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
474 dyn_chain->init_fini.init_fini = init_fini_list;
475 dyn_chain->init_fini.nlist = nlist;
476 i = 0;
477 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
478 init_fini_list[i++] = runp2->tpnt;
479 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
480 if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
481 tmp = malloc(sizeof(struct init_fini_list));
482 tmp->tpnt = runp->tpnt;
483 tmp->next = runp2->tpnt->rtld_local;
484 runp2->tpnt->rtld_local = tmp;
485 }
486 }
487
488 }
489 /* Build the local scope for the dynamically loaded modules. */
490 local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
491 for (i = 0; i < nlist; i++)
492 if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
493 int k, cnt;
494 cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
495 init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
496 init_fini_list[i]->symbol_scope.r_nlist = cnt;
497 _dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
498 cnt * sizeof (struct elf_resolve *));
499 /* Restoring the init_flag.*/
500 for (k = 0; k < nlist; k++)
501 init_fini_list[k]->init_flag &= ~DL_RESERVED;
502 }
503
504 _dl_free(local_scope);
505
506 /* Sort the INIT/FINI list in dependency order. */
507 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
508 unsigned int j, k;
509 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
510 /* Empty */;
511 for (k = j + 1; k < nlist; ++k) {
512 struct init_fini_list *ele = init_fini_list[k]->init_fini;
513
514 for (; ele; ele = ele->next) {
515 if (ele->tpnt == runp2->tpnt) {
516 struct elf_resolve *here = init_fini_list[k];
517 _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
518 for (i = (k - j); i; --i)
519 init_fini_list[i+j] = init_fini_list[i+j-1];
520 init_fini_list[j] = here;
521 ++j;
522 break;
523 }
524 }
525 }
526 }
527#ifdef __SUPPORT_LD_DEBUG__
528 if (_dl_debug) {
529 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
530 for (i = 0; i < nlist; i++) {
531 fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
532 runp = init_fini_list[i]->init_fini;
533 for (; runp; runp = runp->next)
534 fprintf(stderr, " %s ", runp->tpnt->libname);
535 fprintf(stderr, "\n");
536 }
537 }
538#endif
539
540 _dl_if_debug_print("Beginning dlopen relocation fixups\n");
541 /*
542 * OK, now all of the kids are tucked into bed in their proper addresses.
543 * Now we go through and look for REL and RELA records that indicate fixups
544 * to the GOT tables. We need to do this in reverse order so that COPY
545 * directives work correctly */
546
547 /* Get the tail of the list */
548 for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
549
550 /* Extend the global scope by adding the local scope of the dlopened DSO. */
551 ls->next = &dyn_chain->dyn->symbol_scope;
552#ifdef __mips__
553 /*
554 * Relocation of the GOT entries for MIPS have to be done
555 * after all the libraries have been loaded.
556 */
557 _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
558#endif
559
560 if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
561 goto oops;
562
563 if (relro_ptr) {
564 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
565 if (rpnt->dyn->relro_size)
566 _dl_protect_relro(rpnt->dyn);
567 }
568 }
569 /* TODO: Should we set the protections of all pages back to R/O now ? */
570
571
572#if defined(USE_TLS) && USE_TLS
573
574 for (i=0; i < nlist; i++) {
575 struct elf_resolve *tmp_tpnt = init_fini_list[i];
576 /* Only add TLS memory if this object is loaded now and
577 therefore is not yet initialized. */
578
579 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
580 /* Only if the module defines thread local data. */
581 && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
582
583 /* Now that we know the object is loaded successfully add
584 modules containing TLS data to the slot info table. We
585 might have to increase its size. */
586 _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
587
588 /* It is the case in which we couldn't perform TLS static
589 initialization at relocation time, and we delayed it until
590 the relocation has been completed. */
591
592 if (tmp_tpnt->l_need_tls_init) {
593 tmp_tpnt->l_need_tls_init = 0;
594# ifdef SHARED
595 /* Update the slot information data for at least the
596 generation of the DSO we are allocating data for. */
597 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
598# endif
599
600 _dl_init_static_tls((struct link_map*)tmp_tpnt);
601 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
602 }
603
604 /* We have to bump the generation counter. */
605 any_tls = true;
606 }
607 }
608
609 /* Bump the generation number if necessary. */
610 if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
611 _dl_debug_early("TLS generation counter wrapped! Please report this.");
612 _dl_exit(30);
613 }
614
615#endif
616
617 /* Notify the debugger we have added some objects. */
618 if (_dl_debug_addr) {
619 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
620 if (dl_brk != NULL) {
621 _dl_debug_addr->r_state = RT_ADD;
622 (*dl_brk) ();
623
624 _dl_debug_addr->r_state = RT_CONSISTENT;
625 (*dl_brk) ();
626 }
627 }
628
629 /* Run the ctors and setup the dtors */
630 for (i = nlist; i; --i) {
631 tpnt = init_fini_list[i-1];
632 if (tpnt->init_flag & INIT_FUNCS_CALLED)
633 continue;
634 tpnt->init_flag |= INIT_FUNCS_CALLED;
635
636 if (tpnt->dynamic_info[DT_INIT]) {
637 void (*dl_elf_func) (void);
638 dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
639 if (dl_elf_func) {
640 _dl_if_debug_print("running ctors for library %s at '%p'\n",
641 tpnt->libname, dl_elf_func);
642 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
643 }
644 }
645
646 _dl_run_init_array(tpnt);
647 }
648
649 _dl_unmap_cache();
650 return (void *) dyn_chain;
651
652oops:
653 /* Something went wrong. Clean up and return NULL. */
654 _dl_unmap_cache();
655 do_dlclose(dyn_chain, 0);
656 return NULL;
657}
658
659void *dlopen(const char *libname, int flag)
660{
661 void *ret;
662
663 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
664 ret = do_dlopen(libname, flag);
665 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
666
667 return ret;
668}
669
670static void *do_dlsym(void *vhandle, const char *name, void *caller_address)
671{
672 struct elf_resolve *tpnt, *tfrom;
673 struct dyn_elf *handle;
674 ElfW(Addr) from;
675 struct dyn_elf *rpnt;
676 void *ret;
677 struct symbol_ref sym_ref = { NULL, NULL };
678 /* Nastiness to support underscore prefixes. */
679#ifdef __UCLIBC_UNDERSCORES__
680 char tmp_buf[80];
681 char *name2 = tmp_buf;
682 size_t nlen = strlen (name) + 1;
683 if (nlen + 1 > sizeof (tmp_buf))
684 name2 = malloc (nlen + 1);
685 if (name2 == 0) {
686 _dl_error_number = LD_ERROR_MMAP_FAILED;
687 return 0;
688 }
689 name2[0] = '_';
690 memcpy (name2 + 1, name, nlen);
691#else
692 const char *name2 = name;
693#endif
694 handle = (struct dyn_elf *) vhandle;
695
696 /* First of all verify that we have a real handle
697 of some kind. Return NULL if not a valid handle. */
698
699 if (handle == NULL)
700 handle = _dl_symbol_tables;
701 else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
702 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
703 if (rpnt == handle)
704 break;
705 if (!rpnt) {
706 _dl_error_number = LD_BAD_HANDLE;
707 ret = NULL;
708 goto out;
709 }
710 } else if (handle == RTLD_NEXT) {
711 /*
712 * Try and locate the module we were called from - we
713 * need this so that we know where to start searching
714 * from. We never pass RTLD_NEXT down into the actual
715 * dynamic loader itself, as it doesn't know
716 * how to properly treat it.
717 */
718 from = (ElfW(Addr)) caller_address;
719
720 tfrom = NULL;
721 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
722 tpnt = rpnt->dyn;
723 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
724 tfrom = tpnt;
725 handle = rpnt->next;
726 }
727 }
728 }
729 tpnt = NULL;
730 if (handle == _dl_symbol_tables)
731 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
732 ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, tpnt, ELF_RTYPE_CLASS_DLSYM, &sym_ref);
733
734#if defined(USE_TLS) && USE_TLS && defined SHARED
735 if (sym_ref.sym && (ELF_ST_TYPE(sym_ref.sym->st_info) == STT_TLS) && (sym_ref.tpnt)) {
736 /* The found symbol is a thread-local storage variable.
737 Return its address for the current thread. */
738 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
739 }
740#endif
741
742 /*
743 * Nothing found.
744 */
745 if (!ret)
746 _dl_error_number = LD_NO_SYMBOL;
747out:
748#ifdef __UCLIBC_UNDERSCORES__
749 if (name2 != tmp_buf)
750 free (name2);
751#endif
752 return ret;
753}
754
755void *dlsym(void *vhandle, const char *name)
756{
757 void *ret;
758
759 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
760 ret = do_dlsym(vhandle, name, __builtin_return_address(0));
761 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
762
763 return ret;
764}
765
766#if 0
767void *dlvsym(void *vhandle, const char *name, const char *version)
768{
769 return dlsym(vhandle, name);
770}
771#endif
772
773static int do_dlclose(void *vhandle, int need_fini)
774{
775 struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
776 struct init_fini_list *runp, *tmp;
777 ElfW(Phdr) *ppnt;
778 struct elf_resolve *tpnt, *run_tpnt;
779 int (*dl_elf_fini) (void);
780 void (*dl_brk) (void);
781 struct dyn_elf *handle;
782 unsigned int end = 0, start = 0xffffffff;
783 unsigned int i, j;
784 struct r_scope_elem *ls, *ls_next = NULL;
785 struct elf_resolve **handle_rlist;
786
787#if defined(USE_TLS) && USE_TLS
788 bool any_tls = false;
789 size_t tls_free_start = NO_TLS_OFFSET;
790 size_t tls_free_end = NO_TLS_OFFSET;
791 struct link_map *tls_lmap;
792#endif
793
794 handle = (struct dyn_elf *) vhandle;
795 if (handle == _dl_symbol_tables)
796 return 0;
797 rpnt1 = NULL;
798 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
799 if (rpnt == handle)
800 break;
801 rpnt1 = rpnt;
802 }
803
804 if (!rpnt) {
805 _dl_error_number = LD_BAD_HANDLE;
806 return 1;
807 }
808 if (rpnt1)
809 rpnt1->next_handle = rpnt->next_handle;
810 else
811 _dl_handles = rpnt->next_handle;
812 _dl_if_debug_print("%s: usage count: %d\n",
813 handle->dyn->libname, handle->dyn->usage_count);
814 if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
815 handle->dyn->usage_count--;
816 free(handle);
817 return 0;
818 }
819
820 /* Store the handle's local scope array for later removal */
821 handle_rlist = handle->dyn->symbol_scope.r_list;
822
823 /* Store references to the local scope entries for later removal */
824 for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next)
825 if (ls->next->r_list[0] == handle->dyn) {
826 break;
827 }
828 /* ls points to the previous local symbol scope */
829 if(ls && ls->next)
830 ls_next = ls->next->next;
831
832 /* OK, this is a valid handle - now close out the file */
833 for (j = 0; j < handle->init_fini.nlist; ++j) {
834 tpnt = handle->init_fini.init_fini[j];
835 tpnt->usage_count--;
836 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
837 if ((tpnt->dynamic_info[DT_FINI]
838 || tpnt->dynamic_info[DT_FINI_ARRAY])
839 && need_fini
840 && !(tpnt->init_flag & FINI_FUNCS_CALLED)
841 ) {
842 tpnt->init_flag |= FINI_FUNCS_CALLED;
843 _dl_run_fini_array(tpnt);
844
845 if (tpnt->dynamic_info[DT_FINI]) {
846 dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
847 _dl_if_debug_print("running dtors for library %s at '%p'\n",
848 tpnt->libname, dl_elf_fini);
849 DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
850 }
851 }
852
853 _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
854 end = 0;
855 for (i = 0, ppnt = tpnt->ppnt;
856 i < tpnt->n_phent; ppnt++, i++) {
857 if (ppnt->p_type != PT_LOAD)
858 continue;
859 if (ppnt->p_vaddr < start)
860 start = ppnt->p_vaddr;
861 if (end < ppnt->p_vaddr + ppnt->p_memsz)
862 end = ppnt->p_vaddr + ppnt->p_memsz;
863 }
864
865#if defined(USE_TLS) && USE_TLS
866 /* Do the cast to make things easy. */
867 tls_lmap = (struct link_map *) tpnt;
868
869 /* Remove the object from the dtv slotinfo array if it uses TLS. */
870 if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
871 any_tls = true;
872
873 if (_dl_tls_dtv_slotinfo_list != NULL
874 && ! remove_slotinfo (tls_lmap->l_tls_modid,
875 _dl_tls_dtv_slotinfo_list, 0,
876 (tpnt->init_flag & INIT_FUNCS_CALLED)))
877 /* All dynamically loaded modules with TLS are unloaded. */
878 _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
879
880 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
881 /*
882 * Collect a contiguous chunk built from the objects in
883 * this search list, going in either direction. When the
884 * whole chunk is at the end of the used area then we can
885 * reclaim it.
886 */
887# if defined(TLS_TCB_AT_TP)
888 if (tls_free_start == NO_TLS_OFFSET
889 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
890 /* Extend the contiguous chunk being reclaimed. */
891 tls_free_start
892 = tls_lmap->l_tls_offset -
893 tls_lmap->l_tls_blocksize;
894
895 if (tls_free_end == NO_TLS_OFFSET)
896 tls_free_end = tls_lmap->l_tls_offset;
897 } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
898 == tls_free_end)
899 /* Extend the chunk backwards. */
900 tls_free_end = tls_lmap->l_tls_offset;
901 else {
902 /*
903 * This isn't contiguous with the last chunk freed.
904 * One of them will be leaked unless we can free
905 * one block right away.
906 */
907 if (tls_free_end == _dl_tls_static_used) {
908 _dl_tls_static_used = tls_free_start;
909 tls_free_end = tls_lmap->l_tls_offset;
910 tls_free_start
911 = tls_free_end - tls_lmap->l_tls_blocksize;
912 } else if ((size_t) tls_lmap->l_tls_offset
913 == _dl_tls_static_used)
914 _dl_tls_static_used = tls_lmap->l_tls_offset -
915 tls_lmap->l_tls_blocksize;
916 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
917 /*
918 * We pick the later block. It has a chance
919 * to be freed.
920 */
921 tls_free_end = tls_lmap->l_tls_offset;
922 tls_free_start = tls_free_end -
923 tls_lmap->l_tls_blocksize;
924 }
925 }
926# elif defined(TLS_DTV_AT_TP)
927 if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
928 /* Extend the contiguous chunk being reclaimed. */
929 tls_free_end -= tls_lmap->l_tls_blocksize;
930 else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
931 == tls_free_start)
932 /* Extend the chunk backwards. */
933 tls_free_start = tls_lmap->l_tls_offset;
934 else {
935 /*
936 * This isn't contiguous with the last chunk
937 * freed. One of them will be leaked.
938 */
939 if (tls_free_end == _dl_tls_static_used)
940 _dl_tls_static_used = tls_free_start;
941 tls_free_start = tls_lmap->l_tls_offset;
942 tls_free_end = tls_free_start +
943 tls_lmap->l_tls_blocksize;
944 }
945# else
946# error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
947# endif
948 } else {
949
950#define TLS_DTV_UNALLOCATED ((void *) -1l)
951
952 dtv_t *dtv = THREAD_DTV ();
953
954 _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
955 if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
956 /* Note that free is called for NULL is well. We
957 deallocate even if it is this dtv entry we are
958 supposed to load. The reason is that we call
959 memalign and not malloc. */
960 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
961 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
962 }
963 }
964 }
965#endif
966
967 end = (end + ADDR_ALIGN) & PAGE_ALIGN;
968 start = start & ~ADDR_ALIGN;
969 DL_LIB_UNMAP (tpnt, end - start);
970 /* Free elements in RTLD_LOCAL scope list */
971 for (runp = tpnt->rtld_local; runp; runp = tmp) {
972 tmp = runp->next;
973 free(runp);
974 }
975
976 /* Next, remove tpnt from the loaded_module list */
977 if (_dl_loaded_modules == tpnt) {
978 _dl_loaded_modules = tpnt->next;
979 if (_dl_loaded_modules)
980 _dl_loaded_modules->prev = 0;
981 } else {
982 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
983 if (run_tpnt->next == tpnt) {
984 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
985 run_tpnt->next = run_tpnt->next->next;
986 if (run_tpnt->next)
987 run_tpnt->next->prev = run_tpnt;
988 break;
989 }
990 }
991 }
992
993 /* Next, remove tpnt from the global symbol table list */
994 if (_dl_symbol_tables) {
995 if (_dl_symbol_tables->dyn == tpnt) {
996 _dl_symbol_tables = _dl_symbol_tables->next;
997 if (_dl_symbol_tables)
998 _dl_symbol_tables->prev = 0;
999 } else {
1000 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
1001 if (rpnt1->next->dyn == tpnt) {
1002 _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
1003 rpnt1_tmp = rpnt1->next->next;
1004 free(rpnt1->next);
1005 rpnt1->next = rpnt1_tmp;
1006 if (rpnt1->next)
1007 rpnt1->next->prev = rpnt1;
1008 break;
1009 }
1010 }
1011 }
1012 }
1013 free(tpnt->libname);
1014 if (handle->dyn != tpnt)
1015 free(tpnt->symbol_scope.r_list);
1016 free(tpnt);
1017 }
1018 }
1019 /* Unlink and release the handle's local scope from global one */
1020 if(ls)
1021 ls->next = ls_next;
1022 free(handle_rlist);
1023
1024 for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
1025 rpnt1_tmp = rpnt1->next;
1026 free(rpnt1);
1027 }
1028 free(handle->init_fini.init_fini);
1029 free(handle);
1030
1031#if defined(USE_TLS) && USE_TLS
1032 /* If we removed any object which uses TLS bump the generation counter. */
1033 if (any_tls) {
1034 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
1035 _dl_debug_early("TLS generation counter wrapped! Please report to the uClibc mailing list.\n");
1036 _dl_exit(30);
1037 }
1038
1039 if (tls_free_end == _dl_tls_static_used)
1040 _dl_tls_static_used = tls_free_start;
1041 }
1042#endif
1043
1044 if (_dl_debug_addr) {
1045 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
1046 if (dl_brk != NULL) {
1047 _dl_debug_addr->r_state = RT_DELETE;
1048 (*dl_brk) ();
1049
1050 _dl_debug_addr->r_state = RT_CONSISTENT;
1051 (*dl_brk) ();
1052 }
1053 }
1054
1055 return 0;
1056}
1057
1058int dlclose(void *vhandle)
1059{
1060 int ret;
1061
1062 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1063 ret = do_dlclose(vhandle, 1);
1064 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
1065
1066 return ret;
1067}
1068
1069char *dlerror(void)
1070{
1071 const char *retval;
1072
1073 if (!_dl_error_number)
1074 return NULL;
1075 retval = dl_error_names[_dl_error_number];
1076 _dl_error_number = 0;
1077 return (char *)retval;
1078}
1079
1080/*
1081 * Dump information to stderr about the current loaded modules
1082 */
1083#ifdef __USE_GNU
1084static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
1085
1086int dlinfo(void)
1087{
1088 struct elf_resolve *tpnt;
1089 struct dyn_elf *rpnt, *hpnt;
1090
1091 fprintf(stderr, "List of loaded modules\n");
1092 /* First start with a complete list of all of the loaded files. */
1093 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1094 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1095 DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1096 type[tpnt->libtype],
1097 tpnt->usage_count, tpnt->libname);
1098 }
1099
1100 /* Next dump the module list for the application itself */
1101 fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1102 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1103 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1104
1105 for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1106 fprintf(stderr, "Modules for handle %p\n", hpnt);
1107 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1108 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1109 }
1110 return 0;
1111}
1112
1113static int do_dladdr(const void *__address, Dl_info * __info)
1114{
1115 struct elf_resolve *pelf;
1116 struct elf_resolve *rpnt;
1117
1118 _dl_map_cache();
1119
1120 /*
1121 * Try and locate the module address is in
1122 */
1123 pelf = NULL;
1124
1125 _dl_if_debug_print("__address: %p __info: %p\n", __address, __info);
1126
1127 __address = DL_LOOKUP_ADDRESS (__address);
1128
1129 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1130 struct elf_resolve *tpnt;
1131
1132 tpnt = rpnt;
1133
1134 _dl_if_debug_print("Module \"%s\" at %p\n",
1135 tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1136
1137 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1138 pelf = tpnt;
1139 }
1140
1141 if (!pelf) {
1142 return 0;
1143 }
1144
1145 /*
1146 * Try and locate the symbol of address
1147 */
1148
1149 {
1150 char *strtab;
1151 ElfW(Sym) *symtab;
1152 unsigned int hn, si, sn, sf;
1153 ElfW(Addr) sa = 0;
1154
1155 /* Set the info for the object the address lies in */
1156 __info->dli_fname = pelf->libname;
1157 __info->dli_fbase = (void *)pelf->mapaddr;
1158
1159 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1160 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1161
1162 sf = sn = 0;
1163
1164#ifdef __LDSO_GNU_HASH_SUPPORT__
1165 if (pelf->l_gnu_bitmask) {
1166 for (hn = 0; hn < pelf->nbucket; hn++) {
1167 si = pelf->l_gnu_buckets[hn];
1168 if (!si)
1169 continue;
1170
1171 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1172 do {
1173 ElfW(Addr) symbol_addr;
1174
1175 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1176 if ((symtab[si].st_shndx != SHN_UNDEF
1177 || symtab[si].st_value != 0)
1178 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1179 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1180 (ElfW(Addr)) __address)) {
1181 sa = symbol_addr;
1182 sn = si;
1183 sf = 1;
1184 }
1185 _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1186 ++si;
1187 } while ((*hasharr++ & 1u) == 0);
1188 }
1189 } else
1190#endif
1191 for (hn = 0; hn < pelf->nbucket; hn++) {
1192 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1193 ElfW(Addr) symbol_addr;
1194
1195 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1196 if ((symtab[si].st_shndx != SHN_UNDEF
1197 || symtab[si].st_value != 0)
1198 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1199 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1200 (ElfW(Addr)) __address)) {
1201 sa = symbol_addr;
1202 sn = si;
1203 sf = 1;
1204 }
1205
1206 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1207 strtab + symtab[si].st_name, symbol_addr);
1208 }
1209 }
1210
1211 if (sf) {
1212 /* A nearest symbol has been found; fill the entries */
1213 __info->dli_sname = strtab + symtab[sn].st_name;
1214 __info->dli_saddr = (void *)sa;
1215 } else {
1216 /* No symbol found, fill entries with NULL value,
1217 only the containing object will be returned. */
1218 __info->dli_sname = NULL;
1219 __info->dli_saddr = NULL;
1220 }
1221 return 1;
1222 }
1223}
1224#endif
1225
1226int dladdr(const void *__address, Dl_info * __info)
1227{
1228 int ret;
1229
1230 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1231 ret = do_dladdr(__address, __info);
1232 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
1233
1234 return ret;
1235}