xref: /haiku/src/system/runtime_loader/runtime_loader.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 	// 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
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
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
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
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
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
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
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
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
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
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