xref: /haiku/src/system/runtime_loader/arch/x86_64/arch_relocate.cpp (revision 73ad2473e7874b3702cf5b0fdf4c81b747812ed9)
1 /*
2  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "runtime_loader_private.h"
8 
9 #include <runtime_loader.h>
10 
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 
16 static status_t
17 relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel,
18 	size_t relLength, SymbolLookupCache* cache)
19 {
20 	for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) {
21 		int type = ELF64_R_TYPE(rel[i].r_info);
22 		int symIndex = ELF64_R_SYM(rel[i].r_info);
23 		Elf64_Addr symAddr = 0;
24 
25 		// Resolve the symbol, if any.
26 		if (symIndex != 0) {
27 			Elf64_Sym* sym = SYMBOL(image, symIndex);
28 
29 			status_t status = resolve_symbol(rootImage, image, sym, cache,
30 				&symAddr);
31 			if (status != B_OK) {
32 				TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
33 					SYMNAME(image, sym), status));
34 				printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n",
35 					SYMNAME(image, sym), status);
36 				return status;
37 			}
38 		}
39 
40 		// Address of the relocation.
41 		Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset;
42 
43 		// Calculate the relocation value.
44 		Elf64_Addr relocValue;
45 		switch(type) {
46 			case R_X86_64_NONE:
47 				continue;
48 			case R_X86_64_64:
49 			case R_X86_64_GLOB_DAT:
50 			case R_X86_64_JUMP_SLOT:
51 				relocValue = symAddr + rel[i].r_addend;
52 				break;
53 			case R_X86_64_PC32:
54 				relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
55 				break;
56 			case R_X86_64_RELATIVE:
57 				relocValue = image->regions[0].delta + rel[i].r_addend;
58 				break;
59 			default:
60 				TRACE(("unhandled relocation type %d\n", type));
61 				return B_BAD_DATA;
62 		}
63 
64 		*(Elf64_Addr *)relocAddr = relocValue;
65 	}
66 
67 	return B_OK;
68 }
69 
70 
71 status_t
72 arch_relocate_image(image_t* rootImage, image_t* image,
73 	SymbolLookupCache* cache)
74 {
75 	status_t status;
76 
77 	// No REL on x86_64.
78 
79 	// Perform RELA relocations.
80 	if (image->rela) {
81 		status = relocate_rela(rootImage, image, image->rela, image->rela_len,
82 			cache);
83 		if (status != B_OK)
84 			return status;
85 	}
86 
87 	// PLT relocations (they are RELA on x86_64).
88 	if (image->pltrel) {
89 		status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel,
90 			image->pltrel_len, cache);
91 		if (status != B_OK)
92 			return status;
93 	}
94 
95 	return B_OK;
96 }
97