lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | /* Copyright (C) 2011-2015 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library. If not, see |
| 17 | <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | /* Like x86_64, we pass the index of the relocation and not its offset. |
| 20 | In _dl_profile_fixup and _dl_call_pltexit we also use the index. |
| 21 | Therefore it is wasteful to compute the offset in the trampoline |
| 22 | just to reverse the operation immediately afterwards. */ |
| 23 | #define reloc_offset reloc_arg * sizeof (PLTREL) |
| 24 | #define reloc_index reloc_arg |
| 25 | |
| 26 | #include <elf/dl-runtime.c> |
| 27 | |
| 28 | #include <sys/mman.h> |
| 29 | #include <arch/sim.h> |
| 30 | #include <dl-unmap-segments.h> |
| 31 | |
| 32 | /* Like realpath(), but simplified: no dynamic memory use, no lstat(), |
| 33 | no set_errno(), no valid "rpath" on error, etc. This handles some |
| 34 | simple cases where the simulator might not have a valid entry for |
| 35 | a loaded Elf object, in particular dlopen() with a relative path. |
| 36 | For this relatively rare case, one could also imagine using |
| 37 | link_map.l_origin to avoid the getcwd() here, but the simpler code |
| 38 | here seems like a better solution. */ |
| 39 | static char * |
| 40 | dl_realpath (const char *name, char *rpath) |
| 41 | { |
| 42 | char *dest; |
| 43 | const char *start, *end; |
| 44 | |
| 45 | if (name[0] != '/') |
| 46 | { |
| 47 | if (!__getcwd (rpath, PATH_MAX)) |
| 48 | return NULL; |
| 49 | dest = __rawmemchr (rpath, '\0'); |
| 50 | } |
| 51 | else |
| 52 | { |
| 53 | rpath[0] = '/'; |
| 54 | dest = rpath + 1; |
| 55 | } |
| 56 | |
| 57 | for (start = end = name; *start; start = end) |
| 58 | { |
| 59 | /* Skip sequence of multiple path-separators. */ |
| 60 | while (*start == '/') |
| 61 | ++start; |
| 62 | |
| 63 | /* Find end of path component. */ |
| 64 | for (end = start; *end && *end != '/'; ++end) |
| 65 | /* Nothing. */; |
| 66 | |
| 67 | if (end - start == 0) |
| 68 | break; |
| 69 | else if (end - start == 1 && start[0] == '.') |
| 70 | /* nothing */; |
| 71 | else if (end - start == 2 && start[0] == '.' && start[1] == '.') |
| 72 | { |
| 73 | /* Back up to previous component, ignore if at root already. */ |
| 74 | if (dest > rpath + 1) |
| 75 | while ((--dest)[-1] != '/'); |
| 76 | } |
| 77 | else |
| 78 | { |
| 79 | if (dest[-1] != '/') |
| 80 | *dest++ = '/'; |
| 81 | |
| 82 | if (dest + (end - start) >= rpath + PATH_MAX) |
| 83 | return NULL; |
| 84 | |
| 85 | dest = __mempcpy (dest, start, end - start); |
| 86 | *dest = '\0'; |
| 87 | } |
| 88 | } |
| 89 | if (dest > rpath + 1 && dest[-1] == '/') |
| 90 | --dest; |
| 91 | *dest = '\0'; |
| 92 | |
| 93 | return rpath; |
| 94 | } |
| 95 | |
| 96 | /* Support notifying the simulator about new objects. */ |
| 97 | void internal_function |
| 98 | _dl_after_load (struct link_map *l) |
| 99 | { |
| 100 | int shift; |
| 101 | char pathbuf[PATH_MAX]; |
| 102 | char *path; |
| 103 | |
| 104 | /* Don't bother if not in the simulator. */ |
| 105 | if (__insn_mfspr (SPR_SIM_CONTROL) == 0) |
| 106 | return; |
| 107 | |
| 108 | #define DLPUTC(c) __insn_mtspr (SPR_SIM_CONTROL, \ |
| 109 | (SIM_CONTROL_DLOPEN \ |
| 110 | | ((c) << _SIM_CONTROL_OPERATOR_BITS))) |
| 111 | |
| 112 | /* Write the library address in hex. */ |
| 113 | DLPUTC ('0'); |
| 114 | DLPUTC ('x'); |
| 115 | for (shift = (int) sizeof (unsigned long) * 8 - 4; shift >= 0; shift -= 4) |
| 116 | DLPUTC ("0123456789abcdef"[(l->l_map_start >> shift) & 0xF]); |
| 117 | DLPUTC (':'); |
| 118 | |
| 119 | /* Write the library path, including the terminating '\0'. */ |
| 120 | path = dl_realpath (l->l_name, pathbuf) ?: l->l_name; |
| 121 | for (size_t i = 0;; i++) |
| 122 | { |
| 123 | DLPUTC (path[i]); |
| 124 | if (path[i] == '\0') |
| 125 | break; |
| 126 | } |
| 127 | #undef DLPUTC |
| 128 | } |
| 129 | |
| 130 | /* Support notifying the simulator about removed objects prior to munmap(). */ |
| 131 | static void |
| 132 | sim_dlclose (ElfW(Addr) map_start) |
| 133 | { |
| 134 | int shift; |
| 135 | |
| 136 | /* Don't bother if not in the simulator. */ |
| 137 | if (__insn_mfspr (SPR_SIM_CONTROL) == 0) |
| 138 | return; |
| 139 | |
| 140 | #define DLPUTC(c) __insn_mtspr (SPR_SIM_CONTROL, \ |
| 141 | (SIM_CONTROL_DLCLOSE \ |
| 142 | | ((c) << _SIM_CONTROL_OPERATOR_BITS))) |
| 143 | |
| 144 | /* Write the library address in hex. */ |
| 145 | DLPUTC ('0'); |
| 146 | DLPUTC ('x'); |
| 147 | for (shift = (int) sizeof (unsigned long) * 8 - 4; shift >= 0; shift -= 4) |
| 148 | DLPUTC ("0123456789abcdef"[(map_start >> shift) & 0xF]); |
| 149 | DLPUTC ('\0'); |
| 150 | |
| 151 | #undef DLPUTC |
| 152 | } |
| 153 | |
| 154 | void internal_function |
| 155 | _dl_unmap (struct link_map *map) |
| 156 | { |
| 157 | sim_dlclose (map->l_map_start); |
| 158 | _dl_unmap_segments (map); |
| 159 | } |