| 1 | /* Operating system support for run-time dynamic linker. Hurd version. |
| 2 | Copyright (C) 1995-2024 Free Software Foundation, Inc. |
| 3 | This file is part of the GNU C Library. |
| 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 | <https://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | /* In the static library, this is all handled by dl-support.c |
| 20 | or by the vanilla definitions in the rest of the C library. */ |
| 21 | #ifdef SHARED |
| 22 | |
| 23 | #include <hurd.h> |
| 24 | #include <link.h> |
| 25 | #include <unistd.h> |
| 26 | #include <fcntl.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <sys/mman.h> |
| 29 | #include <ldsodefs.h> |
| 30 | #include <sys/wait.h> |
| 31 | #include <assert.h> |
| 32 | #include <sysdep.h> |
| 33 | #include <argz.h> |
| 34 | #include <mach/mig_support.h> |
| 35 | #include "hurdstartup.h" |
| 36 | #include <hurd/lookup.h> |
| 37 | #include <hurd/auth.h> |
| 38 | #include <hurd/term.h> |
| 39 | #include <stdarg.h> |
| 40 | #include <ctype.h> |
| 41 | #include <sys/stat.h> |
| 42 | #include <sys/uio.h> |
| 43 | |
| 44 | #include <entry.h> |
| 45 | #include <dl-machine.h> |
| 46 | #include <dl-procinfo.h> |
| 47 | |
| 48 | #include <dl-tunables.h> |
| 49 | #include <not-errno.h> |
| 50 | #include <not-cancel.h> |
| 51 | |
| 52 | extern void __mach_init (void); |
| 53 | |
| 54 | extern int _dl_argc; |
| 55 | extern char **_dl_argv; |
| 56 | extern char **_environ; |
| 57 | |
| 58 | int __libc_enable_secure = 0; |
| 59 | rtld_hidden_data_def (__libc_enable_secure) |
| 60 | /* This variable contains the lowest stack address ever used. */ |
| 61 | void *__libc_stack_end = NULL; |
| 62 | rtld_hidden_data_def(__libc_stack_end) |
| 63 | |
| 64 | /* TODO: Initialize. */ |
| 65 | void *_dl_random attribute_relro = NULL; |
| 66 | |
| 67 | struct hurd_startup_data *_dl_hurd_data; |
| 68 | |
| 69 | |
| 70 | ElfW(Addr) |
| 71 | _dl_sysdep_start (void **start_argptr, |
| 72 | void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent, |
| 73 | ElfW(Addr) *user_entry, |
| 74 | ElfW(auxv_t) *auxv)) |
| 75 | { |
| 76 | void go (intptr_t *argdata) |
| 77 | { |
| 78 | char *orig_argv0; |
| 79 | char **p; |
| 80 | |
| 81 | /* Cache the information in various global variables. */ |
| 82 | _dl_argc = *argdata; |
| 83 | _dl_argv = 1 + (char **) argdata; |
| 84 | _environ = &_dl_argv[_dl_argc + 1]; |
| 85 | for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ |
| 86 | |
| 87 | orig_argv0 = _dl_argv[0]; |
| 88 | |
| 89 | if ((void *) p == _dl_argv[0]) |
| 90 | { |
| 91 | static struct hurd_startup_data nodata; |
| 92 | _dl_hurd_data = &nodata; |
| 93 | nodata.user_entry = (vm_address_t) ENTRY_POINT; |
| 94 | } |
| 95 | else |
| 96 | _dl_hurd_data = (void *) p; |
| 97 | |
| 98 | GLRO(dl_platform) = NULL; /* Default to nothing known about the platform. */ |
| 99 | |
| 100 | __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE; |
| 101 | |
| 102 | __tunables_init (_environ); |
| 103 | |
| 104 | /* Initialize DSO sorting algorithm after tunables. */ |
| 105 | _dl_sort_maps_init (); |
| 106 | |
| 107 | #ifdef DL_SYSDEP_INIT |
| 108 | DL_SYSDEP_INIT; |
| 109 | #endif |
| 110 | |
| 111 | #ifdef DL_PLATFORM_INIT |
| 112 | DL_PLATFORM_INIT; |
| 113 | #endif |
| 114 | |
| 115 | /* Determine the length of the platform name. */ |
| 116 | if (GLRO(dl_platform) != NULL) |
| 117 | GLRO(dl_platformlen) = strlen (GLRO(dl_platform)); |
| 118 | |
| 119 | if (_dl_hurd_data->flags & EXEC_STACK_ARGS |
| 120 | && _dl_hurd_data->user_entry == 0) |
| 121 | _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT; |
| 122 | |
| 123 | #if 0 /* XXX make this work for real someday... */ |
| 124 | if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT) |
| 125 | /* We were invoked as a command, not as the program interpreter. |
| 126 | The generic ld.so code supports this: it will parse the args |
| 127 | as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we |
| 128 | support an additional special syntax: |
| 129 | ld.so [-LIBS...] PROGRAM [ARGS...] |
| 130 | Each LIBS word consists of "FILENAME=MEMOBJ"; |
| 131 | for example "-/lib/libc.so=123" says that the contents of |
| 132 | /lib/libc.so are found in a memory object whose port name |
| 133 | in our task is 123. */ |
| 134 | while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-') |
| 135 | { |
| 136 | char *lastslash, *memobjname, *p; |
| 137 | struct link_map *l; |
| 138 | mach_port_t memobj; |
| 139 | error_t err; |
| 140 | |
| 141 | --_dl_argc; |
| 142 | p = _dl_argv++[1] + 1; |
| 143 | |
| 144 | memobjname = strchr (p, '='); |
| 145 | if (! memobjname) |
| 146 | _dl_sysdep_fatal ("Bogus library spec: " , p, "\n" , NULL); |
| 147 | *memobjname++ = '\0'; |
| 148 | memobj = 0; |
| 149 | while (*memobjname != '\0') |
| 150 | memobj = (memobj * 10) + (*memobjname++ - '0'); |
| 151 | |
| 152 | /* Add a user reference on the memory object port, so we will |
| 153 | still have one after _dl_map_object_from_fd calls our |
| 154 | `close'. */ |
| 155 | err = __mach_port_mod_refs (__mach_task_self (), memobj, |
| 156 | MACH_PORT_RIGHT_SEND, +1); |
| 157 | assert_perror (err); |
| 158 | |
| 159 | lastslash = strrchr (p, '/'); |
| 160 | l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, NULL, |
| 161 | memobj, strdup (p), 0); |
| 162 | |
| 163 | /* Squirrel away the memory object port where it |
| 164 | can be retrieved by the program later. */ |
| 165 | l->l_info[DT_NULL] = (void *) memobj; |
| 166 | } |
| 167 | #endif |
| 168 | |
| 169 | /* Call elf/rtld.c's main program. It will set everything |
| 170 | up and leave us to transfer control to USER_ENTRY. */ |
| 171 | (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr, |
| 172 | _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)), |
| 173 | (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL); |
| 174 | |
| 175 | /* The call above might screw a few things up. |
| 176 | |
| 177 | P is the location after the terminating NULL of the list of |
| 178 | environment variables. It has to point to the Hurd startup |
| 179 | data or if that's missing then P == ARGV[0] must hold. The |
| 180 | startup code in init-first.c will get confused if this is not |
| 181 | the case, so we must rearrange things to make it so. We'll |
| 182 | recompute P and move the Hurd data or the new ARGV[0] there. |
| 183 | |
| 184 | Note: directly invoked ld.so can move arguments and env vars. |
| 185 | |
| 186 | We use memmove, since the locations might overlap. */ |
| 187 | |
| 188 | char **newp; |
| 189 | for (newp = _environ; *newp++;); |
| 190 | |
| 191 | if (newp != p || _dl_argv[0] != orig_argv0) |
| 192 | { |
| 193 | if (orig_argv0 == (char *) p) |
| 194 | { |
| 195 | if ((char *) newp != _dl_argv[0]) |
| 196 | { |
| 197 | assert ((char *) newp < _dl_argv[0]); |
| 198 | _dl_argv[0] = memmove ((char *) newp, _dl_argv[0], |
| 199 | strlen (_dl_argv[0]) + 1); |
| 200 | } |
| 201 | } |
| 202 | else |
| 203 | { |
| 204 | if ((void *) newp != _dl_hurd_data) |
| 205 | memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data)); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | _dl_init_first (argdata); |
| 210 | |
| 211 | { |
| 212 | extern void _dl_start_user (void); |
| 213 | /* Unwind the stack to ARGDATA and simulate a return from _dl_start |
| 214 | to the RTLD_START code which will run the user's entry point. */ |
| 215 | RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | /* Set up so we can do RPCs. */ |
| 220 | __mach_init (); |
| 221 | |
| 222 | /* Initialize frequently used global variable. */ |
| 223 | GLRO(dl_pagesize) = __getpagesize (); |
| 224 | |
| 225 | /* See hurd/hurdstartup.c; this deals with getting information |
| 226 | from the exec server and slicing up the arguments. |
| 227 | Then it will call `go', above. */ |
| 228 | _hurd_startup (start_argptr, &go); |
| 229 | |
| 230 | LOSE; |
| 231 | abort (); |
| 232 | } |
| 233 | |
| 234 | void |
| 235 | _dl_sysdep_start_cleanup (void) |
| 236 | { |
| 237 | /* Deallocate the reply port and task port rights acquired by |
| 238 | __mach_init. We are done with them now, and the user will |
| 239 | reacquire them for himself when he wants them. */ |
| 240 | __mig_dealloc_reply_port (__mig_get_reply_port ()); |
| 241 | __mach_port_deallocate (__mach_task_self (), __mach_host_self_); |
| 242 | __mach_port_deallocate (__mach_task_self (), __mach_task_self_); |
| 243 | } |
| 244 | |
| 245 | /* Minimal open/close/mmap/etc. implementation sufficient for initial loading of |
| 246 | shared libraries. These are weak definitions so that when the |
| 247 | dynamic linker re-relocates itself to be user-visible (for -ldl), |
| 248 | it will get the user's definition (i.e. usually libc's). |
| 249 | |
| 250 | They also need to be set in the libc and ld section of |
| 251 | sysdeps/mach/hurd/Versions, to be overridable, and in libc.abilist and |
| 252 | ld.abilist to be checked. */ |
| 253 | |
| 254 | /* This macro checks that the function does not get renamed to be hidden: we do |
| 255 | need these to be overridable by libc's. */ |
| 256 | #define check_no_hidden(name) \ |
| 257 | __typeof (name) __check_##name##_no_hidden \ |
| 258 | __attribute__ ((alias (#name))) \ |
| 259 | __attribute_copy__ (name); |
| 260 | |
| 261 | /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an |
| 262 | error. If STAT is non-zero, stat the file into that stat buffer. */ |
| 263 | static error_t |
| 264 | open_file (const char *file_name, int flags, |
| 265 | mach_port_t *port, struct stat64 *stat) |
| 266 | { |
| 267 | enum retry_type doretry; |
| 268 | char retryname[1024]; /* XXX string_t LOSES! */ |
| 269 | file_t startdir; |
| 270 | error_t err; |
| 271 | |
| 272 | error_t use_init_port (int which, error_t (*operate) (file_t)) |
| 273 | { |
| 274 | return (which < _dl_hurd_data->portarraysize |
| 275 | ? ((*operate) (_dl_hurd_data->portarray[which])) |
| 276 | : EGRATUITOUS); |
| 277 | } |
| 278 | file_t get_dtable_port (int fd) |
| 279 | { |
| 280 | if ((unsigned int) fd < _dl_hurd_data->dtablesize |
| 281 | && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL) |
| 282 | { |
| 283 | __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd], |
| 284 | MACH_PORT_RIGHT_SEND, +1); |
| 285 | return _dl_hurd_data->dtable[fd]; |
| 286 | } |
| 287 | return __hurd_fail (EBADF), MACH_PORT_NULL; |
| 288 | } |
| 289 | |
| 290 | assert (!(flags & ~(O_READ | O_EXEC | O_CLOEXEC | O_IGNORE_CTTY))); |
| 291 | flags &= ~(O_CLOEXEC | O_IGNORE_CTTY); |
| 292 | |
| 293 | startdir = _dl_hurd_data->portarray[file_name[0] == '/' |
| 294 | ? INIT_PORT_CRDIR : INIT_PORT_CWDIR]; |
| 295 | |
| 296 | while (file_name[0] == '/') |
| 297 | file_name++; |
| 298 | |
| 299 | err = __dir_lookup (startdir, (char *)file_name, flags, 0, |
| 300 | &doretry, retryname, port); |
| 301 | |
| 302 | if (!err) |
| 303 | err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port, |
| 304 | __dir_lookup, doretry, retryname, |
| 305 | flags, 0, port); |
| 306 | if (!err && stat) |
| 307 | { |
| 308 | err = __io_stat (*port, stat); |
| 309 | if (err) |
| 310 | __mach_port_deallocate (__mach_task_self (), *port); |
| 311 | } |
| 312 | |
| 313 | return err; |
| 314 | } |
| 315 | |
| 316 | check_no_hidden(__open); |
| 317 | check_no_hidden (__open64); |
| 318 | check_no_hidden (__open_nocancel); |
| 319 | int weak_function |
| 320 | __open (const char *file_name, int mode, ...) |
| 321 | { |
| 322 | mach_port_t port; |
| 323 | error_t err = open_file (file_name, mode, &port, 0); |
| 324 | if (err) |
| 325 | return __hurd_fail (err); |
| 326 | else |
| 327 | return (int)port; |
| 328 | } |
| 329 | weak_alias (__open, __open64) |
| 330 | weak_alias (__open, __open_nocancel) |
| 331 | |
| 332 | check_no_hidden(__close); |
| 333 | check_no_hidden(__close_nocancel); |
| 334 | int weak_function |
| 335 | __close (int fd) |
| 336 | { |
| 337 | if (fd != (int) MACH_PORT_NULL) |
| 338 | __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd); |
| 339 | return 0; |
| 340 | } |
| 341 | weak_alias (__close, __close_nocancel) |
| 342 | |
| 343 | check_no_hidden(__pread64); |
| 344 | check_no_hidden(__pread64_nocancel); |
| 345 | __ssize_t weak_function |
| 346 | __pread64 (int fd, void *buf, size_t nbytes, off64_t offset) |
| 347 | { |
| 348 | error_t err; |
| 349 | char *data; |
| 350 | mach_msg_type_number_t nread; |
| 351 | |
| 352 | data = buf; |
| 353 | nread = nbytes; |
| 354 | err = __io_read ((mach_port_t) fd, &data, &nread, offset, nbytes); |
| 355 | if (err) |
| 356 | return __hurd_fail (err); |
| 357 | |
| 358 | if (data != buf) |
| 359 | { |
| 360 | memcpy (buf, data, nread); |
| 361 | __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread); |
| 362 | } |
| 363 | |
| 364 | return nread; |
| 365 | } |
| 366 | libc_hidden_weak (__pread64) |
| 367 | weak_alias (__pread64, __pread64_nocancel) |
| 368 | |
| 369 | check_no_hidden(__read); |
| 370 | check_no_hidden(__read_nocancel); |
| 371 | __ssize_t weak_function |
| 372 | __read (int fd, void *buf, size_t nbytes) |
| 373 | { |
| 374 | return __pread64 (fd, buf, nbytes, -1); |
| 375 | } |
| 376 | libc_hidden_weak (__read) |
| 377 | weak_alias (__read, __read_nocancel) |
| 378 | |
| 379 | check_no_hidden(__write); |
| 380 | check_no_hidden(__write_nocancel); |
| 381 | __ssize_t weak_function |
| 382 | __write (int fd, const void *buf, size_t nbytes) |
| 383 | { |
| 384 | error_t err; |
| 385 | vm_size_t nwrote; |
| 386 | |
| 387 | assert (fd < _hurd_init_dtablesize); |
| 388 | |
| 389 | err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote); |
| 390 | if (err) |
| 391 | return __hurd_fail (err); |
| 392 | |
| 393 | return nwrote; |
| 394 | } |
| 395 | libc_hidden_weak (__write) |
| 396 | weak_alias (__write, __write_nocancel) |
| 397 | |
| 398 | /* This is only used for printing messages (see dl-misc.c). */ |
| 399 | check_no_hidden(__writev); |
| 400 | __ssize_t weak_function |
| 401 | __writev (int fd, const struct iovec *iov, int niov) |
| 402 | { |
| 403 | if (fd >= _hurd_init_dtablesize) |
| 404 | return __hurd_fail (EBADF); |
| 405 | |
| 406 | int i; |
| 407 | size_t total = 0; |
| 408 | for (i = 0; i < niov; ++i) |
| 409 | total += iov[i].iov_len; |
| 410 | |
| 411 | if (total != 0) |
| 412 | { |
| 413 | char buf[total], *bufp = buf; |
| 414 | error_t err; |
| 415 | vm_size_t nwrote; |
| 416 | |
| 417 | for (i = 0; i < niov; ++i) |
| 418 | bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len) |
| 419 | + iov[i].iov_len); |
| 420 | |
| 421 | err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote); |
| 422 | if (err) |
| 423 | return __hurd_fail (err); |
| 424 | |
| 425 | return nwrote; |
| 426 | } |
| 427 | return 0; |
| 428 | } |
| 429 | |
| 430 | check_no_hidden(__libc_lseek64); |
| 431 | off64_t weak_function |
| 432 | __libc_lseek64 (int fd, off64_t offset, int whence) |
| 433 | { |
| 434 | error_t err; |
| 435 | |
| 436 | err = __io_seek ((mach_port_t) fd, offset, whence, &offset); |
| 437 | if (err) |
| 438 | return __hurd_fail (err); |
| 439 | |
| 440 | return offset; |
| 441 | } |
| 442 | |
| 443 | check_no_hidden(__mmap); |
| 444 | void *weak_function |
| 445 | __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset) |
| 446 | { |
| 447 | error_t err; |
| 448 | vm_prot_t vmprot; |
| 449 | vm_address_t mapaddr, mask; |
| 450 | mach_port_t memobj_rd, memobj_wr; |
| 451 | |
| 452 | vmprot = VM_PROT_NONE; |
| 453 | if (prot & PROT_READ) |
| 454 | vmprot |= VM_PROT_READ; |
| 455 | if (prot & PROT_WRITE) |
| 456 | vmprot |= VM_PROT_WRITE; |
| 457 | if (prot & PROT_EXEC) |
| 458 | vmprot |= VM_PROT_EXECUTE; |
| 459 | |
| 460 | #ifdef __LP64__ |
| 461 | if ((addr == NULL) && (prot & PROT_EXEC) |
| 462 | && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC)) |
| 463 | flags |= MAP_32BIT; |
| 464 | #endif |
| 465 | mask = (flags & MAP_32BIT) ? ~(vm_address_t) 0x7FFFFFFF : 0; |
| 466 | |
| 467 | if (flags & MAP_ANON) |
| 468 | memobj_rd = MACH_PORT_NULL; |
| 469 | else |
| 470 | { |
| 471 | assert (!(flags & MAP_SHARED)); |
| 472 | err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr); |
| 473 | if (err) |
| 474 | return __hurd_fail (err), MAP_FAILED; |
| 475 | if (MACH_PORT_VALID (memobj_wr)) |
| 476 | __mach_port_deallocate (__mach_task_self (), memobj_wr); |
| 477 | } |
| 478 | |
| 479 | mapaddr = (vm_address_t) addr; |
| 480 | err = __vm_map (__mach_task_self (), |
| 481 | &mapaddr, (vm_size_t) len, mask, |
| 482 | !(flags & MAP_FIXED), |
| 483 | memobj_rd, |
| 484 | (vm_offset_t) offset, |
| 485 | flags & (MAP_COPY|MAP_PRIVATE), |
| 486 | vmprot, VM_PROT_ALL, |
| 487 | (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY); |
| 488 | if (err == KERN_NO_SPACE && (flags & MAP_FIXED)) |
| 489 | { |
| 490 | /* XXX this is not atomic as it is in unix! */ |
| 491 | /* The region is already allocated; deallocate it first. */ |
| 492 | err = __vm_deallocate (__mach_task_self (), mapaddr, len); |
| 493 | if (! err) |
| 494 | err = __vm_map (__mach_task_self (), |
| 495 | &mapaddr, (vm_size_t) len, |
| 496 | mask, |
| 497 | !(flags & MAP_FIXED), |
| 498 | memobj_rd, (vm_offset_t) offset, |
| 499 | flags & (MAP_COPY|MAP_PRIVATE), |
| 500 | vmprot, VM_PROT_ALL, |
| 501 | (flags & MAP_SHARED) |
| 502 | ? VM_INHERIT_SHARE : VM_INHERIT_COPY); |
| 503 | } |
| 504 | |
| 505 | if ((flags & MAP_ANON) == 0) |
| 506 | __mach_port_deallocate (__mach_task_self (), memobj_rd); |
| 507 | |
| 508 | if (err) |
| 509 | return __hurd_fail (err), MAP_FAILED; |
| 510 | return (void *) mapaddr; |
| 511 | } |
| 512 | |
| 513 | check_no_hidden(__fstat64); |
| 514 | int weak_function |
| 515 | __fstat64 (int fd, struct stat64 *buf) |
| 516 | { |
| 517 | error_t err; |
| 518 | |
| 519 | err = __io_stat ((mach_port_t) fd, buf); |
| 520 | if (err) |
| 521 | return __hurd_fail (err); |
| 522 | |
| 523 | return 0; |
| 524 | } |
| 525 | libc_hidden_def (__fstat64) |
| 526 | |
| 527 | check_no_hidden(__stat64); |
| 528 | int weak_function |
| 529 | __stat64 (const char *file, struct stat64 *buf) |
| 530 | { |
| 531 | error_t err; |
| 532 | mach_port_t port; |
| 533 | |
| 534 | err = open_file (file, 0, &port, buf); |
| 535 | if (err) |
| 536 | return __hurd_fail (err); |
| 537 | |
| 538 | __mach_port_deallocate (__mach_task_self (), port); |
| 539 | |
| 540 | return 0; |
| 541 | } |
| 542 | libc_hidden_def (__stat64) |
| 543 | |
| 544 | /* This function is called by the dynamic linker (rtld.c) to check for |
| 545 | existence of /etc/ld.so.preload. This stub will always fail, which |
| 546 | means that /etc/ld.so.preload is unsupported. */ |
| 547 | check_no_hidden(__access); |
| 548 | int weak_function |
| 549 | __access (const char *file, int type) |
| 550 | { |
| 551 | return __hurd_fail (ENOSYS); |
| 552 | } |
| 553 | |
| 554 | int |
| 555 | __rtld_execve (const char *file_name, char *const argv[], |
| 556 | char *const envp[]) |
| 557 | { |
| 558 | file_t file; |
| 559 | error_t err; |
| 560 | char *args, *env; |
| 561 | size_t argslen, envlen; |
| 562 | mach_port_t *ports = _dl_hurd_data->portarray; |
| 563 | unsigned int portarraysize = _dl_hurd_data->portarraysize; |
| 564 | file_t *dtable = _dl_hurd_data->dtable; |
| 565 | unsigned int dtablesize = _dl_hurd_data->dtablesize; |
| 566 | int *intarray = _dl_hurd_data->intarray; |
| 567 | unsigned int i, j; |
| 568 | mach_port_t *please_dealloc, *pdp; |
| 569 | mach_port_t *portnames = NULL; |
| 570 | mach_msg_type_number_t nportnames = 0; |
| 571 | mach_port_type_t *porttypes = NULL; |
| 572 | mach_msg_type_number_t nporttypes = 0; |
| 573 | int flags; |
| 574 | |
| 575 | err = open_file (file_name, O_EXEC, &file, NULL); |
| 576 | if (err) |
| 577 | goto out; |
| 578 | |
| 579 | if (argv == NULL) |
| 580 | args = NULL, argslen = 0; |
| 581 | else if (err = __argz_create (argv, &args, &argslen)) |
| 582 | goto outfile; |
| 583 | if (envp == NULL) |
| 584 | env = NULL, envlen = 0; |
| 585 | else if (err = __argz_create (envp, &env, &envlen)) |
| 586 | goto outargs; |
| 587 | |
| 588 | please_dealloc = __alloca ((portarraysize + dtablesize) |
| 589 | * sizeof (mach_port_t)); |
| 590 | pdp = please_dealloc; |
| 591 | |
| 592 | /* Get all ports that we may not know about and we should thus destroy. */ |
| 593 | err = __mach_port_names (__mach_task_self (), |
| 594 | &portnames, &nportnames, |
| 595 | &porttypes, &nporttypes); |
| 596 | if (err) |
| 597 | goto outenv; |
| 598 | if (nportnames != nporttypes) |
| 599 | { |
| 600 | err = EGRATUITOUS; |
| 601 | goto outenv; |
| 602 | } |
| 603 | |
| 604 | for (i = 0; i < portarraysize; ++i) |
| 605 | if (ports[i] != MACH_PORT_NULL) |
| 606 | { |
| 607 | *pdp++ = ports[i]; |
| 608 | for (j = 0; j < nportnames; j++) |
| 609 | if (portnames[j] == ports[i]) |
| 610 | portnames[j] = MACH_PORT_NULL; |
| 611 | } |
| 612 | for (i = 0; i < dtablesize; ++i) |
| 613 | if (dtable[i] != MACH_PORT_NULL) |
| 614 | { |
| 615 | *pdp++ = dtable[i]; |
| 616 | for (j = 0; j < nportnames; j++) |
| 617 | if (portnames[j] == dtable[i]) |
| 618 | portnames[j] = MACH_PORT_NULL; |
| 619 | } |
| 620 | |
| 621 | /* Pack ports to be destroyed together. */ |
| 622 | for (i = 0, j = 0; i < nportnames; i++) |
| 623 | { |
| 624 | if (portnames[i] == MACH_PORT_NULL) |
| 625 | continue; |
| 626 | if (j != i) |
| 627 | portnames[j] = portnames[i]; |
| 628 | j++; |
| 629 | } |
| 630 | nportnames = j; |
| 631 | |
| 632 | flags = 0; |
| 633 | #ifdef EXEC_SIGTRAP |
| 634 | if (__sigismember (&intarray[INIT_TRACEMASK], SIGKILL)) |
| 635 | flags |= EXEC_SIGTRAP; |
| 636 | #endif |
| 637 | |
| 638 | err = __file_exec_paths (file, __mach_task_self (), flags, |
| 639 | file_name, file_name[0] == '/' ? file_name : "" , |
| 640 | args, argslen, |
| 641 | env, envlen, |
| 642 | dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize, |
| 643 | ports, MACH_MSG_TYPE_COPY_SEND, portarraysize, |
| 644 | intarray, INIT_INT_MAX, |
| 645 | please_dealloc, pdp - please_dealloc, |
| 646 | portnames, nportnames); |
| 647 | |
| 648 | /* Oh well. Might as well be tidy. */ |
| 649 | outenv: |
| 650 | free (env); |
| 651 | outargs: |
| 652 | free (args); |
| 653 | outfile: |
| 654 | __mach_port_deallocate (__mach_task_self (), file); |
| 655 | out: |
| 656 | return err; |
| 657 | } |
| 658 | |
| 659 | check_no_hidden(__getpid); |
| 660 | pid_t weak_function |
| 661 | __getpid (void) |
| 662 | { |
| 663 | pid_t pid, ppid; |
| 664 | int orphaned; |
| 665 | |
| 666 | if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC], |
| 667 | &pid, &ppid, &orphaned)) |
| 668 | return -1; |
| 669 | |
| 670 | return pid; |
| 671 | } |
| 672 | |
| 673 | /* We need this alias to satisfy references from libc_pic.a objects |
| 674 | that were affected by the libc_hidden_proto declaration for __getpid. */ |
| 675 | strong_alias (__getpid, __GI___getpid) |
| 676 | |
| 677 | /* This is called only in some strange cases trying to guess a value |
| 678 | for $ORIGIN for the executable. The dynamic linker copes with |
| 679 | getcwd failing (dl-object.c), and it's too much hassle to include |
| 680 | the functionality here. (We could, it just requires duplicating or |
| 681 | reusing getcwd.c's code but using our special lookup function as in |
| 682 | `open', above.) */ |
| 683 | check_no_hidden(__getcwd); |
| 684 | char *weak_function |
| 685 | __getcwd (char *buf, size_t size) |
| 686 | { |
| 687 | return __hurd_fail (ENOSYS), NULL; |
| 688 | } |
| 689 | |
| 690 | /* This is used by dl-tunables.c to strdup strings. We can just make this a |
| 691 | mere allocation. */ |
| 692 | check_no_hidden(__sbrk); |
| 693 | void *weak_function |
| 694 | __sbrk (intptr_t increment) |
| 695 | { |
| 696 | vm_address_t addr; |
| 697 | if (__vm_allocate (__mach_task_self (), &addr, increment, 1)) |
| 698 | return NULL; |
| 699 | return (void *) addr; |
| 700 | } |
| 701 | |
| 702 | /* This is only used by hurdlookup for the /dev/fd/nnn magic. |
| 703 | * We avoid pulling the whole libc implementation, and we can keep this hidden. */ |
| 704 | unsigned long int weak_function |
| 705 | __strtoul_internal (const char *nptr, char **endptr, int base, int group) |
| 706 | { |
| 707 | assert (base == 0 || base == 10); |
| 708 | assert (group == 0); |
| 709 | return _dl_strtoul (nptr, endptr); |
| 710 | } |
| 711 | |
| 712 | /* We need this alias to satisfy references from libc_pic.a objects |
| 713 | that were affected by the libc_hidden_proto declaration for __strtoul_internal. */ |
| 714 | strong_alias (__strtoul_internal, __GI___strtoul_internal) |
| 715 | strong_alias (__strtoul_internal, __GI_____strtoul_internal) |
| 716 | |
| 717 | check_no_hidden(_exit); |
| 718 | void weak_function attribute_hidden |
| 719 | _exit (int status) |
| 720 | { |
| 721 | __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC], |
| 722 | W_EXITCODE (status, 0), 0); |
| 723 | while (__task_terminate (__mach_task_self ())) |
| 724 | __mach_task_self_ = (__mach_task_self) (); |
| 725 | |
| 726 | LOSE; |
| 727 | abort (); |
| 728 | } |
| 729 | /* We need this alias to satisfy references from libc_pic.a objects |
| 730 | that were affected by the libc_hidden_proto declaration for _exit. */ |
| 731 | strong_alias (_exit, __GI__exit) |
| 732 | |
| 733 | /* Try to get a machine dependent instruction which will make the |
| 734 | program crash. This is used in case everything else fails. */ |
| 735 | #include <abort-instr.h> |
| 736 | #ifndef ABORT_INSTRUCTION |
| 737 | /* No such instruction is available. */ |
| 738 | # define ABORT_INSTRUCTION |
| 739 | #endif |
| 740 | |
| 741 | check_no_hidden(abort); |
| 742 | void weak_function |
| 743 | abort (void) |
| 744 | { |
| 745 | /* Try to abort using the system specific command. */ |
| 746 | ABORT_INSTRUCTION; |
| 747 | |
| 748 | /* If the abort instruction failed, exit. */ |
| 749 | _exit (127); |
| 750 | |
| 751 | /* If even this fails, make sure we never return. */ |
| 752 | while (1) |
| 753 | /* Try for ever and ever. */ |
| 754 | ABORT_INSTRUCTION; |
| 755 | } |
| 756 | |
| 757 | /* We need this alias to satisfy references from libc_pic.a objects |
| 758 | that were affected by the libc_hidden_proto declaration for abort. */ |
| 759 | strong_alias (abort, __GI_abort) |
| 760 | strong_alias (abort, __GI___fortify_fail) |
| 761 | strong_alias (abort, __GI___assert_fail) |
| 762 | strong_alias (abort, __GI___assert_perror_fail) |
| 763 | |
| 764 | /* This function is called by interruptible RPC stubs. For initial |
| 765 | dynamic linking, just use the normal mach_msg. Since this defn is |
| 766 | weak, the real defn in libc.so will override it if we are linked into |
| 767 | the user program (-ldl). */ |
| 768 | |
| 769 | error_t weak_function |
| 770 | _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, |
| 771 | mach_msg_option_t option, |
| 772 | mach_msg_size_t send_size, |
| 773 | mach_msg_size_t rcv_size, |
| 774 | mach_port_t rcv_name, |
| 775 | mach_msg_timeout_t timeout, |
| 776 | mach_port_t notify) |
| 777 | { |
| 778 | return __mach_msg (msg, option, send_size, rcv_size, rcv_name, |
| 779 | timeout, notify); |
| 780 | } |
| 781 | |
| 782 | |
| 783 | void |
| 784 | _dl_show_auxv (void) |
| 785 | { |
| 786 | /* There is nothing to print. Hurd has no auxiliary vector. */ |
| 787 | } |
| 788 | |
| 789 | |
| 790 | void weak_function |
| 791 | _dl_init_first (void *p) |
| 792 | { |
| 793 | /* This no-op definition only gets used if libc is not linked in. */ |
| 794 | } |
| 795 | |
| 796 | #endif /* SHARED */ |
| 797 | |