xref: /haiku/src/system/runtime_loader/elf_load_image.cpp (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
1 /*
2  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2003-2012, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2002, Manuel J. Petit. All rights reserved.
7  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9  */
10 
11 #include "elf_load_image.h"
12 
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include <syscalls.h>
17 
18 #include "add_ons.h"
19 #include "elf_haiku_version.h"
20 #include "elf_symbol_lookup.h"
21 #include "elf_tls.h"
22 #include "elf_versioning.h"
23 #include "images.h"
24 #include "runtime_loader_private.h"
25 
26 
27 static const char* sSearchPathSubDir = NULL;
28 
29 
30 static const char*
31 get_program_path()
32 {
33 	return gProgramImage != NULL ? gProgramImage->path : NULL;
34 }
35 
36 
37 static int32
38 count_regions(const char* imagePath, char const* buff, int phnum, int phentsize)
39 {
40 	elf_phdr* pheaders;
41 	int32 count = 0;
42 	int i;
43 
44 	for (i = 0; i < phnum; i++) {
45 		pheaders = (elf_phdr*)(buff + i * phentsize);
46 
47 		switch (pheaders->p_type) {
48 			case PT_NULL:
49 				// NOP header
50 				break;
51 			case PT_LOAD:
52 				count += 1;
53 				if (pheaders->p_memsz != pheaders->p_filesz) {
54 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr
55 						+ pheaders->p_memsz);
56 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr
57 						+ pheaders->p_filesz);
58 
59 					if (A != B)
60 						count += 1;
61 				}
62 				break;
63 			case PT_DYNAMIC:
64 				// will be handled at some other place
65 				break;
66 			case PT_INTERP:
67 				// should check here for appropriate interpreter
68 				break;
69 			case PT_NOTE:
70 				// unsupported
71 				break;
72 			case PT_SHLIB:
73 				// undefined semantics
74 				break;
75 			case PT_PHDR:
76 				// we don't use it
77 				break;
78 			case PT_EH_FRAME:
79 			case PT_RELRO:
80 				// not implemented yet, but can be ignored
81 				break;
82 			case PT_STACK:
83 				// we don't use it
84 				break;
85 			case PT_TLS:
86 				// will be handled at some other place
87 				break;
88 			case PT_ARM_UNWIND:
89 				// will be handled in libgcc_s.so.1
90 				break;
91 			case PT_RISCV_ATTRIBUTES:
92 				// TODO: check ABI compatibility attributes
93 				break;
94 			default:
95 				FATAL("%s: Unhandled pheader type in count 0x%" B_PRIx32 "\n",
96 					imagePath, pheaders->p_type);
97 				break;
98 		}
99 	}
100 
101 	return count;
102 }
103 
104 
105 static status_t
106 parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
107 {
108 	elf_phdr* pheader;
109 	int regcount;
110 	int i;
111 
112 	image->dso_tls_id = unsigned(-1);
113 
114 	regcount = 0;
115 	for (i = 0; i < phnum; i++) {
116 		pheader = (elf_phdr*)(buff + i * phentsize);
117 
118 		switch (pheader->p_type) {
119 			case PT_NULL:
120 				/* NOP header */
121 				break;
122 			case PT_LOAD:
123 				if (pheader->p_memsz == pheader->p_filesz) {
124 					/*
125 					 * everything in one area
126 					 */
127 					image->regions[regcount].start = pheader->p_vaddr;
128 					image->regions[regcount].size = pheader->p_memsz;
129 					image->regions[regcount].vmstart
130 						= PAGE_BASE(pheader->p_vaddr);
131 					image->regions[regcount].vmsize
132 						= TO_PAGE_SIZE(pheader->p_memsz
133 							+ PAGE_OFFSET(pheader->p_vaddr));
134 					image->regions[regcount].fdstart = pheader->p_offset;
135 					image->regions[regcount].fdsize = pheader->p_filesz;
136 					image->regions[regcount].delta = 0;
137 					image->regions[regcount].flags = 0;
138 					if (pheader->p_flags & PF_WRITE) {
139 						// this is a writable segment
140 						image->regions[regcount].flags |= RFLAG_RW;
141 					}
142 				} else {
143 					/*
144 					 * may require splitting
145 					 */
146 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr
147 						+ pheader->p_memsz);
148 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr
149 						+ pheader->p_filesz);
150 
151 					image->regions[regcount].start = pheader->p_vaddr;
152 					image->regions[regcount].size = pheader->p_filesz;
153 					image->regions[regcount].vmstart
154 						= PAGE_BASE(pheader->p_vaddr);
155 					image->regions[regcount].vmsize
156 						= TO_PAGE_SIZE(pheader->p_filesz
157 							+ PAGE_OFFSET(pheader->p_vaddr));
158 					image->regions[regcount].fdstart = pheader->p_offset;
159 					image->regions[regcount].fdsize = pheader->p_filesz;
160 					image->regions[regcount].delta = 0;
161 					image->regions[regcount].flags = 0;
162 					if (pheader->p_flags & PF_WRITE) {
163 						// this is a writable segment
164 						image->regions[regcount].flags |= RFLAG_RW;
165 					}
166 
167 					if (A != B) {
168 						/*
169 						 * yeah, it requires splitting
170 						 */
171 						regcount += 1;
172 						image->regions[regcount].start = pheader->p_vaddr;
173 						image->regions[regcount].size
174 							= pheader->p_memsz - pheader->p_filesz;
175 						image->regions[regcount].vmstart
176 							= image->regions[regcount-1].vmstart
177 								+ image->regions[regcount-1].vmsize;
178 						image->regions[regcount].vmsize
179 							= TO_PAGE_SIZE(pheader->p_memsz
180 									+ PAGE_OFFSET(pheader->p_vaddr))
181 								- image->regions[regcount-1].vmsize;
182 						image->regions[regcount].fdstart = 0;
183 						image->regions[regcount].fdsize = 0;
184 						image->regions[regcount].delta = 0;
185 						image->regions[regcount].flags = RFLAG_ANON;
186 						if (pheader->p_flags & PF_WRITE) {
187 							// this is a writable segment
188 							image->regions[regcount].flags |= RFLAG_RW;
189 						}
190 					}
191 				}
192 				regcount += 1;
193 				break;
194 			case PT_DYNAMIC:
195 				image->dynamic_ptr = pheader->p_vaddr;
196 				break;
197 			case PT_INTERP:
198 				// should check here for appropiate interpreter
199 				break;
200 			case PT_NOTE:
201 				// unsupported
202 				break;
203 			case PT_SHLIB:
204 				// undefined semantics
205 				break;
206 			case PT_PHDR:
207 				// we don't use it
208 				break;
209 			case PT_EH_FRAME:
210 			case PT_RELRO:
211 				// not implemented yet, but can be ignored
212 				break;
213 			case PT_STACK:
214 				// we don't use it
215 				break;
216 			case PT_TLS:
217 				image->dso_tls_id
218 					= TLSBlockTemplates::Get().Register(
219 						TLSBlockTemplate((void*)pheader->p_vaddr,
220 							pheader->p_filesz, pheader->p_memsz));
221 				break;
222 			case PT_ARM_UNWIND:
223 				// will be handled in libgcc_s.so.1
224 				break;
225 			case PT_RISCV_ATTRIBUTES:
226 				// TODO: check ABI compatibility attributes
227 				break;
228 			default:
229 				FATAL("%s: Unhandled pheader type in parse 0x%" B_PRIx32 "\n",
230 					image->path, pheader->p_type);
231 				return B_BAD_DATA;
232 		}
233 	}
234 
235 	return B_OK;
236 }
237 
238 
239 static bool
240 assert_dynamic_loadable(image_t* image)
241 {
242 	uint32 i;
243 
244 	if (!image->dynamic_ptr)
245 		return true;
246 
247 	for (i = 0; i < image->num_regions; i++) {
248 		if (image->dynamic_ptr >= image->regions[i].start
249 			&& image->dynamic_ptr
250 				< image->regions[i].start + image->regions[i].size) {
251 			return true;
252 		}
253 	}
254 
255 	return false;
256 }
257 
258 
259 static bool
260 parse_dynamic_segment(image_t* image)
261 {
262 	elf_dyn* d;
263 	int i;
264 	int sonameOffset = -1;
265 
266 	image->symhash = 0;
267 	image->syms = 0;
268 	image->strtab = 0;
269 
270 	d = (elf_dyn*)image->dynamic_ptr;
271 	if (!d)
272 		return true;
273 
274 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
275 		switch (d[i].d_tag) {
276 			case DT_NEEDED:
277 				image->num_needed += 1;
278 				break;
279 			case DT_HASH:
280 				image->symhash
281 					= (uint32*)(d[i].d_un.d_ptr + image->regions[0].delta);
282 				break;
283 			case DT_STRTAB:
284 				image->strtab
285 					= (char*)(d[i].d_un.d_ptr + image->regions[0].delta);
286 				break;
287 			case DT_SYMTAB:
288 				image->syms = (elf_sym*)
289 					(d[i].d_un.d_ptr + image->regions[0].delta);
290 				break;
291 			case DT_REL:
292 				image->rel = (elf_rel*)
293 					(d[i].d_un.d_ptr + image->regions[0].delta);
294 				break;
295 			case DT_RELSZ:
296 				image->rel_len = d[i].d_un.d_val;
297 				break;
298 			case DT_RELA:
299 				image->rela = (elf_rela*)
300 					(d[i].d_un.d_ptr + image->regions[0].delta);
301 				break;
302 			case DT_RELASZ:
303 				image->rela_len = d[i].d_un.d_val;
304 				break;
305 			case DT_JMPREL:
306 				// procedure linkage table relocations
307 				image->pltrel = (elf_rel*)
308 					(d[i].d_un.d_ptr + image->regions[0].delta);
309 				break;
310 			case DT_PLTRELSZ:
311 				image->pltrel_len = d[i].d_un.d_val;
312 				break;
313 			case DT_INIT:
314 				image->init_routine
315 					= (d[i].d_un.d_ptr + image->regions[0].delta);
316 				break;
317 			case DT_FINI:
318 				image->term_routine
319 					= (d[i].d_un.d_ptr + image->regions[0].delta);
320 				break;
321 			case DT_SONAME:
322 				sonameOffset = d[i].d_un.d_val;
323 				break;
324 			case DT_GNU_HASH:
325 			{
326 				uint32* gnuhash = (uint32*)
327 					(d[i].d_un.d_ptr + image->regions[0].delta);
328 				const uint32 bucketCount = gnuhash[0];
329 				const uint32 symIndex = gnuhash[1];
330 				const uint32 maskWordsCount = gnuhash[2];
331 				const uint32 bloomSize = maskWordsCount * (sizeof(elf_addr) / 4);
332 
333 				image->gnuhash.mask_words_count_mask = maskWordsCount - 1;
334 				image->gnuhash.shift2 = gnuhash[3];
335 				image->gnuhash.bucket_count = bucketCount;
336 				image->gnuhash.bloom = (elf_addr*)(gnuhash + 4);
337 				image->gnuhash.buckets = gnuhash + 4 + bloomSize;
338 				image->gnuhash.chain0 = image->gnuhash.buckets + bucketCount - symIndex;
339 				break;
340 			}
341 			case DT_VERSYM:
342 				image->symbol_versions = (elf_versym*)
343 					(d[i].d_un.d_ptr + image->regions[0].delta);
344 				break;
345 			case DT_VERDEF:
346 				image->version_definitions = (elf_verdef*)
347 					(d[i].d_un.d_ptr + image->regions[0].delta);
348 				break;
349 			case DT_VERDEFNUM:
350 				image->num_version_definitions = d[i].d_un.d_val;
351 				break;
352 			case DT_VERNEED:
353 				image->needed_versions = (elf_verneed*)
354 					(d[i].d_un.d_ptr + image->regions[0].delta);
355 				break;
356 			case DT_VERNEEDNUM:
357 				image->num_needed_versions = d[i].d_un.d_val;
358 				break;
359 			case DT_SYMBOLIC:
360 				image->flags |= RFLAG_SYMBOLIC;
361 				break;
362 			case DT_FLAGS:
363 			{
364 				uint32 flags = d[i].d_un.d_val;
365 				if ((flags & DF_SYMBOLIC) != 0)
366 					image->flags |= RFLAG_SYMBOLIC;
367 				if ((flags & DF_STATIC_TLS) != 0) {
368 					FATAL("Static TLS model is not supported.\n");
369 					return false;
370 				}
371 				break;
372 			}
373 			case DT_INIT_ARRAY:
374 				// array of pointers to initialization functions
375 				image->init_array = (addr_t*)
376 					(d[i].d_un.d_ptr + image->regions[0].delta);
377 				break;
378 			case DT_INIT_ARRAYSZ:
379 				// size in bytes of the array of initialization functions
380 				image->init_array_len = d[i].d_un.d_val;
381 				break;
382 			case DT_PREINIT_ARRAY:
383 				// array of pointers to pre-initialization functions
384 				image->preinit_array = (addr_t*)
385 					(d[i].d_un.d_ptr + image->regions[0].delta);
386 				break;
387 			case DT_PREINIT_ARRAYSZ:
388 				// size in bytes of the array of pre-initialization functions
389 				image->preinit_array_len = d[i].d_un.d_val;
390 				break;
391 			case DT_FINI_ARRAY:
392 				// array of pointers to termination functions
393 				image->term_array = (addr_t*)
394 					(d[i].d_un.d_ptr + image->regions[0].delta);
395 				break;
396 			case DT_FINI_ARRAYSZ:
397 				// size in bytes of the array of termination functions
398 				image->term_array_len = d[i].d_un.d_val;
399 				break;
400 			default:
401 				continue;
402 
403 			// TODO: Implement:
404 			// DT_RELENT: The size of a DT_REL entry.
405 			// DT_RELAENT: The size of a DT_RELA entry.
406 			// DT_SYMENT: The size of a symbol table entry.
407 			// DT_PLTREL: The type of the PLT relocation entries (DT_JMPREL).
408 			// DT_BIND_NOW/DF_BIND_NOW: No lazy binding allowed.
409 			// DT_TEXTREL/DF_TEXTREL: Indicates whether text relocations are
410 			//		required (for optimization purposes only).
411 		}
412 	}
413 
414 	// lets make sure we found all the required sections
415 	if (!image->symhash || !image->syms || !image->strtab)
416 		return false;
417 
418 	if (sonameOffset >= 0)
419 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
420 
421 	return true;
422 }
423 
424 
425 // #pragma mark -
426 
427 
428 status_t
429 parse_elf_header(elf_ehdr* eheader, int32* _pheaderSize,
430 	int32* _sheaderSize)
431 {
432 	if (memcmp(eheader->e_ident, ELFMAG, 4) != 0)
433 		return B_NOT_AN_EXECUTABLE;
434 
435 	if (eheader->e_ident[4] != ELF_CLASS)
436 		return B_NOT_AN_EXECUTABLE;
437 
438 	if (eheader->e_phoff == 0)
439 		return B_NOT_AN_EXECUTABLE;
440 
441 	if (eheader->e_phentsize < sizeof(elf_phdr))
442 		return B_NOT_AN_EXECUTABLE;
443 
444 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
445 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
446 
447 	if (*_pheaderSize <= 0)
448 		return B_NOT_AN_EXECUTABLE;
449 
450 	return B_OK;
451 }
452 
453 
454 #if defined(_COMPAT_MODE)
455 #if defined(__x86_64__)
456 status_t
457 parse_elf32_header(Elf32_Ehdr* eheader, int32* _pheaderSize,
458 	int32* _sheaderSize)
459 {
460 	if (memcmp(eheader->e_ident, ELFMAG, 4) != 0)
461 		return B_NOT_AN_EXECUTABLE;
462 
463 	if (eheader->e_ident[4] != ELFCLASS32)
464 		return B_NOT_AN_EXECUTABLE;
465 
466 	if (eheader->e_phoff == 0)
467 		return B_NOT_AN_EXECUTABLE;
468 
469 	if (eheader->e_phentsize < sizeof(Elf32_Phdr))
470 		return B_NOT_AN_EXECUTABLE;
471 
472 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
473 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
474 
475 	if (*_pheaderSize <= 0)
476 		return B_NOT_AN_EXECUTABLE;
477 
478 	return B_OK;
479 }
480 #else
481 status_t
482 parse_elf64_header(Elf64_Ehdr* eheader, int32* _pheaderSize,
483 	int32* _sheaderSize)
484 {
485 	if (memcmp(eheader->e_ident, ELFMAG, 4) != 0)
486 		return B_NOT_AN_EXECUTABLE;
487 
488 	if (eheader->e_ident[4] != ELFCLASS64)
489 		return B_NOT_AN_EXECUTABLE;
490 
491 	if (eheader->e_phoff == 0)
492 		return B_NOT_AN_EXECUTABLE;
493 
494 	if (eheader->e_phentsize < sizeof(Elf64_Phdr))
495 		return B_NOT_AN_EXECUTABLE;
496 
497 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
498 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
499 
500 	if (*_pheaderSize <= 0)
501 		return B_NOT_AN_EXECUTABLE;
502 
503 	return B_OK;
504 }
505 #endif	// __x86_64__
506 #endif	// _COMPAT_MODE
507 
508 
509 status_t
510 load_image(char const* name, image_type type, const char* rpath, const char* runpath,
511 	const char* requestingObjectPath, image_t** _image)
512 {
513 	int32 pheaderSize, sheaderSize;
514 	char path[PATH_MAX];
515 	ssize_t length;
516 	char pheaderBuffer[4096];
517 	int32 numRegions;
518 	image_t* found;
519 	image_t* image;
520 	status_t status;
521 	int fd;
522 
523 	elf_ehdr eheader;
524 
525 	// Have we already loaded that image? Don't check for add-ons -- we always
526 	// reload them.
527 	if (type != B_ADD_ON_IMAGE) {
528 		found = find_loaded_image_by_name(name, APP_OR_LIBRARY_TYPE);
529 
530 		if (found == NULL && type != B_APP_IMAGE && gProgramImage != NULL) {
531 			// Special case for add-ons that link against the application
532 			// executable, with the executable not having a soname set.
533 			if (const char* lastSlash = strrchr(name, '/')) {
534 				if (strcmp(gProgramImage->name, lastSlash + 1) == 0)
535 					found = gProgramImage;
536 			}
537 		}
538 
539 		if (found) {
540 			atomic_add(&found->ref_count, 1);
541 			*_image = found;
542 			KTRACE("rld: load_container(\"%s\", type: %d, %s: \"%s\") "
543 				"already loaded", name, type,
544 				runpath != NULL ? "runpath" : "rpath", runpath != NULL ? runpath : rpath);
545 			return B_OK;
546 		}
547 	}
548 
549 	KTRACE("rld: load_container(\"%s\", type: %d, %s: \"%s\")", name, type,
550 		runpath != NULL ? "runpath" : "rpath", runpath != NULL ? runpath : rpath);
551 
552 	strlcpy(path, name, sizeof(path));
553 
554 	// find and open the file
555 	fd = open_executable(path, type, rpath, runpath, get_program_path(),
556 		requestingObjectPath, sSearchPathSubDir);
557 	if (fd < 0) {
558 		FATAL("Cannot open file %s (needed by %s): %s\n", name, requestingObjectPath, strerror(fd));
559 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
560 		return fd;
561 	}
562 
563 	// normalize the image path
564 	status = _kern_normalize_path(path, true, path);
565 	if (status != B_OK)
566 		goto err1;
567 
568 	// Test again if this image has been registered already - this time,
569 	// we can check the full path, not just its name as noted.
570 	// You could end up loading an image twice with symbolic links, else.
571 	if (type != B_ADD_ON_IMAGE) {
572 		found = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
573 		if (found) {
574 			atomic_add(&found->ref_count, 1);
575 			*_image = found;
576 			_kern_close(fd);
577 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
578 				name);
579 			return B_OK;
580 		}
581 	}
582 
583 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
584 	if (length != sizeof(eheader)) {
585 		status = B_NOT_AN_EXECUTABLE;
586 		FATAL("%s: Troubles reading ELF header\n", path);
587 		goto err1;
588 	}
589 
590 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
591 	if (status < B_OK) {
592 		FATAL("%s: Incorrect ELF header\n", path);
593 		goto err1;
594 	}
595 
596 	// ToDo: what to do about this restriction??
597 	if (pheaderSize > (int)sizeof(pheaderBuffer)) {
598 		FATAL("%s: Cannot handle program headers bigger than %lu\n",
599 			path, sizeof(pheaderBuffer));
600 		status = B_UNSUPPORTED;
601 		goto err1;
602 	}
603 
604 	length = _kern_read(fd, eheader.e_phoff, pheaderBuffer, pheaderSize);
605 	if (length != pheaderSize) {
606 		FATAL("%s: Could not read program headers: %s\n", path,
607 			strerror(length));
608 		status = B_BAD_DATA;
609 		goto err1;
610 	}
611 
612 	numRegions = count_regions(path, pheaderBuffer, eheader.e_phnum,
613 		eheader.e_phentsize);
614 	if (numRegions <= 0) {
615 		FATAL("%s: Troubles parsing Program headers, numRegions = %" B_PRId32
616 			"\n", path, numRegions);
617 		status = B_BAD_DATA;
618 		goto err1;
619 	}
620 
621 	image = create_image(name, path, numRegions);
622 	if (image == NULL) {
623 		FATAL("%s: Failed to allocate image_t object\n", path);
624 		status = B_NO_MEMORY;
625 		goto err1;
626 	}
627 
628 	status = parse_program_headers(image, pheaderBuffer, eheader.e_phnum,
629 		eheader.e_phentsize);
630 	if (status < B_OK)
631 		goto err2;
632 
633 	if (!assert_dynamic_loadable(image)) {
634 		FATAL("%s: Dynamic segment must be loadable (implementation "
635 			"restriction)\n", image->path);
636 		status = B_UNSUPPORTED;
637 		goto err2;
638 	}
639 
640 	status = map_image(fd, path, image, eheader.e_type == ET_EXEC);
641 	if (status < B_OK) {
642 		FATAL("%s: Could not map image: %s\n", image->path, strerror(status));
643 		status = B_ERROR;
644 		goto err2;
645 	}
646 
647 	if (!parse_dynamic_segment(image)) {
648 		FATAL("%s: Troubles handling dynamic section\n", image->path);
649 		status = B_BAD_DATA;
650 		goto err3;
651 	}
652 
653 	if (eheader.e_entry != 0)
654 		image->entry_point = eheader.e_entry + image->regions[0].delta;
655 
656 	analyze_image_haiku_version_and_abi(fd, image, eheader, sheaderSize,
657 		pheaderBuffer, sizeof(pheaderBuffer));
658 
659 	// If sSearchPathSubDir is unset (meaning, this is the first image we're
660 	// loading) we init the search path subdir if the compiler version doesn't
661 	// match ours.
662 	if (sSearchPathSubDir == NULL) {
663 		#if __GNUC__ == 2 || (defined(_COMPAT_MODE) && !defined(__x86_64__))
664 			if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_4)
665 				sSearchPathSubDir = "x86";
666 		#endif
667 		#if __GNUC__ >= 4 || (defined(_COMPAT_MODE) && !defined(__x86_64__))
668 			if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2)
669 				sSearchPathSubDir = "x86_gcc2";
670 		#endif
671 	}
672 
673 	set_abi_api_version(image->abi, image->api_version);
674 
675 	// init gcc version dependent image flags
676 	// symbol resolution strategy
677 	if (image->abi == B_HAIKU_ABI_GCC_2_ANCIENT)
678 		image->find_undefined_symbol = find_undefined_symbol_beos;
679 
680 	// init version infos
681 	status = init_image_version_infos(image);
682 
683 	image->type = type;
684 	register_image(image, fd, path);
685 	image_event(image, IMAGE_EVENT_LOADED);
686 
687 	_kern_close(fd);
688 
689 	enqueue_loaded_image(image);
690 
691 	*_image = image;
692 
693 	KTRACE("rld: load_container(\"%s\"): done: id: %" B_PRId32 " (ABI: %#"
694 		B_PRIx32 ")", name, image->id, image->abi);
695 
696 	return B_OK;
697 
698 err3:
699 	unmap_image(image);
700 err2:
701 	delete_image_struct(image);
702 err1:
703 	_kern_close(fd);
704 
705 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
706 		strerror(status));
707 
708 	return status;
709 }
710