1 /* 2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002, Manuel J. Petit. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include "runtime_loader_private.h" 11 12 #include <string.h> 13 #include <stdlib.h> 14 #include <sys/stat.h> 15 16 #include <algorithm> 17 18 #include <ByteOrder.h> 19 20 #include <directories.h> 21 #include <find_directory_private.h> 22 #include <image_defs.h> 23 #include <syscalls.h> 24 #include <user_runtime.h> 25 #include <vm_defs.h> 26 27 #include "elf_symbol_lookup.h" 28 #include "pe.h" 29 30 31 struct user_space_program_args *gProgramArgs; 32 void *__gCommPageAddress; 33 void *__dso_handle; 34 35 int32 __gCPUCount = 1; 36 37 const directory_which kLibraryDirectories[] = { 38 B_SYSTEM_LIB_DIRECTORY, 39 B_SYSTEM_NONPACKAGED_LIB_DIRECTORY, 40 B_USER_LIB_DIRECTORY, 41 B_USER_NONPACKAGED_LIB_DIRECTORY 42 }; 43 44 45 static const char * 46 search_path_for_type(image_type type) 47 { 48 const char *path = NULL; 49 50 // TODO: The *PATH variables should not include the standard system paths. 51 // Instead those paths should always be used after the directories specified 52 // via the variables. 53 switch (type) { 54 case B_APP_IMAGE: 55 path = getenv("PATH"); 56 break; 57 case B_LIBRARY_IMAGE: 58 path = getenv("LIBRARY_PATH"); 59 break; 60 case B_ADD_ON_IMAGE: 61 path = getenv("ADDON_PATH"); 62 break; 63 64 default: 65 return NULL; 66 } 67 68 if (path != NULL) 69 return path; 70 71 // The environment variables may not have been set yet - in that case, 72 // we're returning some useful defaults. 73 // Since the kernel does not set any variables, this is also needed 74 // to start the root shell. 75 76 // TODO: The user specific paths should not be used by default. 77 switch (type) { 78 case B_APP_IMAGE: 79 return kUserNonpackagedBinDirectory 80 ":" kUserBinDirectory 81 // TODO: Remove! 82 ":" kSystemNonpackagedBinDirectory 83 ":" kGlobalBinDirectory 84 ":" kSystemAppsDirectory 85 ":" kSystemPreferencesDirectory; 86 87 case B_LIBRARY_IMAGE: 88 return kAppLocalLibDirectory 89 ":" kUserNonpackagedLibDirectory 90 ":" kUserLibDirectory 91 // TODO: Remove! 92 ":" kSystemNonpackagedLibDirectory 93 ":" kSystemLibDirectory; 94 95 case B_ADD_ON_IMAGE: 96 return kAppLocalAddonsDirectory 97 ":" kUserNonpackagedAddonsDirectory 98 ":" kUserAddonsDirectory 99 // TODO: Remove! 100 ":" kSystemNonpackagedAddonsDirectory 101 ":" kSystemAddonsDirectory; 102 103 default: 104 return NULL; 105 } 106 } 107 108 109 static bool 110 replace_executable_path_placeholder(const char*& dir, int& dirLength, 111 const char* placeholder, size_t placeholderLength, 112 const char* replacementSubPath, char*& buffer, size_t& bufferSize, 113 status_t& _error) 114 { 115 if (dirLength < (int)placeholderLength 116 || strncmp(dir, placeholder, placeholderLength) != 0) { 117 return false; 118 } 119 120 if (replacementSubPath == NULL) { 121 _error = B_ENTRY_NOT_FOUND; 122 return true; 123 } 124 125 char* lastSlash = strrchr(replacementSubPath, '/'); 126 127 // Copy replacementSubPath without the last component (the application file 128 // name, respectively the requesting executable file name). 129 size_t toCopy; 130 if (lastSlash != NULL) { 131 toCopy = lastSlash - replacementSubPath; 132 strlcpy(buffer, replacementSubPath, 133 std::min((ssize_t)bufferSize, lastSlash + 1 - replacementSubPath)); 134 } else { 135 replacementSubPath = "."; 136 toCopy = 1; 137 strlcpy(buffer, ".", bufferSize); 138 } 139 140 if (toCopy >= bufferSize) { 141 _error = B_NAME_TOO_LONG; 142 return true; 143 } 144 145 memcpy(buffer, replacementSubPath, toCopy); 146 buffer[toCopy] = '\0'; 147 148 buffer += toCopy; 149 bufferSize -= toCopy; 150 dir += placeholderLength; 151 dirLength -= placeholderLength; 152 153 _error = B_OK; 154 return true; 155 } 156 157 158 static int 159 try_open_executable(const char *dir, int dirLength, const char *name, 160 const char *programPath, const char *requestingObjectPath, 161 const char *abiSpecificSubDir, char *path, size_t pathLength) 162 { 163 size_t nameLength = strlen(name); 164 struct stat stat; 165 status_t status; 166 167 // construct the path 168 if (dirLength > 0) { 169 char *buffer = path; 170 size_t subDirLen = 0; 171 172 if (programPath == NULL) 173 programPath = gProgramArgs->program_path; 174 175 if (replace_executable_path_placeholder(dir, dirLength, "%A", 2, 176 programPath, buffer, pathLength, status) 177 || replace_executable_path_placeholder(dir, dirLength, "$ORIGIN", 7, 178 requestingObjectPath, buffer, pathLength, status)) { 179 if (status != B_OK) 180 return status; 181 } else if (abiSpecificSubDir != NULL) { 182 // We're looking for a library or an add-on and the executable has 183 // not been compiled with a compiler using the same ABI as the one 184 // the OS has been built with. Thus we only look in subdirs 185 // specific to that ABI. 186 // However, only if it's a known library location 187 for (int i = 0; i < 4; ++i) { 188 char buffer[PATH_MAX]; 189 status_t result = __find_directory(kLibraryDirectories[i], -1, 190 false, buffer, PATH_MAX); 191 if (result == B_OK && strncmp(dir, buffer, dirLength) == 0) { 192 subDirLen = strlen(abiSpecificSubDir) + 1; 193 break; 194 } 195 } 196 } 197 198 if (dirLength + 1 + subDirLen + nameLength >= pathLength) 199 return B_NAME_TOO_LONG; 200 201 memcpy(buffer, dir, dirLength); 202 buffer[dirLength] = '/'; 203 if (subDirLen > 0) { 204 memcpy(buffer + dirLength + 1, abiSpecificSubDir, subDirLen - 1); 205 buffer[dirLength + subDirLen] = '/'; 206 } 207 strcpy(buffer + dirLength + 1 + subDirLen, name); 208 } else { 209 if (nameLength >= pathLength) 210 return B_NAME_TOO_LONG; 211 212 strcpy(path + dirLength + 1, name); 213 } 214 215 TRACE(("runtime_loader: try_open_container(): %s\n", path)); 216 217 // Test if the target is a symbolic link, and correct the path in this case 218 219 status = _kern_read_stat(-1, path, false, &stat, sizeof(struct stat)); 220 if (status < B_OK) 221 return status; 222 223 if (S_ISLNK(stat.st_mode)) { 224 char buffer[PATH_MAX]; 225 size_t length = PATH_MAX - 1; 226 char *lastSlash; 227 228 // it's a link, indeed 229 status = _kern_read_link(-1, path, buffer, &length); 230 if (status < B_OK) 231 return status; 232 buffer[length] = '\0'; 233 234 lastSlash = strrchr(path, '/'); 235 if (buffer[0] != '/' && lastSlash != NULL) { 236 // relative path 237 strlcpy(lastSlash + 1, buffer, lastSlash + 1 - path + pathLength); 238 } else 239 strlcpy(path, buffer, pathLength); 240 } 241 242 return _kern_open(-1, path, O_RDONLY, 0); 243 } 244 245 246 static int 247 search_executable_in_path_list(const char *name, const char *pathList, 248 int pathListLen, const char *programPath, const char *requestingObjectPath, 249 const char *abiSpecificSubDir, char *pathBuffer, size_t pathBufferLength) 250 { 251 const char *pathListEnd = pathList + pathListLen; 252 status_t status = B_ENTRY_NOT_FOUND; 253 254 TRACE(("runtime_loader: search_container_in_path_list() %s in %.*s\n", name, 255 pathListLen, pathList)); 256 257 while (pathListLen > 0) { 258 const char *pathEnd = pathList; 259 int fd; 260 261 // find the next ':' or run till the end of the string 262 while (pathEnd < pathListEnd && *pathEnd != ':') 263 pathEnd++; 264 265 fd = try_open_executable(pathList, pathEnd - pathList, name, 266 programPath, requestingObjectPath, abiSpecificSubDir, pathBuffer, 267 pathBufferLength); 268 if (fd >= 0) { 269 // see if it's a dir 270 struct stat stat; 271 status = _kern_read_stat(fd, NULL, true, &stat, sizeof(struct stat)); 272 if (status == B_OK) { 273 if (!S_ISDIR(stat.st_mode)) 274 return fd; 275 status = B_IS_A_DIRECTORY; 276 } 277 _kern_close(fd); 278 } 279 280 pathListLen = pathListEnd - pathEnd - 1; 281 pathList = pathEnd + 1; 282 } 283 284 return status; 285 } 286 287 288 int 289 open_executable(char *name, image_type type, const char *rpath, 290 const char *programPath, const char *requestingObjectPath, 291 const char *abiSpecificSubDir) 292 { 293 char buffer[PATH_MAX]; 294 int fd = B_ENTRY_NOT_FOUND; 295 296 if (strchr(name, '/')) { 297 // the name already contains a path, we don't have to search for it 298 fd = _kern_open(-1, name, O_RDONLY, 0); 299 if (fd >= 0 || type == B_APP_IMAGE) 300 return fd; 301 302 // can't search harder an absolute path add-on name! 303 if (type == B_ADD_ON_IMAGE && name[0] == '/') 304 return fd; 305 306 // Even though ELF specs don't say this, we give shared libraries 307 // and relative path based add-ons another chance and look 308 // them up in the usual search paths - at 309 // least that seems to be what BeOS does, and since it doesn't hurt... 310 if (type == B_LIBRARY_IMAGE) { 311 // For library (but not add-on), strip any path from name. 312 // Relative path of add-on is kept. 313 const char* paths = strrchr(name, '/') + 1; 314 memmove(name, paths, strlen(paths) + 1); 315 } 316 } 317 318 // try rpath (DT_RPATH) 319 if (rpath != NULL) { 320 // It consists of a colon-separated search path list. Optionally a 321 // second search path list follows, separated from the first by a 322 // semicolon. 323 const char *semicolon = strchr(rpath, ';'); 324 const char *firstList = (semicolon ? rpath : NULL); 325 const char *secondList = (semicolon ? semicolon + 1 : rpath); 326 // If there is no ';', we set only secondList to simplify things. 327 if (firstList) { 328 fd = search_executable_in_path_list(name, firstList, 329 semicolon - firstList, programPath, requestingObjectPath, NULL, 330 buffer, sizeof(buffer)); 331 } 332 if (fd < 0) { 333 fd = search_executable_in_path_list(name, secondList, 334 strlen(secondList), programPath, requestingObjectPath, NULL, 335 buffer, sizeof(buffer)); 336 } 337 } 338 339 // If not found yet, let's evaluate the system path variables to find the 340 // shared object. 341 if (fd < 0) { 342 if (const char *paths = search_path_for_type(type)) { 343 fd = search_executable_in_path_list(name, paths, strlen(paths), 344 programPath, NULL, abiSpecificSubDir, buffer, sizeof(buffer)); 345 } 346 } 347 348 if (fd >= 0) { 349 // we found it, copy path! 350 TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer)); 351 strlcpy(name, buffer, PATH_MAX); 352 } 353 354 return fd; 355 } 356 357 358 /*! 359 Applies haiku-specific fixes to a shebang line. 360 */ 361 static void 362 fixup_shebang(char *invoker) 363 { 364 char *current = invoker; 365 while (*current == ' ' || *current == '\t') { 366 ++current; 367 } 368 369 char *commandStart = current; 370 while (*current != ' ' && *current != '\t' && *current != '\0') { 371 ++current; 372 } 373 374 // replace /usr/bin/env with /bin/env 375 if (memcmp(commandStart, "/usr/bin/env", current - commandStart) == 0) 376 memmove(commandStart, commandStart + 4, strlen(commandStart + 4) + 1); 377 } 378 379 380 /*! 381 Tests if there is an executable file at the provided path. It will 382 also test if the file has a valid ELF header or is a shell script. 383 Even if the runtime loader does not need to be able to deal with 384 both types, the caller will give scripts a proper treatment. 385 */ 386 status_t 387 test_executable(const char *name, char *invoker) 388 { 389 char path[B_PATH_NAME_LENGTH]; 390 char buffer[B_FILE_NAME_LENGTH]; 391 // must be large enough to hold the ELF header 392 status_t status; 393 ssize_t length; 394 int fd; 395 396 if (name == NULL) 397 return B_BAD_VALUE; 398 399 strlcpy(path, name, sizeof(path)); 400 401 fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL, NULL); 402 if (fd < B_OK) 403 return fd; 404 405 // see if it's executable at all 406 status = _kern_access(-1, path, X_OK, false); 407 if (status != B_OK) 408 goto out; 409 410 // read and verify the ELF header 411 412 length = _kern_read(fd, 0, buffer, sizeof(buffer)); 413 if (length < 0) { 414 status = length; 415 goto out; 416 } 417 418 status = elf_verify_header(buffer, length); 419 #ifdef _COMPAT_MODE 420 #ifdef __x86_64__ 421 if (status == B_NOT_AN_EXECUTABLE) 422 status = elf32_verify_header(buffer, length); 423 #else 424 if (status == B_NOT_AN_EXECUTABLE) 425 status = elf64_verify_header(buffer, length); 426 #endif // __x86_64__ 427 #endif // _COMPAT_MODE 428 if (status == B_NOT_AN_EXECUTABLE) { 429 if (!strncmp(buffer, "#!", 2)) { 430 // test for shell scripts 431 char *end; 432 buffer[min_c((size_t)length, sizeof(buffer) - 1)] = '\0'; 433 434 end = strchr(buffer, '\n'); 435 if (end == NULL) { 436 status = E2BIG; 437 goto out; 438 } else 439 end[0] = '\0'; 440 441 if (invoker) { 442 strcpy(invoker, buffer + 2); 443 fixup_shebang(invoker); 444 } 445 446 status = B_OK; 447 } else { 448 // Something odd like a PE? 449 status = pe_verify_header(buffer, length); 450 451 // It is a PE, throw B_UNKNOWN_EXECUTABLE 452 // likely win32 at this point 453 if (status == B_OK) 454 status = B_UNKNOWN_EXECUTABLE; 455 } 456 } else if (status == B_OK) { 457 elf_ehdr *elfHeader = (elf_ehdr *)buffer; 458 if (elfHeader->e_entry == 0) { 459 // we don't like to open shared libraries 460 status = B_NOT_AN_EXECUTABLE; 461 } else if (invoker) 462 invoker[0] = '\0'; 463 } 464 465 out: 466 _kern_close(fd); 467 return status; 468 } 469 470 471 static bool 472 determine_x86_abi(int fd, const Elf32_Ehdr& elfHeader, bool& _isGcc2) 473 { 474 // Unless we're a little-endian CPU, don't bother. We're not x86, so it 475 // doesn't matter all that much whether we can determine the correct gcc 476 // ABI. This saves the code below from having to deal with endianess 477 // conversion. 478 #if B_HOST_IS_LENDIAN 479 480 // Since we don't want to load the complete image, we can't use the 481 // functions that normally determine the Haiku version and ABI. Instead 482 // we'll load the symbol and string tables and resolve the ABI symbol 483 // manually. 484 485 // map the file into memory 486 struct stat st; 487 if (_kern_read_stat(fd, NULL, true, &st, sizeof(st)) != B_OK) 488 return false; 489 490 void* fileBaseAddress; 491 area_id area = _kern_map_file("mapped file", &fileBaseAddress, 492 B_ANY_ADDRESS, st.st_size, B_READ_AREA, REGION_NO_PRIVATE_MAP, false, 493 fd, 0); 494 if (area < 0) 495 return false; 496 497 struct AreaDeleter { 498 AreaDeleter(area_id area) 499 : 500 fArea(area) 501 { 502 } 503 504 ~AreaDeleter() 505 { 506 _kern_delete_area(fArea); 507 } 508 509 private: 510 area_id fArea; 511 } areaDeleter(area); 512 513 // get the section headers 514 if (elfHeader.e_shoff == 0 || elfHeader.e_shentsize < sizeof(Elf32_Shdr)) 515 return false; 516 517 size_t sectionHeadersSize = elfHeader.e_shentsize * elfHeader.e_shnum; 518 if (elfHeader.e_shoff + (off_t)sectionHeadersSize > st.st_size) 519 return false; 520 521 void* sectionHeaders = (uint8*)fileBaseAddress + elfHeader.e_shoff; 522 523 // find the sections we need 524 uint32* symbolHash = NULL; 525 uint32 symbolHashSize = 0; 526 uint32 symbolHashChainSize = 0; 527 Elf32_Sym* symbolTable = NULL; 528 uint32 symbolTableSize = 0; 529 const char* stringTable = NULL; 530 off_t stringTableSize = 0; 531 532 for (int32 i = 0; i < elfHeader.e_shnum; i++) { 533 Elf32_Shdr* sectionHeader 534 = (Elf32_Shdr*)((uint8*)sectionHeaders + i * elfHeader.e_shentsize); 535 if ((off_t)sectionHeader->sh_offset + (off_t)sectionHeader->sh_size 536 > st.st_size) { 537 continue; 538 } 539 540 void* sectionAddress = (uint8*)fileBaseAddress 541 + sectionHeader->sh_offset; 542 543 switch (sectionHeader->sh_type) { 544 case SHT_HASH: 545 symbolHash = (uint32*)sectionAddress; 546 if (sectionHeader->sh_size < (off_t)sizeof(symbolHash[0])) 547 return false; 548 symbolHashSize = symbolHash[0]; 549 symbolHashChainSize 550 = sectionHeader->sh_size / sizeof(symbolHash[0]); 551 if (symbolHashChainSize < symbolHashSize + 2) 552 return false; 553 symbolHashChainSize -= symbolHashSize + 2; 554 break; 555 case SHT_DYNSYM: 556 symbolTable = (Elf32_Sym*)sectionAddress; 557 symbolTableSize = sectionHeader->sh_size; 558 break; 559 case SHT_STRTAB: 560 // .shstrtab has the same type as .dynstr, but it isn't loaded 561 // into memory. 562 if (sectionHeader->sh_addr == 0) 563 continue; 564 stringTable = (const char*)sectionAddress; 565 stringTableSize = (off_t)sectionHeader->sh_size; 566 break; 567 default: 568 continue; 569 } 570 } 571 572 if (symbolHash == NULL || symbolTable == NULL || stringTable == NULL) 573 return false; 574 uint32 symbolCount 575 = std::min(symbolTableSize / (uint32)sizeof(Elf32_Sym), 576 symbolHashChainSize); 577 if (symbolCount < symbolHashSize) 578 return false; 579 580 // look up the ABI symbol 581 const char* name = B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME; 582 size_t nameLength = strlen(name); 583 uint32 bucket = elf_hash(name) % symbolHashSize; 584 585 for (uint32 i = symbolHash[bucket + 2]; i < symbolCount && i != STN_UNDEF; 586 i = symbolHash[2 + symbolHashSize + i]) { 587 Elf32_Sym* symbol = symbolTable + i; 588 if (symbol->st_shndx != SHN_UNDEF 589 && ((symbol->Bind() == STB_GLOBAL) || (symbol->Bind() == STB_WEAK)) 590 && symbol->Type() == STT_OBJECT 591 && (off_t)symbol->st_name + (off_t)nameLength < stringTableSize 592 && strcmp(stringTable + symbol->st_name, name) == 0) { 593 if (symbol->st_value > 0 && symbol->st_size >= sizeof(uint32) 594 && symbol->st_shndx < elfHeader.e_shnum) { 595 Elf32_Shdr* sectionHeader = (Elf32_Shdr*)((uint8*)sectionHeaders 596 + symbol->st_shndx * elfHeader.e_shentsize); 597 if (symbol->st_value >= sectionHeader->sh_addr 598 && symbol->st_value 599 <= sectionHeader->sh_addr + sectionHeader->sh_size) { 600 off_t fileOffset = symbol->st_value - sectionHeader->sh_addr 601 + sectionHeader->sh_offset; 602 if (fileOffset + (off_t)sizeof(uint32) <= st.st_size) { 603 uint32 abi 604 = *(uint32*)((uint8*)fileBaseAddress + fileOffset); 605 _isGcc2 = (abi & B_HAIKU_ABI_MAJOR) 606 == B_HAIKU_ABI_GCC_2; 607 return true; 608 } 609 } 610 } 611 612 return false; 613 } 614 } 615 616 // ABI symbol not found. That means the object pre-dates its introduction 617 // in Haiku. So this is most likely gcc 2. We don't fall back to reading 618 // the comment sections to verify. 619 _isGcc2 = true; 620 return true; 621 #else // not little endian 622 return false; 623 #endif 624 } 625 626 627 static status_t 628 get_executable_architecture(int fd, const char** _architecture) 629 { 630 // Read the ELF header. We read the 32 bit header. Generally the e_machine 631 // field is the last one that interests us and the 64 bit header is still 632 // identical at that point. 633 Elf32_Ehdr elfHeader; 634 ssize_t bytesRead = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader)); 635 if (bytesRead < 0) 636 return bytesRead; 637 if ((size_t)bytesRead != sizeof(elfHeader)) 638 return B_NOT_AN_EXECUTABLE; 639 640 // check whether this is indeed an ELF file 641 if (memcmp(elfHeader.e_ident, ELFMAG, 4) != 0) 642 return B_NOT_AN_EXECUTABLE; 643 644 // check the architecture 645 uint16 machine = elfHeader.e_machine; 646 if ((elfHeader.e_ident[EI_DATA] == ELFDATA2LSB) != (B_HOST_IS_LENDIAN != 0)) 647 machine = (machine >> 8) | (machine << 8); 648 649 const char* architecture = NULL; 650 switch (machine) { 651 case EM_386: 652 case EM_486: 653 { 654 bool isGcc2; 655 if (determine_x86_abi(fd, elfHeader, isGcc2) && isGcc2) 656 architecture = "x86_gcc2"; 657 else 658 architecture = "x86"; 659 break; 660 } 661 case EM_68K: 662 architecture = "m68k"; 663 break; 664 case EM_PPC: 665 architecture = "ppc"; 666 break; 667 case EM_ARM: 668 architecture = "arm"; 669 break; 670 case EM_ARM64: 671 architecture = "arm64"; 672 break; 673 case EM_X86_64: 674 architecture = "x86_64"; 675 break; 676 case EM_RISCV: 677 architecture = "riscv"; 678 break; 679 } 680 681 if (architecture == NULL) 682 return B_NOT_SUPPORTED; 683 684 *_architecture = architecture; 685 return B_OK; 686 } 687 688 689 status_t 690 get_executable_architecture(const char* path, const char** _architecture) 691 { 692 int fd = _kern_open(-1, path, O_RDONLY, 0); 693 if (fd < 0) 694 return fd; 695 696 status_t error = get_executable_architecture(fd, _architecture); 697 698 _kern_close(fd); 699 return error; 700 } 701 702 703 /*! 704 This is the main entry point of the runtime loader as 705 specified by its ld-script. 706 */ 707 int 708 runtime_loader(void* _args, void* commpage) 709 { 710 void *entry = NULL; 711 int returnCode; 712 713 gProgramArgs = (struct user_space_program_args *)_args; 714 __gCommPageAddress = commpage; 715 716 // Relocate the args and env arrays -- they are organized in a contiguous 717 // buffer which the kernel just copied into user space without adjusting the 718 // pointers. 719 { 720 int32 i; 721 addr_t relocationOffset = 0; 722 723 if (gProgramArgs->arg_count > 0) 724 relocationOffset = (addr_t)gProgramArgs->args[0]; 725 else if (gProgramArgs->env_count > 0) 726 relocationOffset = (addr_t)gProgramArgs->env[0]; 727 728 // That's basically: <new buffer address> - <old buffer address>. 729 // It looks a little complicated, since we don't have the latter one at 730 // hand and thus need to reconstruct it (<first string pointer> - 731 // <arguments + environment array sizes>). 732 relocationOffset = (addr_t)gProgramArgs->args - relocationOffset 733 + (gProgramArgs->arg_count + gProgramArgs->env_count + 2) 734 * sizeof(char*); 735 736 for (i = 0; i < gProgramArgs->arg_count; i++) 737 gProgramArgs->args[i] += relocationOffset; 738 739 for (i = 0; i < gProgramArgs->env_count; i++) 740 gProgramArgs->env[i] += relocationOffset; 741 } 742 743 #if DEBUG_RLD 744 close(0); open("/dev/console", 0); /* stdin */ 745 close(1); open("/dev/console", 0); /* stdout */ 746 close(2); open("/dev/console", 0); /* stderr */ 747 #endif 748 749 if (heap_init() < B_OK) 750 return 1; 751 752 rldexport_init(); 753 rldelf_init(); 754 755 load_program(gProgramArgs->program_path, &entry); 756 757 if (entry == NULL) 758 return -1; 759 760 // call the program entry point (usually _start()) 761 returnCode = ((int (*)(int, void *, void *))entry)(gProgramArgs->arg_count, 762 gProgramArgs->args, gProgramArgs->env); 763 764 terminate_program(); 765 766 return returnCode; 767 } 768