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