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
31struct user_space_program_args *gProgramArgs;
32void *__gCommPageAddress;
33void *__dso_handle;
34
35int32 __gCPUCount = 1;
36
37const 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
45static const char *
46search_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
122static bool
123replace_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
171static int
172try_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(-1, 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(-1, 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(-1, path, O_RDONLY, 0);
256}
257
258
259static int
260search_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
301int
302open_executable(char *name, image_type type, const char *rpath,
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(-1, 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 rpath (DT_RPATH)
332	if (rpath != NULL) {
333		// It consists of a colon-separated search path list. Optionally a
334		// second search path list follows, separated from the first by a
335		// semicolon.
336		const char *semicolon = strchr(rpath, ';');
337		const char *firstList = (semicolon ? rpath : NULL);
338		const char *secondList = (semicolon ? semicolon + 1 : rpath);
339			// If there is no ';', we set only secondList to simplify things.
340		if (firstList) {
341			fd = search_executable_in_path_list(name, firstList,
342				semicolon - firstList, programPath, requestingObjectPath, NULL,
343				buffer, sizeof(buffer));
344		}
345		if (fd < 0) {
346			fd = search_executable_in_path_list(name, secondList,
347				strlen(secondList), programPath, requestingObjectPath, NULL,
348				buffer, sizeof(buffer));
349		}
350	}
351
352	// If not found yet, let's evaluate the system path variables to find the
353	// shared object.
354	if (fd < 0) {
355		if (const char *paths = search_path_for_type(type)) {
356			fd = search_executable_in_path_list(name, paths, strlen(paths),
357				programPath, NULL, abiSpecificSubDir, buffer, sizeof(buffer));
358		}
359	}
360
361	if (fd >= 0) {
362		// we found it, copy path!
363		TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer));
364		strlcpy(name, buffer, PATH_MAX);
365	}
366
367	return fd;
368}
369
370
371/*!
372	Applies haiku-specific fixes to a shebang line.
373*/
374static void
375fixup_shebang(char *invoker)
376{
377	char *current = invoker;
378	while (*current == ' ' || *current == '\t') {
379		++current;
380	}
381
382	char *commandStart = current;
383	while (*current != ' ' && *current != '\t' && *current != '\0') {
384		++current;
385	}
386
387	// replace /usr/bin/ with /bin/
388	if (memcmp(commandStart, "/usr/bin/", strlen("/usr/bin/")) == 0)
389		memmove(commandStart, commandStart + 4, strlen(commandStart + 4) + 1);
390}
391
392
393/*!
394	Tests if there is an executable file at the provided path. It will
395	also test if the file has a valid ELF header or is a shell script.
396	Even if the runtime loader does not need to be able to deal with
397	both types, the caller will give scripts a proper treatment.
398*/
399status_t
400test_executable(const char *name, char *invoker)
401{
402	char path[B_PATH_NAME_LENGTH];
403	char buffer[B_FILE_NAME_LENGTH];
404		// must be large enough to hold the ELF header
405	status_t status;
406	ssize_t length;
407	int fd;
408
409	if (name == NULL)
410		return B_BAD_VALUE;
411
412	strlcpy(path, name, sizeof(path));
413
414	fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL, NULL);
415	if (fd < B_OK)
416		return fd;
417
418	// see if it's executable at all
419	status = _kern_access(-1, path, X_OK, false);
420	if (status != B_OK)
421		goto out;
422
423	// read and verify the ELF header
424
425	length = _kern_read(fd, 0, buffer, sizeof(buffer));
426	if (length < 0) {
427		status = length;
428		goto out;
429	}
430
431	status = elf_verify_header(buffer, length);
432#ifdef _COMPAT_MODE
433#ifdef __x86_64__
434	if (status == B_NOT_AN_EXECUTABLE)
435		status = elf32_verify_header(buffer, length);
436#else
437	if (status == B_NOT_AN_EXECUTABLE)
438		status = elf64_verify_header(buffer, length);
439#endif	// __x86_64__
440#endif	// _COMPAT_MODE
441	if (status == B_NOT_AN_EXECUTABLE) {
442		if (!strncmp(buffer, "#!", 2)) {
443			// test for shell scripts
444			char *end;
445			buffer[min_c((size_t)length, sizeof(buffer) - 1)] = '\0';
446
447			end = strchr(buffer, '\n');
448			if (end == NULL) {
449				status = E2BIG;
450				goto out;
451			} else
452				end[0] = '\0';
453
454			if (invoker) {
455				strcpy(invoker, buffer + 2);
456				fixup_shebang(invoker);
457			}
458
459			status = B_OK;
460		} else {
461			// Something odd like a PE?
462			status = pe_verify_header(buffer, length);
463
464			// It is a PE, throw B_UNKNOWN_EXECUTABLE
465			// likely win32 at this point
466			if (status == B_OK)
467				status = B_UNKNOWN_EXECUTABLE;
468		}
469	} else if (status == B_OK) {
470		elf_ehdr *elfHeader = (elf_ehdr *)buffer;
471		if (elfHeader->e_entry == 0) {
472			// we don't like to open shared libraries
473			status = B_NOT_AN_EXECUTABLE;
474		} else if (invoker)
475			invoker[0] = '\0';
476	}
477
478out:
479	_kern_close(fd);
480	return status;
481}
482
483
484static bool
485determine_x86_abi(int fd, const Elf32_Ehdr& elfHeader, bool& _isGcc2)
486{
487	// Unless we're a little-endian CPU, don't bother. We're not x86, so it
488	// doesn't matter all that much whether we can determine the correct gcc
489	// ABI. This saves the code below from having to deal with endianess
490	// conversion.
491#if B_HOST_IS_LENDIAN
492
493	// Since we don't want to load the complete image, we can't use the
494	// functions that normally determine the Haiku version and ABI. Instead
495	// we'll load the symbol and string tables and resolve the ABI symbol
496	// manually.
497
498	// map the file into memory
499	struct stat st;
500	if (_kern_read_stat(fd, NULL, true, &st, sizeof(st)) != B_OK)
501		return false;
502
503	void* fileBaseAddress;
504	area_id area = _kern_map_file("mapped file", &fileBaseAddress,
505		B_ANY_ADDRESS, st.st_size, B_READ_AREA, REGION_NO_PRIVATE_MAP, false,
506		fd, 0);
507	if (area < 0)
508		return false;
509
510	struct AreaDeleter {
511		AreaDeleter(area_id area)
512			:
513			fArea(area)
514		{
515		}
516
517		~AreaDeleter()
518		{
519			_kern_delete_area(fArea);
520		}
521
522	private:
523		area_id	fArea;
524	} areaDeleter(area);
525
526	// get the section headers
527	if (elfHeader.e_shoff == 0 || elfHeader.e_shentsize < sizeof(Elf32_Shdr))
528		return false;
529
530	size_t sectionHeadersSize = elfHeader.e_shentsize * elfHeader.e_shnum;
531	if (elfHeader.e_shoff + (off_t)sectionHeadersSize > st.st_size)
532		return false;
533
534	void* sectionHeaders = (uint8*)fileBaseAddress + elfHeader.e_shoff;
535
536	// find the sections we need
537	uint32* symbolHash = NULL;
538	uint32 symbolHashSize = 0;
539	uint32 symbolHashChainSize = 0;
540	Elf32_Sym* symbolTable = NULL;
541	uint32 symbolTableSize = 0;
542	const char* stringTable = NULL;
543	off_t stringTableSize = 0;
544
545	for (int32 i = 0; i < elfHeader.e_shnum; i++) {
546		Elf32_Shdr* sectionHeader
547			= (Elf32_Shdr*)((uint8*)sectionHeaders + i * elfHeader.e_shentsize);
548		if ((off_t)sectionHeader->sh_offset + (off_t)sectionHeader->sh_size
549				> st.st_size) {
550			continue;
551		}
552
553		void* sectionAddress = (uint8*)fileBaseAddress
554			+ sectionHeader->sh_offset;
555
556		switch (sectionHeader->sh_type) {
557			case SHT_HASH:
558				symbolHash = (uint32*)sectionAddress;
559				if (sectionHeader->sh_size < (off_t)sizeof(symbolHash[0]))
560					return false;
561				symbolHashSize = symbolHash[0];
562				symbolHashChainSize
563					= sectionHeader->sh_size / sizeof(symbolHash[0]);
564				if (symbolHashChainSize < symbolHashSize + 2)
565					return false;
566				symbolHashChainSize -= symbolHashSize + 2;
567				break;
568			case SHT_DYNSYM:
569				symbolTable = (Elf32_Sym*)sectionAddress;
570				symbolTableSize = sectionHeader->sh_size;
571				break;
572			case SHT_STRTAB:
573				// .shstrtab has the same type as .dynstr, but it isn't loaded
574				// into memory.
575				if (sectionHeader->sh_addr == 0)
576					continue;
577				stringTable = (const char*)sectionAddress;
578				stringTableSize = (off_t)sectionHeader->sh_size;
579				break;
580			default:
581				continue;
582		}
583	}
584
585	if (symbolHash == NULL || symbolTable == NULL || stringTable == NULL)
586		return false;
587	uint32 symbolCount
588		= std::min(symbolTableSize / (uint32)sizeof(Elf32_Sym),
589			symbolHashChainSize);
590	if (symbolCount < symbolHashSize)
591		return false;
592
593	// look up the ABI symbol
594	const char* name = B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME;
595	size_t nameLength = strlen(name);
596	uint32 bucket = elf_hash(name) % symbolHashSize;
597
598	for (uint32 i = symbolHash[bucket + 2]; i < symbolCount && i != STN_UNDEF;
599		i = symbolHash[2 + symbolHashSize + i]) {
600		Elf32_Sym* symbol = symbolTable + i;
601		if (symbol->st_shndx != SHN_UNDEF
602			&& ((symbol->Bind() == STB_GLOBAL) || (symbol->Bind() == STB_WEAK))
603			&& symbol->Type() == STT_OBJECT
604			&& (off_t)symbol->st_name + (off_t)nameLength < stringTableSize
605			&& strcmp(stringTable + symbol->st_name, name) == 0) {
606			if (symbol->st_value > 0 && symbol->st_size >= sizeof(uint32)
607				&& symbol->st_shndx < elfHeader.e_shnum) {
608				Elf32_Shdr* sectionHeader = (Elf32_Shdr*)((uint8*)sectionHeaders
609					+ symbol->st_shndx * elfHeader.e_shentsize);
610				if (symbol->st_value >= sectionHeader->sh_addr
611					&& symbol->st_value
612						<= sectionHeader->sh_addr + sectionHeader->sh_size) {
613					off_t fileOffset = symbol->st_value - sectionHeader->sh_addr
614						+ sectionHeader->sh_offset;
615					if (fileOffset + (off_t)sizeof(uint32) <= st.st_size) {
616						uint32 abi
617							= *(uint32*)((uint8*)fileBaseAddress + fileOffset);
618						_isGcc2 = (abi & B_HAIKU_ABI_MAJOR)
619							== B_HAIKU_ABI_GCC_2;
620						return true;
621					}
622				}
623			}
624
625			return false;
626		}
627	}
628
629	// ABI symbol not found. That means the object pre-dates its introduction
630	// in Haiku. So this is most likely gcc 2. We don't fall back to reading
631	// the comment sections to verify.
632	_isGcc2 = true;
633	return true;
634#else	// not little endian
635	return false;
636#endif
637}
638
639
640static status_t
641get_executable_architecture(int fd, const char** _architecture)
642{
643	// Read the ELF header. We read the 32 bit header. Generally the e_machine
644	// field is the last one that interests us and the 64 bit header is still
645	// identical at that point.
646	Elf32_Ehdr elfHeader;
647	ssize_t bytesRead = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader));
648	if (bytesRead < 0)
649		return bytesRead;
650	if ((size_t)bytesRead != sizeof(elfHeader))
651		return B_NOT_AN_EXECUTABLE;
652
653	// check whether this is indeed an ELF file
654	if (memcmp(elfHeader.e_ident, ELFMAG, 4) != 0)
655		return B_NOT_AN_EXECUTABLE;
656
657	// check the architecture
658	uint16 machine = elfHeader.e_machine;
659	if ((elfHeader.e_ident[EI_DATA] == ELFDATA2LSB) != (B_HOST_IS_LENDIAN != 0))
660		machine = (machine >> 8) | (machine << 8);
661
662	const char* architecture = NULL;
663	switch (machine) {
664		case EM_386:
665		case EM_486:
666		{
667			bool isGcc2;
668			if (determine_x86_abi(fd, elfHeader, isGcc2) && isGcc2)
669				architecture = "x86_gcc2";
670			else
671				architecture = "x86";
672			break;
673		}
674		case EM_68K:
675			architecture = "m68k";
676			break;
677		case EM_PPC:
678			architecture = "ppc";
679			break;
680		case EM_ARM:
681			architecture = "arm";
682			break;
683		case EM_ARM64:
684			architecture = "arm64";
685			break;
686		case EM_X86_64:
687			architecture = "x86_64";
688			break;
689		case EM_RISCV:
690			architecture = "riscv";
691			break;
692	}
693
694	if (architecture == NULL)
695		return B_NOT_SUPPORTED;
696
697	*_architecture = architecture;
698	return B_OK;
699}
700
701
702status_t
703get_executable_architecture(const char* path, const char** _architecture)
704{
705	int fd = _kern_open(-1, path, O_RDONLY, 0);
706	if (fd < 0)
707		return fd;
708
709	status_t error = get_executable_architecture(fd, _architecture);
710
711	_kern_close(fd);
712	return error;
713}
714
715
716/*!
717	This is the main entry point of the runtime loader as
718	specified by its ld-script.
719*/
720int
721runtime_loader(void* _args, void* commpage)
722{
723	void *entry = NULL;
724	int returnCode;
725
726	gProgramArgs = (struct user_space_program_args *)_args;
727	__gCommPageAddress = commpage;
728
729	// Relocate the args and env arrays -- they are organized in a contiguous
730	// buffer which the kernel just copied into user space without adjusting the
731	// pointers.
732	{
733		int32 i;
734		addr_t relocationOffset = 0;
735
736		if (gProgramArgs->arg_count > 0)
737			relocationOffset = (addr_t)gProgramArgs->args[0];
738		else if (gProgramArgs->env_count > 0)
739			relocationOffset = (addr_t)gProgramArgs->env[0];
740
741		// That's basically: <new buffer address> - <old buffer address>.
742		// It looks a little complicated, since we don't have the latter one at
743		// hand and thus need to reconstruct it (<first string pointer> -
744		// <arguments + environment array sizes>).
745		relocationOffset = (addr_t)gProgramArgs->args - relocationOffset
746			+ (gProgramArgs->arg_count + gProgramArgs->env_count + 2)
747				* sizeof(char*);
748
749		for (i = 0; i < gProgramArgs->arg_count; i++)
750			gProgramArgs->args[i] += relocationOffset;
751
752		for (i = 0; i < gProgramArgs->env_count; i++)
753			gProgramArgs->env[i] += relocationOffset;
754	}
755
756#if DEBUG_RLD
757	close(0); open("/dev/console", 0); /* stdin   */
758	close(1); open("/dev/console", 0); /* stdout  */
759	close(2); open("/dev/console", 0); /* stderr  */
760#endif
761
762	if (heap_init() < B_OK)
763		return 1;
764
765	rldexport_init();
766	rldelf_init();
767
768	load_program(gProgramArgs->program_path, &entry);
769
770	if (entry == NULL)
771		return -1;
772
773	// call the program entry point (usually _start())
774	returnCode = ((int (*)(int, void *, void *))entry)(gProgramArgs->arg_count,
775		gProgramArgs->args, gProgramArgs->env);
776
777	terminate_program();
778
779	return returnCode;
780}
781